Question about quadruped gaits

Hi All,

I have a mini-quadruped with 3DOF legs. I solved IK equations, and created a walking sequence. This walking sequence is discontinuous. You can see it in action from here.

I want to make its movement continuous. So that body and legs will move together as like this robot. I have divided movements into 12 frames. So that within T time interval robot will make 12 moves. In same time interval each leg will be off the ground in 3 frames and, will be on the ground for 9 frames (something like in this diagram. This diagram has 4 frames, I divided each frame to 3 so that 1 frame for step up, one frame for move forward, one frame for step down). Within each frame one leg will either step up, step down, move forward or move backwards. I am dividing walking distance with 9. In each frame I am moving legs, which are on the ground, to backwards by (walking distance)/9.

Although I feel that I am on the right track and the algorithm seems to be working properly, I couldn’t make my robot stable. It falls either front or back. I have experimented several different values as initial positions and for the other variables, I couldn’t find any working solution. Is there any general guide lines, tips, or things to consider while designing this kind of gaits? Is there any practical way of defining initial values for legs? I appreciate any ideas, suggestions, helps.

Can’t see what you are using as the main controller, but we have some code which can be used with Arduino (thanks again Xan) used on the SQ3. This type of gait requires that the robot be almost perfectly balanced.
lynxmotion.com/driver.aspx?Topic=assem03

I couldn’t find the code in the given link, is there any direct link to code? Any suggestions and tips for balancing?

I am using pololu maestro as servo driver and connecting it through bluetooth. My code base is in C#. Below please find the code snippet which generates above mentioned continuous movement.

public void Movement()
        {
           // all meausurements are in inches
            float liftHeight = 1.5f;
            float walkLength = 3.0f;
            int] frames = new int[4] { 9, 3, 6, 0 };
            int frameCount = 12;
            float divFactor = 9;

            // initial
            shadow.legs[Shadow.FL].Position = new Vector3D(shadow.legs[Shadow.FL].Position.x,
                shadow.legs[Shadow.FL].Position.y, 1.5f);
            shadow.legs[Shadow.FR].Position = new Vector3D(shadow.legs[Shadow.FR].Position.x,
                shadow.legs[Shadow.FR].Position.y, -0.5f);
            shadow.legs[Shadow.RL].Position = new Vector3D(shadow.legs[Shadow.RL].Position.x,
                shadow.legs[Shadow.RL].Position.y, -0.5f);
            shadow.legs[Shadow.RR].Position = new Vector3D(shadow.legs[Shadow.RR].Position.x,
                shadow.legs[Shadow.RR].Position.y, -1.5f);
            shadow.RefreshHardware();
            System.Threading.Thread.Sleep((int)(shadow.LastMovementTime));
            Dump();


                for (int frame = 0; frame < frameCount; frame++)
                {
                    // 0 = FL, 1 = FR, 2 = RL, 3 = RR
                    for (int leg = 0; leg < 4; leg++)
                    {
                        if (frame == frames[leg])
                        {
                            shadow.legs[leg].Position += new Vector3D(0, liftHeight, 0);
                        }
                        else if (frame == frames[leg] + 1)
                        {
                            var pos = shadow.legs[leg].Position;
                            pos.z = walkLength / 2.0f;
                            shadow.legs[leg].Position = pos;
                        }
                        else if (frame == frames[leg] + 2)
                        {
                            shadow.legs[leg].Position += new Vector3D(0, -liftHeight, 0);
                        }
                        else
                        {
                            var amount = walkLength / divFactor;
                            shadow.legs[leg].Position -= new Vector3D(0, 0, amount);
                        }
                    }

                    Logger.Instance.Log("Frame {0}", frame);
                    Dump();
                    shadow.RefreshHardware();
                    System.Threading.Thread.Sleep((int)(shadow.LastMovementTime - 10));
                }
        }

github.com/Lynxmotion/Quadrupeds
This code uses the SSC-32 and BotBoarduino, as well as the Lynxmotion PS2.
Perhaps you can find some way of adapting it?

Side note: The code mentioned here, Xan made some changes to my Arduino code base. This code base was converted from Basic to C/C++. My more recent versions of this code base is up on github. The version with the quad support is in the branch: github.com/KurtE/Arduino_Phoeni … ad-Support

Note: there are several configurations up on my version, but possibly not the configuration file for the Lynxmotion SQ3 as I did not test it with this version. Most of my Quad testing was done using the PhantomX Quad.

As mentioned the code is written in C/C++ and runs directly on the Microcontroller.

My guess is you are running C# on a PC that is talking to your servo controller. I don’t have versions of the code base for this. However we do have versions that take serial input for commands (instead of PS2 or Commander XBee, or RC), so you can do that as well.

