I’m continuing to make progress with getting the quad A1 to move at higher speeds, furthering my earlier video update. I’ll write up more later, but here’s a quick snapshot showing a 2 m/s trot:
I’ve started some development on higher speed gaits for the quad A1! No real details to report now, just a video showing the first time I tested it not in simulation. I will admit these clips were cherry-picked, as there are problems still, but it is a start!
I’ve worked through a number of different iterations of the stand-up sequence for the quad A1 (2019-05, 2019-09). The version I’ve been using for the last 6 months or so works pretty well, but because it drags the legs along the ground to get them into position, it can have problems when operating on surfaces with a lot of traction, like EVA foam, besides being uselessly noisy.
To make things just a bit more robust, I’ve now tweaked the startup routine so that the shoulders lift legs clear off the ground before positioning the legs, then lowers them back down into place. This makes the stand up routine much more likely to succeed on just about any surface:
Last time, I described my approach for estimating the terrain under the robot based on the inertial measurement unit and proprioceptive foot feedback. Now, I’ll cover how that is used to balance.
First, let me explain the “R” or “robot” frame and how it is used. The frames I’ve discussed in this series so far are the “B” frame, which is rigidly attached to the center of the robot body, the “M” frame, which is located at the center of mass and level with the ground, and the “T” frame, which is under the robot and level with the current terrain.
The “R” frame, by contrast, is a purely invented frame that is a rigid transform away from the “B” frame. Its purpose is to allow for (1) the cool looking inverse kinematic demos that everyone seems so fond of, and (2) mostly global transforms, like this implementation of terrain based balancing. All of the gait algorithms operate almost exclusively in the R frame, which means that offsets and rotations applied there will affect the balance of the robot during its normal operation.
Using the R frame to balance
Here the algorithm is relatively straightforward. The center of the T frame is taken, transformed into the M frame and then moved up by the current average leg height. In 2D, that looks like:
Then, the point p_0 as measured in the B frame gives the desired RB transform offset. It is that simple! That formulation keeps the center of mass over the 0, 0 R frame point accounting for offsets in the center of mass and for non-level terrain.
Here’s the robot walking up a relatively steep slope in simulation using the above technique. The purple disc shows the estimated terrain value, while the gray disc shows the gravity normal plane.
In the final post for this work, we’ll test it on the real robot!
Last time I discussed the challenges when operating the mjbots quad A1 on sloped surfaces. While there are a number of possible means of tackling this, the approach I’ve gone with for now is to estimate the slope of the terrain under the robot, and use that to determine how to position the center of mass. Here’ll I’ll cover the estimation part of this solution.
On paper, the quad A1 has plenty of information to estimate the terrain under its feet. Between the IMU with attitude estimator, the proprioceptive feedback from the joints, and the ability to move the feet around, it would be obvious to a human whether the ground under them was sloped or level. The challenge here is to devise an algorithm to do so, despite the noise in the IMU, the fact that the feet are not always on the ground, and that as the robot moves, the terrain under it changes.
My basic approach can be summarized in the follow flow chart / block diagram:
First, a brief description of the 3 pertinent reference frames:
- B Frame: The body frame (or B frame), is centered on the robot body, and rigidly fixed to the robot body. The proprioceptive system eventually calculates each of the 4 feet positions in this frame.
- M Frame: The CoM frame (or M frame), is centered at the robot’s idle center of mass and oriented such that positive Z points along gravity toward the ground with a heading that is arbitrary at start up, but that tracks the robot’s changing heading.
- T Frame: The terrain frame (or T frame), is referenced to the M frame at the average height of the legs with a slope that aligns with the average slope of the terrain under the robot.
The algorithm works in roughly the following steps:
- First, project all the feet positions into the M frame.
- For any in-flight legs, reset the Z value to one calculated from the current TM transform and a 0 T frame Z height.
- Fit a plane to these “on-ground” M frame points.
- Update the slope of the T frame using this plane with an exponential filter along the X and Y axes.
This algorithm has the benefit that it will converge on the terrain underneath the robot as long as feet touch the ground with regularity, which is a somewhat necessary condition for a robot supported by its legs. The rate at which the estimate converges can be controlled by the filter constant. Selecting that to be the same order as the step frequency does a decent job of rejecting spurious noise while responding in a timely manner to updated terrain.
Next up we’ll see how to use this information to balance, and watch the results in simulation.
Not too long ago, I ran some outdoor experiments, and while piloting the quad A1 around, realized that it wasn’t going to get very far if it was restricted to just flat ground.
Since the control algorithms are completely ignorant of slopes, the center of gravity of the machine can easily get too close to the support polygon when resting, and similarly fails to stay balanced over the support line during the trot gait.
To get started tackling this, I stuck a configurable ramp in the simulator:
And yes, it fails just as much on the ramp as it did in real life.
After getting a gait which looked like it could balance across the leg support line in 1D, I needed to extend that to 2D and try it out on the robot.
Extension to 2D
Extending this to two dimensions wasn’t too bad. I just did a bunch of geometry to follow the path traced out by a given 2 dimensional velocity and rotation rate, intersected with a line segment:
Given this function, the logic to select a swing target is basically the same as in the 1 dimensional case. We now create two “virtual legs”, which consist of two feet ganged together and produce a single support line. At each time instant when all legs are in stance, we look at the time remaining until each of the virtual legs would cross the center of mass at the current velocity. As soon as one hits the half-swing point, we start a swing.
As part of this, I extended tplot2 to be able to render the target location of each swing.
Once I had an actual robot to test it out on, I found a few other minor problems. When selecting the target for a foot swing, the 1 dimensional case just used the current velocity to move the leg far enough past the pickup point. That doesn’t work out all that well in heavy acceleration though, resulting in very short stance times. What worked much better was to use the expected velocity at the end of the next stance window. That provided much more consistent stance spacings even when accelerating or decelerating.
I still haven’t come up with a great solution for turning in place, for which the entire concept of estimating distance to the balance point doesn’t make sense. Right now, I just rely on the maximum stance time to ensure the legs eventually step in that scenario and don’t extend beyond their physical limits. I’ll probably eventually add a “time to infeasible geometry” criteria to handle that.
Testing it out
While there is still a lot of remaining work, this increased the maximum possible speed of the machine by at least a factor of 2, and the feasible acceleration by a factor of 10 or so. In the video below, I’ve got some clips of the robot walking around at 0.5m/s. That’s not too fast, but is more than a body length per second which counts for something.
I’m working to improve the walking gait of the mjbots quad A1. In this iteration, I wanted to tackle an incremental step towards a more fully dynamic gait, but one that will still greatly increase the capability of the machine. As mentioned last time, the current walking gait cycles between all four legs, and then alternative opposing corner legs in order to move laterally. I’d like to keep that same basic structure, but be a bit smarter about what happens during the swing phase.
First, the obvious: When the robot has legs on the ground, they support it. If all four legs are on the ground, they form a support polygon. If the center of mass of the robot is within this polygon when projected onto the ground, the robot will happily sit there forever without tipping over.
During the flight phase of the gait, only two legs are in contact with the ground. Now, we no longer have a support polygon, but a support line. The center of mass of the robot is either on one side of it or on the other. Well, I suppose it could be exactly over, but then the slightest breeze would push it to one side or the other. Whichever side the robot is on, gravity will exert a torque and cause it to continue to tip over in that direction.
The current gait sequencer is oblivious to this fact. It will happily pick up the legs when the robot is far away from the support polygon, and then move the center of mass even further away. Needless to say, this results in the robot tipping over rather rapidly.
Clearly the robot can’t move while keeping itself exactly over the support line, but can we arrange the gait such that it spends equal amounts of time on both sides (to be more precise, the integral of the distance from the support line over the time of the swing cycle is 0)? If we could, that would result in the minimum possible angular rotation during the swing phase, which would hopefully make things be a lot better without a whole lot more work.
In this post, I’ll consider the problem in 1 dimension, along a line as a simplification. Given that the robot can only move in one direction at a time, we should be able to generalize the 1 dimensional case to the 2 dimensional case later.
For a constant velocity and a fixed swing time, the answer is pretty clearly yes. If we start the swing phase right when the center of mass is 1/2 of the swing time from the opposing support, then the swing will be completed when it is on the other side spending exactly the same amount of time on each side of the support line.
In fact, this also holds for a more general case, as long as we don’t attempt to accelerate during the swing phase itself. All that is necessary is to start the swing when the center of mass is half a swing times away from the support point at the current velocity and not accelerate until the foot is down again.
Granted, in addition to the one dimensional simplification, in this model the feet are allowed to be infinitely far away from the center of mass. However, if we just apply a maximum time spent with all legs in stance, that places a limit on how far the legs can get away with only a slight decrease in performance.
The model also breaks down when the deceleration causes the robot to change directions. A simple heuristic is to change the leg order in that case.
Well, that looks pretty good in 1 dimension. Next up I’ll extend it to 2 dimensions, and try it out on the robot.
Now I’ve got a machine, the mjbots quad A1, which is capable of dynamic motions, but the only gait which takes advantage of these capabilities is the pronking one. That gait has the benefit that the dynamics are very simple. The entire time that that robot is in contact with the ground, it is in contact with all 4 legs, so in that regime it is fully controllable. Since it is fully controllable up to the point of lift-off, we can ensure that there is basically zero rotational rate while the machine is mid-flight, which means that it lands with all four legs largely at the same time. Of course, pronking isn’t a very fast or efficient way of getting anywhere, so I wanted to make the first steps… I guess pun intended, towards improving the more general walking algorithm to make the machine move faster in a more robust manner.
My previous solution
As described here, the gait I was using previously is conceptually very similar to a static IK based gait. The sequencing works by picking up and moving opposing pairs of legs in an alternating fashion. As opposed to a purely IK based solution, the inverse dynamics are accounted for. During the motion, each servo is commanded with appropriate velocities to achieve the end foot velocity profile and appropriate forces are commanded to result in a ground reaction force that matches the mass of the robot.
However, there are many things this doesn’t take into account. Among them are the linear and rotational inertia of the overall machine, the torque that the gravity vector exerts on the center of mass, and the dynamics of the legs themselves, which are assumed massless. It also only uses the high rate feedback from the servos in a very limited way, only to apply a 3D force and velocity command. Thus it completely ignores if a leg strikes the ground early either because of an obstacle or because the machine tipped, or if it strikes the ground late/never because of a depression or hole. Because of all this, it also requires periods where all four legs are on the ground simultaneously in order to maintain stability.
In this simple gait on flat ground, most problems manifest as the robot tipping during the flight phase, resulting in one flight leg striking early, which then results in a high angular rate correction as the controller tries to jam it back to the desired position. This can end up with uncontrolled oscillation of the robot in a wide range of hard to define operating conditions. Note, this is roughly the same problems that most IK based gait engines have, such as on the original Super Mega Microbot.
You can make this gait work passably if you carefully tune things and stick within a limited acceleration and terrain operational envelope, but overall it is rather fragile.
I’m not planning on tackling all of these problems in one go, or just out and out copying another solution, but intend to take small documentable steps towards a more capable machine. Up next I’ll describe my first baby steps towards this, where I look to manage the gravity torque during the flight phase to keep the machine stable even under acceleration.