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::center();

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.

Center and home

center() returns all four servos to the rest position -- 90 degrees, the same reference pose you calibrate against. It is worth calling before and after a sequence, so every behaviour starts from the same stance:

Legs::center();
Legs::walkForward(3);
Legs::center();

Legs::home() is an alias for center(); use whichever word fits your sketch. Arms has the same pair.

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::center();
Legs::upDown(2, 800, 25);
Legs::moonwalkLeft(3);
Legs::moonwalkRight(3);
Legs::jitter(2, 400, 30);
Legs::center();

Gestures

A gesture is a whole canned performance -- leg movement, a face on the matrix, and a sound -- played by one call:

Gestures::play(Gesture::Victory);

Thirteen are built in, each blocking for roughly 0.5 to 3 seconds and self-resetting at the end. Because they move the legs, they honour Legs::disable() and Motion::disable() like any other movement call.

See Gestures for the full story, and the Icon, Sound and Gesture Reference for what each one does on the robot.

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 the legs

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.

This switch covers the legs alone. For "the robot must not move" -- legs and arms, the one call for safety and bench work -- see Motion.

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