A Walking Robot That's Easy to Build
by Peter Balch in Circuits > Robots
10358 Views, 73 Favorites, 0 Comments
A Walking Robot That's Easy to Build
This is a robot that anyone can build on the kitchen table. You don't need a 3D printer. You don't need special tools. You don't need a workshop. But you do need a soldering iron to build the circuit.
I've also included a gait (stepping pattern) generator Windows program. It's difficult to program walking robots and the Windows program should simplify creating Arduino sketches.
Making robots is hard. There are three knowledge domains. You need to know about electronics to design the circuit. You need to know about mechanics and engineering to build the hardware. And you need to know how to program to get it to work. Walking robots are particularly hard to build and to program.
I've looked at the comments and questions on other Instructables and I see there are people who know one of two of the domains but are struggling with the third. So I've tried to design something that anyone can build and program (if you already know how to program an Arduino). I hope it can get people started and then they can learn the parts of robot building they don't already know.
Although this Instructable describes a specific robot, I'm trying to explain how to design walking robots in general and to encourage you to design and build your own.
Why a walking robot if they're harder? Because walking robots are cool. People like walking robots. I think that's the only reason you'd build a walking robot. When I ask AI researchers they talk about going into earthquake zones or damaged nuclear reactors and how walking robots can go places that wheeled or tracked robots can't. It's just nonsense. Look at videos of the best quadrupeds - Big Dog or Spot for instance - and see the sort of terrain they are walking on. Now imagine a tracked or wheeled vehicle the same size; it could go over much more difficult terrain. Search YouTube for "rc rock crawler competition" and imagine any walking robot on the same terrain. But walking robots are way more cool.
The project requires an Arduino Nano (or Uno or ProMini), 12 or 13 servos, a battery pack of some sort, around 100gm of Polymorph and maybe some bamboo skewers. For programming, you'll need a PC and a USB cable. Search eBay or your favourite supplier for "Polymorph". "Polymorph" is a generic term for Polycaprolactone. It is also available under many other trade-names.
As I said, you do need a soldering iron to build the circuit. That's a pity - it would be nice to be able to say "no special tools required" - but I can't find a module that doesn't require at least some soldering. Sorry.
Other than the soldering iron and a screwdriver you only need the implements you find in a kitchen.
Making One Leg
There are lots of websites about "what is a servo" if you need the background information. This robot uses micro servos (also called 9g servos because they weigh 9 grams).
If you buy 20 micro servos they should be a little under £2 each. You could buy standard-sized servos with ten times the torque and scale-up the whole robot. It's worth buying a few "Servo Tester" modules. They're around £1 each. You can see how I've glued four of them onto a strip of wood with 4 AA cells (above).
One of the most important specifications for a servo is its maximum torque. A cheap micro servo will be advertised as 1kg.cm or maybe 1.5kg.cm. 2kg.cm and 2.5kg.cm micro servos are available but they ought to have metal gears and bearings and hence be be more expensive. If they're cheap and claim "2kg.cm" don't believe it. In fact, don't believe claims of "1kg.cm" either. The servo might just about work at that torque but you're much better to assume 0.5kg.cm for a long life.
0.5kg.cm means that if the arm on the servo is 1cm long then it can lift 0.5kg. If the arm is 10cm long then it can lift 0.05kg and so on.
The servo arm ("horn") can rotate up to 180deg. It depends on the manufacturer. A more reasonable estimate is 135deg. There is no standard for which way a servo arm rotates as the control pulse lengthens - some go clockwise and some anticlockwise.
How much does your robot weigh? This one is 240g (plus 120g for 4 AA cells or 60g a 1000mAh Li cells) and you'd like it to be able to carry an extra 50g of "cargo". How long is the leg? In this case it's 5cm when it's bent 90deg. The weight when will be shared between fours legs - 95g each. so that's 0.475kg.cm. When it's walking, could easily double or triple so even a light robot like this is at the limit of the servos.
I decided not to use a 3D printer or any hardware that requires engineering skills. Instead, I've used Polymorph.
Above is a photo of an earlier quadruped that I built using metal and acrylic.
Polymorph is heated with hot water and can then be moulded by hand. I usually drop it into a coffee cup full of recently boiled water. It can be reused by reheating it above 62deg. It can be coloured when soft: roll it out flat; sprinkle powder paint on it, fold it in half; and repeat a few times. Once it has cooled and hardened, it can be drilled and cut. I find self-tapping screws are the best to use. There are lots of websites on how to use polymorph.
I work in the kitchen and use hot water in a coffee mug to heat the polymorph. You need to be near a kettle to keep the water hot - it soon cools down.
You can see that I've made the tibia out of a 7mm dia rod with a servo arm embedded in one end. The polymorph doesn't really adhere to the arm so I put a thin strap around the end of the arm. The overall length is 50mm to 55mm.
I tried adding feet made from pencil erasers. They work well. But they grip a little too well when you're developing your gaits and sudden jerks can damage the servo gears so I removed the erasers and the feet are now more slippery.
The femur contains the bodies of two servos. They're held together by a frame of polymorph. I embedded a piece of bamboo skewer in the frame to stiffen it but it's probably not needed. The overall length (between the centres of the servo axes) is 50mm to 55mm.
The coxa ("hip bone") contains two embedded servo arms with their axes at right angles. The polymorph has to enclose them with just the splines and screw-holes exposed.
The polymorph for one leg weighs 15g which should give you an idea of how much polymorph you'll need for the whole project.
Four Legs and a Chassis
To walk forward and turn, a quadruped should really have 3 degrees of freedom (DOF) per leg. So that's 12-DOF and 12 servos in total.
When a robot turns on the spot, it should move its legs sideways as well as forward/back. Some people make quadrupeds with just 2-DOF legs. They turn by taking longer strides on one side than the other. So they turn like a tank. Therefore the feet have to slip sideways as they turn. If you look at the videos of an "8-DOF quadruped" you'll see that the feet slip a lot and they can only walk on a shiny surface.
(Similarly, a sprawled gait - like a spider - can be used with 2-DOF legs but it too depends on the feet slipping.)
But what if the robot turns around a spot between its back feet? The back feet need only move forward/backward while the front feet move sideways. Maybe 2-DOF back legs and 3-DOF front legs is a good compromise. I haven't tried building a 10-DOF quadruped.
In this 12-servo design, the central chassis holds the four coxa (hip) servos in place.
At first, I made a sandwich. Two thin plywood boards act as the "bread" of the sandwich and the servos are the jam. Three M2.5 nuts-and-bolt hold each servo in place. That was really quite quick to make.
But I'm trying to design a robot which is easy for people to build so I decided to use polymorph and bamboo skewers to make a framework. Once again, there's a sandwich. Self-tapping screws hold the top and bottom together and clamp the servos in place. Polymorph doesn't stick well to bamboo skewers (or to much else). In the case of the femurs, I totally enclosed the skewers in polymorph. Similarly I almost totally enclosed the servo horns when making the coxae. For the chassis, I smeared hot-glue from a hot-glue gun onto the ends of the skewers. Polymorph sticks fairly well to hot-glue.
Polymorph Joints
Hobby servos were designed for model aircraft. The servo sits in the body of the aircraft and operates the rudder, ailerons, etc. via wire rods. That's how you're meant to use them. But robot designers try to use the bearings built into the servo as the knee or hip joint of a leg. I've done it that way myself in the design here but I reckon it's the wrong way to do it.
The joint should be separate from the servo's bearing so it can be stronger. The joint is then operated by a wire rod. I'll explain how you can make legs that way in a later section.
If you use a wire link and make the distance from the attachment point on the leg twice then length of the servo arm, you can double the weight the servo can lift. You have halved the angle through which the joint can move but you've doubled the strength. For a leg, that seems a good trade-off: during walking, a knee or hip generally moves through less than 90deg.
For a robot arm, it's even more important to use links. If you look a miniature arms, the proximal servos have to lift the weight of the distal servos. For instance, the weight of the gripper servo shouldn't be at the end of the arm. Many miniature arms can hardly even lift their own weight. With wire links, you can move the gripper servo to nearer the centre of the body and lower the weight the arm has to lift.
You can form joints with polymorph. Roll a cylinder then squeeze a V into it to be 0.5mm to 1mm thick. I've found it best if the resulting constriction is 12-16mm wide. That gives a flexible but slightly springy joint.
How tough is it? Very tough. I don't know how tough as I haven't managed to break one yet. I attached one to a crank and flexed it 10,000 times. It still seemed as good as new.
Gripper
The gripper uses two polymorph joints and wire links. I fitted pencil erasers to the fingers to give them better grip.
I decided not to put the gripper on the end of an arm The robot can manoeuvre itself into the right position to pick up the object.
To be honest, I think a 1-DOF or 2-DOF arm would be an improvement.
Poly-Jointed Legs
You can see in the photo how I've made a 2-DOF leg with a hip and knee joint. In this example, I've sandwiched a thin sheet of polymorph between the two servos to act as an anchor then rolled a cylinder by hand and nipped it to form two joints. It takes a few attempts to get it right the first time but it becomes easier with practice.
Use steel wire for the links - copper wire isn't strong enough. I'm using 0.75mm copper-coated MIG-welder wire (I got a huge reel in a car-boot sale which will last a lifetime). You could also use 22swg "Piano Wire" from a craft shop or eBay or search for "steel craft wire". If you search eBay for "MIG wire" you'll find it's much cheaper and has the advantage that, being copper coated, you can solder it. You could also try welding hire shops - they may have the tail-end of a reel they want rid of.
I didn't have time to finish a set of four 3-DOF legs. I will let you know how I get on.
Designing Poly-Joints
There are lots of ways of arranging the servos and joints to make a leg. Small changes in the lengths of the segments can make a big difference to how the leg moves.
This device is called a "linkage mechanism". There are several linkage-design web pages and my own Windows program is available on GitHub. Or google "free online linkage simulator".
My own program is designed to facilitate making legs. You can specify the "ground" plane and the height that you want to foot to rise to. You can then tell the program to optimise the lengths of the links to find the longest step size within that constraint. Having designed a linkage, you can ask what torque the servos will experience when supporting the weight of the body. You can specify a maximum torque and find the longest step size that doesn't exceed that torque.
For instance, in the design above, the maximum torque is 0.5kg.cm.
Having found a design I like, I then print it on paper and use it as a reference when making each leg.
The linkage mechanism is designed as a chain of triangles. In Edit mode, to create a new strut:
- Left-click on an existing point
- drag the line
- mouse button up then down to create a new point and strut
- move the mouse near another point
- Left-click to connect the second new strut
The program calculates the positions of points by considering the triangles in the order you created them. The last point to be created is always the "foot".
You can drag existing points by holding down the Shift key.
This program simulates linkage mechanisms and two servos or motors.
The sliders on the right adjust the lengths of the struts and the zero-angle of the servos. If you set a strut length to an "impossible" value then the drawing goes "elasticated".
In Optimise mode, it is assumed that you are trying to create a leg for a walking robot. You can adjust the position of the ground and the height of the step. The green box is the region that the foot must step over.
The optimiser tries to maximise the length of the step by making small changes to the lengths of the links. Always turn off the optimiser and let the program return to the "best" leg arrangement before saving the file.
In the Move mode, you can create servo-position "waypoints". Use the scrollbars at the right to move the servos then Right-click to get a popup-menu which allows you to save that position as a waypoint. When you "Run" the waypoints, the program linearly interpolates between the servo angles. That may not move the foot in a straight line and you may have to add more waypoints. Hold the Control key down to drag the foot.
In Torque mode, the program calculates the torque on the servos for a unit force upwards or sideways on the foot. It displays the maximum torque for the two servos as a coloured chart. The colours show the torque generated by either a horizontal or a vertical force (choose in Options). Darker colours mean the robot is weaker. If you move the mouse over a point, the torques due to the horizontal and vertical forces are shown at the bottom left. The torque generated in a real robot depends on the scale of the drawing and the weight of the robot. The torque is calculated and displayed in Newton-pixels and kg.cm.
Electronics
You can drive the servos directly from an Arduino Nano using the internal timers of the ATmega chip to generate the required signals. As you can see, the circuit is very simple.
There is a row of three pins for each servo servo connector. The pins are
- ground - black wire
- power - red wire
- signal - white wire
Some servos use different colours
- ground - brown wire
- power - red wire
- signal - orange wire
(In the Olden Days, some servos had the pins in a different order. If you plugged them into a standard supply, you'd burn-out the electronics instantly. Since about 1990 servos have all used the modern pin order. I think even Airtronics have got rid of their weird pin order. But If you have an old or second hand servo, take care.)
I assembled the circuit on stripboard. The diagram shows my layout. The cyan lines are the copper strips under the pcb. Red lines are wires on the top (component) side. Magenta circles are cuts in the copper strips.
The Arduino sketch can control up to 18 servos but I only fitted pins for 13 of them.
You should use separate power for the servos and the Arduino 5V. Do not try to power the servos from the 5V supplied by the Arduino - the 5V regulator can't supply enough current and will burn out. Do not try to power the servos from the 5V supplied over the USB cable - it can't supply enough current either. Use a separate supply such as 4 AA cells. A standard servo will have a stall current around one amp, a micro servo might be half that.
Most servos nominally run on 6V but they will work with 5V (with reduced power) up to maybe 6.5V. So four AA cells will be OK. (Of course there are always exceptions - "high voltage" servos might work with 9V and "low voltage" ones with 3.7V. I'll assume you have 6V servos.)
If you're a beginner, it's easier to stick with AA cells (alkaline or NiCd). But Lithium cells have up to twice the energy per gram of alkaline or NiCd cells.
You could use two "3.7V" Lithium cells but when they're fully charged they'll produce as much as 4.2V each. That might be too much for some servos. You can reduce the voltage by passing the power through two or more silicon diodes. Each diode will drop the voltage by around 0.7V.
You can remove the Lithium cells to recharge them or add an external charging module.
Learning a Simple Gait
You now need to program the robot to walk. At this point in other projects the author generally seems to step aside. Their answer is either that you write your own C program or "here's my program maybe it will work with your robot" or perhaps they talk about inverse kinematics. An Arduino isn't really capable of inverse kinematics and inverse kinematics requires the program to have an accurate internal model of the robot which, for a hobby robot, is unlikely.
The more I think about the problem, the harder I think it is.
We don't want to move the servos at their maximum speed by simply setting their angles. We want them to move in a coordinated way at a reasonable speed.
Let's define some terms. A "Pose" is a set of angles of the leg servos. A "Gait" is a sequence of "Poses" that makes the robot move - preferably without falling over.
How can we easily program an Arduino to do that? We'll store the poses of a gait in memory as a table of numbers - the servo angles - and play them back in sequence using a timer of some sort. Where do the numbers come from? We'll teach them to the robot by sending them from a PC.
Imagine you're making a stop-motion animation of a walking quadruped. You adjust the leg positions and take a photo. Then you adjust the leg positions again and take another photo. Eventually you've got a movie.
Servo18.exe is a Windows program that allows you to nudge the servo angles by sending commands to the INO sketch (see next section). You can then store their angles on the PC as a "Pose". The sequence of poses - the "gait-table" - can then be sent to the Arduino to be stored in EEPROM or can be exported as a *.H file.
A typical crawl walking gait might have 12 poses. When it's executing the gait, the Arduino will play-back the poses perhaps over 4 seconds.
That's 3 poses per second. To make it less jerky, the Arduino does "inbetweening". The gait-table provides the "keyframes".
Inbetweening is done by linearly interpolating the servo angles. Does that give a linear interpolation of the foot position? Not exactly but it's close enough if the change in servo angle is small.
I'm not going to give a user's manual of Servo18.exe here. I hope the user-interface is simple enough for you to work out how to use it. You would typically
- Open the Walk.btn file which describes a quadruped robot
- right-click on the buttons near the joints in the image to connect them to the correct servos
- (you could add your own robot with it's own image and drag the buttons around)
- click Gait|NewGait to start a new gait
- click the buttons near the joints to nudge the servos to the correct angle
- click Gait|AddPose to add the pose to the gait-table
- click the Run checkbox to run the gait from the PC
The program sends commands to the Arduino to move the servos together. If a change from one pose to another requires servo A to turn a small angle and servo B to turn a large angle, the program will turn servo A more slowly so they both arrive at the pose at the same time. The program allows you to specify the maximum speed any individual servo can move and the minimum time to progress from one pose to the next.
A gait-table specifies which servos the gait applies to. For instance, you might have 12 leg servos and 3 arm servos. There would be gait-tables for leg movements and gait-tables for arm movements. both "gaits" could be run at the same time without interfering with each other. I suppose you could build a robot like a praying mantis: it normally walks as a hexapod but can rear up on its hind legs and use its front legs as arms.
The Arduino Sketch
The Arduino Quad3.ino sketch can control up to 18 servos.
- Servo 0 = pin D2
- Servo 1 = pin D3
- Servo 2 = pin D4
- Servo 3 = pin D5
- Servo 4 = pin D6
- Servo 5 = pin D7
- Servo 6 = pin D8
- Servo 7 = pin D9
- Servo 8 = pin D10
- Servo 9 = pin A0
- Servo 10 = pin A1
- Servo 11 = pin A2
- Servo 12 = pin A3
- Servo 13 = pin A4
- Servo 14 = pin A5
- Servo 15 = pin D11
- Servo 16 = pin D12
- Servo 17 = pin D13
The sketch includes my own version of the Servos.h Arduino library but I have added more servos. The standard library allows a maximum of 12 servos per timer and for the Arduino Nano, it uses only one timer. I've modified the Servos.h file to allow 18 servos per timer.
#define SERVOS_PER_TIMER 18 // the maximum number of servos controlled by one timer
And I've renamed it to myServos. Put all the files in the same directory as the Quad3.ino sketch.
Using 18 servos per timer alters the timing a little when you're using all the servo pins at once but seems to work OK.
Gait-tables can be stored in PROGMEM or EEPROM.
To use EEPROM, include this line in the sketch
#define UseEEPROM
(It's commented out by default.)
I don't recommend using EEPROM. It's too small to be useful. If a gait typically has 12 poses for 12 servos, that's 144 bytes, So you'll only have room for 7 gaits in the 1024 bytes of EEPROM.
I'm going to assume you're using PROGMEM which is much bigger. In theory you'll have room for hundreds of gait.
Each gait-table has the following format:
- number of poses in gait (1 byte)
- ServoSet - 1 bit per servo (4 bytes)
- servo angles (numposes * servoset.count bytes)
The Servo18.exe program can write its gait-tables to a file usually called Gaits.h.
A typical Gaits.h file contains
const byte WaveLegs[] PROGMEM = { 9, // num poses 0xFB,0x1F,0x00,0x00, // servo set 71, 149, 90, 90, 90, 90, 36, 109, 86, 134, 75, 54, 71, 149, 90, 90, 90, 90, 36, 109, 86, 134, 134, 120, 71, 149, 90, 90, 90, 90, 36, 109, 86, 134, 75, 54, 71, 149, 90, 90, 90, 90, 36, 109, 136, 53, 75, 54, 71, 149, 90, 90, 90, 90, 36, 109, 86, 134, 75, 54, 133, 88, 90, 90, 90, 90, 36, 109, 86, 134, 75, 54, 71, 149, 90, 90, 90, 90, 36, 109, 86, 134, 75, 54, 71, 149, 90, 90, 90, 90, 84, 41, 86, 134, 75, 54, 71, 149, 90, 90, 90, 90, 36, 109, 86, 134, 75, 54}; const byte Grip[] PROGMEM = { 2, // num poses 0x04,0x00,0x00,0x00, // servo set 79, 136}; int GaitTableAddr[] = { WaveLegs, Grip};
This example contains two gaits: WaveLegs and Grip. With WaveLegs, the robot lies on its back waving its legs in the air (a useful test!). With Grip, the robot opens and closes its gripper.
The WaveLegs table says that is contains 9 poses. The servos it uses are in the set 0x1FFB. That's a long integer with 1 bit per servo There are 12 bits set so the gait uses 12 servos. Bit 2 is set to zero so servo 2 is not used. Then come 9 poses and each pose specifies the angles of 12 servos.
The Grip table says that it contains 2 poses - gripper open or closed. The servos it uses are in the set 0x0004. There is one bit set in the servo-set so the gait uses 1 servo. Bit 2 is set so servo 2 is used for the gripper.
Of course, you will have plugged the leg and gripper servos into different pins. You will have specified that in the Servo18.exe program.
Opening and closing the gripper is not really a "gait" but it's controlled by a gait-table so we'll call it a gait.
You can run a gait from your INO sketch by calling
void StartRunGait( int gait_addr, int blend_addr, byte poseStart, byte poseEnd, byte MaxServoSpeed, byte MinApproachTime, byte aShare);
If you are running a simple gait then
- gait_addr is the address of the gait-table
- blend_addr is set to -1
- poseStart is the staring pose
- poseEnd is pose it should stop at; set to 255 to run forever
- MaxServoSpeed is the maximum speed any servo can run at
- MinApproachTime is the minimum time it must take the servos to reach a target pose
- aShare is ignored
If you are blending two gaits then
- blend_addr is the address of the gait-table of a gait that should be blended
- aShare is 1..100 and is the share of the blend that the gait_addr gait will contribute; the blend_addr gait will contribute (100-share)
Blending is discussed in Step 12.
For instance, to run a single gait forever:
StartRunGait(WaveLegs, -1, 0, 255, 100, 0, 100);
Each gait has its own MaxServoSpeed. It is the maximum speed any servo can run at. You don't want the servos to run so fast, they're really jerky. 100 is a reasonable value.
If several servos are approaching a set of target positions then they will take a certain amount of time to reach them. When walking, you want each phase of the gait to take roughly the same time. The sketch calculates how fast each servo must move so they all reach their targets simultaneously. MinApproachTime is the minimum time it must take the servos to reach a target pose.
The purpose of the Quad3.ino sketch is to accept and run commands from a PC and allow you to develop your gait-tables. You will replace it with your own sketch that does something useful with your robot.
When the sketch starts, the servos must have reasonable value for their angles and targets - otherwise they will go to a crazy position. The sketch sets them all to 90 degrees.
Notice how the main loop of my program contains the code
RunGaits();
RunGaits() runs the code to control running the gait tables. If you don't call it every few milliseconds, none of the gaits will run. So you must remember to call it inside any loops that are waiting for something to happen.
Download all these files and copy them into a directory called Quad3. The Gaits.h file is just an example - you will have to create your own version using the Servo18.exe program.
The Crawl Gait
There are lots a web pages about the crawl gait for a quadruped so I'm not going to describe it in detail.
To walk forward, you lift one foot at a time and move it forward while the other three feet are forming a triangle. The centre of gravity of the robot is always inside the triangle. The order in which you lift the legs determines how big the triangle is. The optimum order of foot lifts turns out to be
- back-left
- front left
- back-right
- front right
The robot should, for instance, put the back-left foot down just before it raises its front-left foot. So, for a moment, all four feet are on the ground.
Why does a crawl gait require 12 poses?
For each leg we need poses for
- foot up at rear of stride
- foot up at front of stride
- N poses as the foot is down and moving backwards
There are 4 legs so that's at least 2*4=8 poses per gait - i.e. N=6.
But if you look at Fig1 you'll see that in pose 8, the back-left foot is going up while the front-left foot is going down. So we need to insert an extra pose in which both feet are down. Similarly for pose 4 and the back-right foot and similarly for poses 2 and 6. That's 4 extra poses giving 12 poses in total which gives Fig2. In Fig2 you'll see that in poses 1,4,7 and 10, all four feet are on the ground.
Gait Transitions
So far so good. You've got your robot walking forward in a straight line using the crawl gait. The order of foot lifts is BL-FL-BR-FR.
To walk backwards, just reverse the sequence of poses - run the gait-table backwards. To crawl forwards curving to the right with a small degree of curvature you can use the same gait but move the feet side-to-side as you move them backwards and forwards. There could be a way to blend the side-to-side movement of a foot with the forwards-backwards movement of the foot to get different amounts of curvature.
Traversing to the left is different. It's like the forward crawl but the the order of foot lifts is BR-BL-FR-FL. Traversing to the right is the reverse of that.
To rotate clockwise on the spot, the order is BR-BL-FL-FR. That's different again.
Because the order of foot lifts is different, there's no way to blend the traversing gait with the forward gait to get a diagonally-forward-and-to-the-left gait. Similarly there's no way to blend the rotation and forward gaits to get forward-rotate gait to get a tight turn. You can only blend gait-tables which have the same number of poses and where the foot-lifts occur in the same places.
Most papers on gait transitions are behind paywalls but here is a good open-access one: "Omnidirectional Static Walking of a Quadruped Robot" Ma, Tomiyama, Wada, 2005. Or you can use Google to find a different open access copy.
They discuss the problem of merging or blending gaits and suggest that to transition from one gait to another you find two poses that are similar in the two gaits and swap between gaits when you reach that pose. Which is what you've probably thought of yourself. Ma, Tomiyama, and Wada call a transition point a "diagonal triangle exchange" (DTE) point. They suggest that every DTE should involve three feet down forming a triangle. You can imagine that pose 2 of the forward gait (above) could easily transition to pose 2 of the rotation gait: the three down feet match exactly and the up foot can be moved to its new position.
You could also have short gait-tables specifically for transitions: if you're in pose n of gait A and want to swap to gait B, then use gait-table C which will perform the required intermediate poses.
Here, here and here are some other papers.
All this implies that you can't change immediately from one gait to another. You may be used to wheeled robots which can instantly change from forward to forward-turn then to turn-on-the-spot. Quadrupeds can't do that. There are certain transition points that they must use.
Blending Gaits
So far we've discussed running a single gait-table. We must now consider running multiple gait-tables.
The easy way to Blend gaits is when there is no overlap in their servo-sets. The servos used in one gait-table are not use in the other gait-table. Perhaps we have legs and an arm. We can simply start and stop the gaits whenever we like.
There's a more complicated way of blending gaits.
Let's say you have one gait for "walk forwards" and another for "walk forwards and turn to the right" or for
- "walk forwards and traverse to the right"
- "walk forwards while crouching"
- "walk forwards on tip-toe"
- etc.
All these gaits use the same servos, all have the same number of poses in the table and all lift their legs in the same order. So we ought to be able to say
- I want to Blend the servo angles of table A and table B
- I want 80% of table A and 20% of table B
So you could gradually change from a normal walk to a crouching walk.
As described in Step 9, Quad3.ino allows you to run two tables simultaneously and Blend them by calling StartRunGait().
You can run a gait from your INO sketch by calling
void StartRunGait( int gait_addr, int blend_addr, byte poseStart, byte poseEnd, byte MaxServoSpeed, byte MinApproachTime, byte aShare);
If you are blending two gaits then
- blend_addr is the address of the gait-table of a gait that should be blended
- aShare is 1..100 and is the share of the blend that the gait_addr gait will contribute; the blend_addr gait will contribute (100-share)
StartRunGait() assumes that the servos in the gait-table are not already in use in other gait tables. It assumes that the two tables share servos. The tables must contain the same number of poses.
If a servo is in both tables then its angle is set to
- (angleA * share + angleB * (100-share) / 100
If a servo is in just one table then its angle is set to the value specified by that table.
The pose number applies to both tables: if you're in pose 3 of one table then you're also in pose 3 of the other table.
When a gait-table is running, you can ask what pose number the robot is currently executing:
byte QueryPose(int gait_table_addr)
The result is the pose number that the robot is approaching (its target pose) or has already reached. If the gait-table is not running, the result is 255.
You can ask whether the servos have reached their target angles
bool AtTargets(int gait_table_addr)
When a gait-table is running, you can stop it immediately with
void StopNow(int gait_table_addr)
Or you can tell it to stop when all the servos of the table have reached their target angles:
void StopWhen(int gait_table_addr, byte poseN)
So to transition from the "Forward" gait to the "Spin" gait, you would find poses that matched in the two tables; stop one table at pose A and start the other at pose B:
- StartRunGait(Forward, -1, 0, 255 ...);
- ... // do other things
- StopWhen(Forward, poseA)
- while ( ! AtTargets(Forward)) {
- ... // do other things
- }
- StartRunGait(Spin, -1, poseB, 255 ...);
The Future
I'd like to have included a lot more in this Instructable but the deadline for a Robots competition is fast approaching.
As I said at the beginning, making robots is hard. You need to know about mechanics, electronics and programming.
Polymorph makes mechanics easier.
The electronics that I've suggested is very easy to build but perhaps you'd prefer to drive the servos in hardware. Search eBay or your favourite supplier for "pwm servo driver pca9685" or some combination of those words. I've bought one but I haven't got around to programming it yet.
I have previously written servo driver software for PICs which included a servo saver. The idea is that you put a 1 ohm resistor in the "ground" pins for all your servos - just one resistor shared between them all. The 1 ohm resistor is connected to an ADC input of the Arduino to measure the current through the servo.
When you send a pulse to a servo, the pulse width specifies the servo angle. The servo turns on its motor for a few mSec to bring it closer to the target angle. The 1 ohm resistor allows you to measure the width of that pulse. As soon as the pulse finishes, you do the same for the next servo and so on. So you know how hard the servo is working. That information might be useful within your robot program - e.g. it might tell you that a gripper is holding something. If the servo pulse width exceeds a maximum value for more than a few pulses, the servo is jammed. You stop sending command pulses to all the servos. The servos all then relax. It acts as a servo-saver and you stop breaking the gear teeth when your legs jam.
Programming robots is hard. I've been thinking about the problem for decades. Any program can be written in any reasonable computer language so why do we need a different language for robot-programming? A lot of people think "I know C and C can do anything so why should I ever need anything else". It's because C is missing a lot of features robot languages need.
Robot software is so fascinating because it must be an integrated whole that operates at very many different levels. Other software applications aren't like that. Robot software must operate at levels from the bare metal up to, say, neural-nets, vision or knowledge-based-reasoning algorithms. It must include parallelism because a robot must keep track of many things at once. And it should be able to describe a system which operates over several processors.
Robot programming requires us to consider both Flow of Execution (like C) and Flow of Data (like LabView) and there's currently no programming language that adequately covers both. Plus you certainly need multitasking. Multitasking on an Arduino Nano is a little tricky but not impossible.
For hobby robots, you may be wanting to let beginners program the robot. Scratch and Mindstorms allow drag-and-drop programming but they're not good at Flow of Data and their multitasking leaves a lot to be desired. And none of the score of languages I've used allow a program to be spread over multiple processors (alright, I did program in Occam for a little while) and over a variety of processors.
I'm a huge fan of the subsumption architecture for small robots. So should the language encourage subsumption?
The program IDE should allow lots of feedback from the robot's sensors. It should show graphs and diagrams of what the robot is sensing otherwise it's very hard to work out why your program doesn't do what you want.
Should you program by dragging and dropping pictures or by writing text? Robot programming requires us to consider both Flow of Execution and Flow of Data. I think those two was of looking at the program should be dealt with by separate, different syntax and semantics. The arguments for visual vs textual are different for those two domains. Imperative programming languages (like C) concentrate on Flow of Execution. Analogue computers (and their digital simulations, e.g. for servoing) concentrate on Flow of Data. Much business software concerned with "transaction processing" is defined by Flow of Data. Subsumption neatly separates Flow of Execution and Flow of Data. Vision processing software is defined by both Flow of Execution and Flow of Data. Etc. etc. The arguments go round and round.
So I will try over the next few months to write an Arduino compiler that incorporates Flow of Execution, Flow of Data, subsumption and visual programming.
Maybe you could think about the problem yourself and let me know your thoughts or discuss it in the comments below.