This log will go over the ideas I am going to implement to make the motion for my VR shoes as smooth as possible. If you haven't already seen it, check out my walk in No Man's Sky with my VR shoes. The motion I have now is already pretty good, but as you'll read, it can get even better.
Note that I will not be going over the return to center algorithm in this article. If you're wonder how the shoes know when to move, you can read about the algorithm here. Essentially, the shoe going forward tells the other shoe to go backwards at the same speed. This article will be going over the additional actions I'll take to smooth the motion. In an ideal world the return to center algorithm on its own would be perfect, but latency for communication between the shoes and start-up time for the motors means that additional actions need to be taken.
The first action I have already taken is to update that algorithm so that a single stride can only have one speed. Previously, as I would bring my foot forward, the speed at which I did so would vary a bit. This caused the other shoe to try to move backwards and vary it's speed similarly. The variable speed made the motion feel choppy and hard to balance. So, I updated the code so that once the shoe starts moving backwards, it stays at one speed to create a smooth motion. Drift can be compensated by the next stride. In the future I may update the code so that a single stride as one speed or can only accelerate or deaccelerate from there, but I'm not going to do that for now.
That is the action I have already taken. The rest of the things are actions I plan on implementing.
Part of the motion algorithm can be described using a state machine diagram.
The shoes can be in the following states.
* Stopped - The shoes are not moving.
* First Step - The user has started to move. The first step is being taken.
* Walking - The user is beyond the first step and is walking.
I will have different code for going from stopped to the first step, and from going to the first step to walking. Stopped to the first step will prioritize a smooth, slower startup. The shoes will more gradually gain speed in the first step to make going from stopped to walking feel smoother. Starting up the motors too fast when starting from 0 RPM will feel like a jolt of speed and may through the user's balance off.
Going from the first step to walking will prioritize maintaining speed and eliminating drift. During walking, the shoes will start up faster. Since the user is already moving the jolts of speed that the motors provide will be less jarring.
In addition to the state machine I've already shown, the shoes will be in different additional states depending on where they are in the stride. This state machine will apply when the shoes are in the walking state.
The shoe will be in the following states.
* Front of stride - The shoe is in front of the user and the user has just put is foot down.
* Middle of stride - The shoe has been moved (by the motors) to the middle of the stride. The shoe is directly under the user or close to it.
* Back of stride - The shoe is behind the user and the user is lifting his foot again to start another stride.
These additional states will be used to increase the responsiveness of the shoes. As the user walks, the user is constantly alternating his legs back and forth. When the legs change direction there is a moment when the speed of the shoe will decelerate, be zero, then accelerate again. During this moment, according to my return to center algorithm, the shoe in front of the user is waiting until the other foot lifts up off the platform and starts to move forward. Once the other shoe has done that, it sends a message to the front shoe that it's good to start actuating the motor and moving backwards. All of this creates a delay.
How can we get rid of the delay, or minimize it as much as possible? One option is for the front shoe to not wait for a signal from the back shoe. The front shoe will start moving backwards because it thinks that the user wants to continue walking. But what if the user doesn't want to continue walking?
I have found for myself that as I walk, when I eventually stop walking I almost always end my walk where both my feet are below me. I don't end my walk with my feet positioned behind and in front of me. I believe that is the case for most people. So for the shoes, the plan is once the shoes get to the walking state, when the user brings his foot down in front of him it is a safe assumption that he is planning to continue walking. With that being the case, the moment the user brings his foot down in front of him, the shoe can start going backwards without waiting for the back shoe's message. In most cases this will be fine, but for the case where the user actually wanted to stop, the front shoe will only go backwards for a set amount of time before receiving the signal from the other shoe. If it doesn't receive the signal within the time limit, it will stop moving. So in this case the user will experience a small amount of motion but it will stop quickly and in most cases the shoes will be more responsive.
It's a safe assuming that if the shoe is at the front of the stride, the user wants to keep walking. It's also a safe assumption that if the shoe is in the middle of the stride and the user brings his foot down, he wants to stop walking. Then the third assumption is if the shoe is at the back of the stride and the user lifts his foot, he wants to take another step.
When the shoe gets to the back of the stride and the user lifts his foot, a momentary break will be applied to stop the momentum the shoe has accumulated.
When the user lifts his foot, he either wants to start walking or rotate his foot. How can we tell which one he intends to do? The current program has a check in the code that says the shoe cannot start actuating until the other shoe has moved forward a certain distance. For example, if I raise my right foot, I must move my right foot a certain distance forward before the left shoe will start actuating the motor. This means that I can raise my right foot and rotate it, as long as during the rotation I don't turn the wheels on the shoe too much. This simple solution was adequate for the No Man's Sky demo I did, but more can be done.
The addition of an IMU can improve turning. I mentioned that with the simple code I have now that rotating is fine as long as I don't turn the wheels during my rotation. Well, it's easy to turn the wheels during the rotation. Using an IMU, I will add two additional conditions. The first will be that the rate of change of degrees needs to be smaller than a configurable amount. Again, if I raise my right foot and start to rotate it, imagine I turn the wheels a bit, but I'm turning my foot at a sufficient speed (say, 10 degrees/second), so the left shoe knows not to actuate the motor. The second condition will be if the angles of each shoe differ by a configurable amount. Again, if I raise my right foot and turn it 90 degrees, the left shoe shouldn't actuate the motor because the user intends to walk right, but the left shoe is not pointed in the correct direction to negate that motion. It's also possible the shoes will collide if the left foot actuates under those conditions.
I have a set of tuning parameters in the code now that work well for one speed. I plan on adding additional tuning parameters for different speeds.
If you watched my No Mans Sky walk, you may have noticed that the motion was very stop and go. I would take a step, stop, take my next step, stop, and so on. The pause in-between each step should be reduced as much as possible. I was informed by a user on my discord that other VR locomotion solutions, such as Natural Locomotion, don't bring the user to a stop the moment the user stops, but instead the user is decelerated in the game. I'm going to take the same approach where my character in the game will decelerate by a configurable amount between each step instead of just stopping. I could configure the amount so that basically no deceleration happens if I want.
One other in game optimization I plan on making is making it easy to re-calibrate the shoe's absolute orientation. Like I mentioned before, I'm going to add IMUs to each shoe. I will use these to track the shoe's orientation relative to the headset. Over time the IMUs will accumulate error. The user can occasionally re-calibrate the orientation by having his feet face the same direction he is facing and pressing a button or combination of buttons on the controllers, such as both home buttons at once. This will tell the shoes that the user's feet are facing the same direction as the headset and they can calibrate accordingly.