Skip to content

Movement

Ahmed Dabak edited this page Jul 25, 2026 · 4 revisions

Movement

Introduction

Legs drives the four leg and foot servos: two hips, two feet. It is a facade over the LegServos module, and its whole purpose is that a sketch never contains a bare 1 or -1 for a direction.

Legs::walkForward(2);
Legs::turnLeft(1);
Legs::home();

Movement is enabled after OttoFlow::start(). To keep the robot still while you work on other hardware, see Bench Testing.

Warning Put Otto on the floor, not on a table, before enabling movement. A walking Otto reaches the edge sooner than you expect.

Walking and turning

Legs::walkForward(2);            // two steps
Legs::walkBackward(2);
Legs::turnLeft(3);
Legs::turnRight(3);

Each takes an optional period in milliseconds -- the duration of one movement cycle. Higher is slower:

Legs::walkForward(4, 700);       // brisk
Legs::walkForward(4, 1300);      // careful

Defaults are 1000 ms for walking and 2000 ms for turning. Roughly 600 to 1400 ms is the useful walking range; below that the servos cannot keep up and Otto shuffles in place.

home() returns all four servos to the rest position. It is worth calling before and after a sequence, so every behaviour starts from the same stance:

Legs::home();
Legs::walkForward(3);
Legs::home();

Small moves

Legs::bendLeft();                // steps = 1, periodMs = 1400
Legs::bendRight(2, 1200);
Legs::shakeLeftLeg();            // steps = 1, periodMs = 2000
Legs::shakeRightLeg(2);
Legs::jump();                    // steps = 1, periodMs = 2000

jump() is more of a hop, and it is demanding: it needs fresh batteries and a surface with some grip.

Dance moves

Each of these repeats for a number of cycles and takes an amplitude in degrees -- how large the movement is.

Legs::moonwalkLeft(3);
Legs::moonwalkRight(3, 900, 25);
Legs::crusaitoLeft(2);
Legs::crusaitoRight(2);
Legs::swing(2);
Legs::tiptoeSwing(2);
Legs::upDown(4);
Legs::jitter(2);
Legs::ascendingTurn(2);
Legs::flapForward(2);
Legs::flapBackward(2);
Move Signature What it looks like
upDown (cycles = 1, periodMs = 1000, amplitude = 20) Bobbing up and down on both feet
swing (cycles = 1, periodMs = 1000, amplitude = 20) Rocking side to side
tiptoeSwing (cycles = 1, periodMs = 900, amplitude = 20) Rocking while up on the toes
jitter (cycles = 1, periodMs = 500, amplitude = 20) A fast nervous shudder
ascendingTurn (cycles = 1, periodMs = 900, amplitude = 50) Turning while rising
moonwalkLeft / moonwalkRight (cycles = 1, periodMs = 900, amplitude = 25) Sliding sideways
crusaitoLeft / crusaitoRight (cycles = 1, periodMs = 900, amplitude = 20) A leaning sway
flapForward / flapBackward (cycles = 1, periodMs = 1000, amplitude = 20) Feet flapping like fins

A short routine:

Legs::home();
Legs::upDown(2, 800, 25);
Legs::moonwalkLeft(3);
Legs::moonwalkRight(3);
Legs::jitter(2, 400, 30);
Legs::home();

Gestures

A gesture is a whole performance: movement, a face on the matrix, and a sound, in one call.

Gestures::play(Gesture::Victory);
Gestures::play(Gesture::Love);
Gestures::play(Gesture::Sleeping);

Thirteen are built in -- see the full list, with what each one does. Each blocks for roughly 0.5 to 3 seconds and self-resets at the end, returning to home() with a happy face. Because gestures move the legs, they respect Legs::disable() / Motion::disable(): a disabled robot performs nothing rather than half of the gesture.

Two names catch people out. Gesture::Wave is a wave pattern animated on the LED mouth -- it does not move a limb; the physical wave is Arms::waveRight(). And Gesture::Fail deliberately goes limp mid-gesture, so the momentary flop is expected. (Wave and Magic are mouth-and-sound only, so they play even while movement is disabled.)

Gestures are the fastest way to give a sketch personality:

if (Eyes::closerThanCm(10)) Gestures::play(Gesture::Confused);
if (Touch::wasTapped())     Gestures::play(Gesture::Happy);

Poses and single servos

For calibration, custom animations, or a stance of your own, address the servos directly. Angles run 0 to 180 degrees, with 90 as the centre:

Legs::positionLegLeftDegrees(90);
Legs::positionLegRightDegrees(90);
Legs::positionFootLeftDegrees(90);
Legs::positionFootRightDegrees(90);

These jump to the angle immediately. To move all four together, smoothly interpolated like a keyframe, use:

Legs::positionAllDegrees(90, 90, 90, 90);         // 200 ms by default
Legs::positionAllDegrees(70, 110, 90, 90, 800);   // a slow lean

Arguments are, in order: left leg, right leg, left foot, right foot, and the duration in milliseconds.

Enabling and disabling movement

Legs::disable();     // detach the four leg servos
Legs::enable();
bool moving = Legs::isEnabled();

While disabled, the servos are detached -- no jitter, no current draw -- and every movement call is a silent no-op. Your sketch keeps running normally; the robot simply stays still.

Motion is the switch for all servos, legs and arms together. It is the single call for "the robot must not move":

Motion::disable();   // legs and arms
Motion::enable();    // re-attaches arms only if this build has them
bool any = Motion::isEnabled();

Use Motion for safety and bench work; use Legs::disable() or Arms::relax() when you deliberately want one group off.

Understanding steps, period and amplitude

Parameter Unit Meaning
steps / cycles count, fractional allowed How many times the movement repeats. 0.5 is half a cycle
periodMs milliseconds Duration of one cycle. Higher is slower
amplitude degrees How large the movement is

The total duration of a call is roughly steps * periodMs. Legs::walkForward(4, 1000) takes about four seconds -- during which your sketch does nothing else.

Movement blocks

Every movement call in this version returns only when the motion has finished. While walking, Otto cannot read a sensor or respond to Bluetooth.

Design around it by moving in short bursts and checking sensors in between:

void loop() {
  if (Eyes::closerThanCm(20)) {
    Legs::walkBackward(1);       // one step, then look again
    Legs::turnLeft(1);
  } else {
    Legs::walkForward(1);
  }
}

A non-blocking engine -- startWalkingForward(), isMoving(), stop() -- is the headline item on the Roadmap. The current names were chosen so it can be added without breaking any existing sketch.

Going lower: the LegServos module

The LegServos module is the same functionality with hardware-truth names and explicit direction arguments, where 1 is forward or left and -1 is backward or right:

LegServos::walk(2, 1000, 1);
LegServos::moonwalk(3, 900, 25, -1);

Prefer the facade in sketches. Reach for the module when you are writing a generic routine that computes its own direction:

int dir = obstacleOnLeft ? -1 : 1;
LegServos::turn(1, 2000, dir);

Calibration lives here too -- see Calibration.

Clone this wiki locally