Also have a version of the code base that was adapted to run on Linux (Raspberry Pi, Beagle Bone Black, Odroid, …, Intel NUC ), that is up on my Raspberry Pi project. (github.com/KurtE/Raspberry_Pi), which could also be adapted.

Edit: Forgot to mention, when I merged Xan’s updates into my code base, and worked with the PhantomX quad, I decided to convert the gait structure into
a class, I also allowed each project that uses this to define their own set of gaits. They can either replace the default set or add to the default set.
Example of this in my example file for PhantomX quad

Kurt

Thanks for the answers. I have already a SSC-32 card. I think it worth to try your codebase with arduino+ssc32 hardware. I have another question for this new hardware. I am planning to use Arduino Uno R3+SSC-32+Bluetooth Card. Is it possible to setup this kind of hardware? Does SSC-32 supports daisy chaining?

Bluetooth -> Arduino -> SSC-32. Not a problem at all.
If you want “dedicated” serial for both the Bluetooth and the SSC-32, use softserial (which converts two digital pins to slow serial pins).

Thanks. I setup my new hardware. Currently I have mini-quad + arduino uno + ssc32 + bluetooth with softserial. As software I have downloaded github.com/KurtE/Arduino_Phoenix_Parts/tree/Quad-Support/QuadC_PS2_SSC32. I have couple more questions, since I have ported to a new hardware it is very natural to have more questions :slight_smile:

Could you please point me to the code which accepts serial input for commands instead of PS2? I don’t have a PS2 controller and I am not planning to purchase one.

Correct me if I am wrong, but this code base is not optimized for mini-quad or SQ3 right? Should I expect to see successful stable gaits after having setup a mock controller (using serial port)?

With my In parts project, each of the Input classes and output classes are in different directories. You will notice that the current PS2 sketch includes the file
#include <Phoenix_Input_PS2.h>

You need for it instead to include the file: #include <Phoenix_Input_Serial.h>
Note: You can do this by simply editing the file. In this case sometimes I have found I have to close the Arduino IDE and reopen it. Also you can use the Sketch Import Library menu item to include this one. Note: The serial interface basically emulates the PS2 input and was compatible with the test program that came with the old free software Powerpod, which I no longer see up on the Lynxmotion website.

The code should work fine with the SQ3 as it included all of the changes that were done by Xan (Jeroen) and I believe one of the example sketches is directly from that. As for the mini-quad, earlier on I was testing on this one, but I was using a different legs (old type C) and I found it difficult to get a good walking gait. It would probably work easier with the type of legs that come with the SQ3, which I thought at one point I would convert mine to, but never did. I spend most of my quad time on a different Quad (PhantomX).

The difficulty of stability with quads is how well does the quad stand up on three legs. With some they do this without problems, with others, you need to shift the body weight under the three other legs. There are many strategies on how to shift the weight. I think we talked about a lot of it on the thread: viewtopic.php?f=8&t=8524
It also has a picture of mine with the CHR-3 type legs.

The answer is simple. You need to update the position of each leg at a faster rate. A reasonable rate might be 25 times per second. I think from looking at your software you were only telling the leg to move to the end point. That will make the leg zip along as fast as it can. If you want it to take one step per second then, 25 times per second yu tell it to go another 25th of the way there. Now yu don’t have to move in a straight line you can follow a parabola or sine curve and can and can rig it so the leg hit the ground with the the negative of the robots body velocity. It takes MUCH more computation so some people off load the work to a smart controller that can to the high rate update to all those servos.

25Hz is not a magic number 10Hz can work but the human eye is fooled into seeing continuously motion in video and movies if the frame rate is over about 18 frames per second. I think this same rules holds of mechanics, 18+ Hz is as good as you need EXCEPT it you are doing dynamic balance or a running gait and then I think people go for 100 Hz. You need a bigger computer maybe even for 25Hz and 12 DOF. But even 8 Hz will look OK. Do all the math in integer millimeters and use trig lookup table and you can do IK quickly even on the Arduino.

So your loop might look like this…

wait for a 25Hz "tick"
Compute the desired location of a leg for this exact time.  
send the position command to the servo

Then outside of this 25Hz control loop you do the higher level controls like updating the motion paths for the legs, checking the sonar sensors and deciding where to go. In my code I have a list of what I call “paths” where each one has a target velocity and end point in (x,y,z) and the code that runs in the 25Hz loop looks at the current time and the end point time and computes IK to get to an interpolated x,y,z. There is some optimization where if the “delta x,y,z” is “small” we do nothing and save having to do another IK.

I smarter method I have not implemented yet is to compute a JOINT velocity curve for each leg. I use an XYZ curve. It is much easier to interpolate joint velocity and you can do fewer IKs