Lili's Workshop
Robot no. 1 · Balance mission

The Balancer

Build a robot with Lili that keeps a ping-pong ball balanced on a rail, all by itself.

Difficulty★★☆☆
Time3 afternoons
Budget≈ €45
You'll learnSensor, motor, code

How does it work?

First we understand, then we build. That's the workshop rule!

Lili waving
Hi there!

I'm Lili! Have you ever tried to balance a ball on a ruler? As soon as it tilts a little, the ball rolls off. Our robot will do what your hands do without thinking: watch the ball and tilt the ruler just the right amount.

The eyes

The ultrasonic sensor

It shouts a very high sound you can't hear and listens for the echo, like a bat. That's how it knows where the ball is.

The brain

The Arduino board

A tiny computer. It reads what the eyes see and decides how much to tilt the rail.

The muscle

The servo motor

A motor that turns to the exact angle you ask for. It pushes the end of the rail up or down.

The playground

The rail

Two wooden dowels the ball rolls on. It moves like a seesaw, around a hinge.

The eyes look → the brain thinks → the muscle moves… and again, 25 times a second!

Lili explaining with a tablet
Let me explain

The brain's secret is a 3-ingredient recipe called PID. P for "Push": the further the ball is from the middle, the more we tilt. D for "Dampen": if the ball comes in fast, we brake before it overshoots. I for "Insist": if the ball always stops a little off, we correct it bit by bit.

Play with the robot's brain

The force that brings the ball back to the middle.
The brake that stops the ball from overshooting.

Try with D at zero: the ball keeps swinging back and forth. Now raise D little by little…

Shopping list

Tick each thing once it's on your table. Lili remembers your ticks.

0 / 0 found

Electronics

    Wood and hardware

      Lili with her arms crossed
      With a grown-up

      The saw, the drill and the hot glue gun are used with a grown-up, never alone. I ask for help with those too!

      Tools to get ready: ruler, pencil, Phillips screwdriver, small saw, hot glue gun, and a computer with the free Arduino IDE software. Prices are rough guides. The Amazon buttons open a search: pick a well-rated seller and compare with the "Check" line.

      Building, step by step

      One step at a time. Click "Done!" when you've finished.

      0 / 0 steps
      1

      Set up your workshop

      10 minutes
      1. Clear a big table and protect it with an old piece of cardboard.
      2. Lay out every part from the shopping list in front of you.
      3. Put the small parts (screws, screw eye, paper clip) in a bowl so they don't get lost.
      4. Ask a grown-up to install the Arduino IDE software on the computer.
      Tip

      Take a photo of all your parts before you start. It will be the first page of your robot-builder's logbook!

      2

      The base and the post

      20 minutes · with a grown-up for the saw
      BoardSquare battenWood glueSaw
      1. Cut a 12 cm piece from the batten: that's the post.
      2. Cut a second piece of 6 cm: that will hold the motor.
      3. Glue the post standing up, 3 cm from the left edge of the board, right in the middle of its width.
      4. Let it dry for 30 minutes. Meanwhile, move on to step 3!
      What do you think?

      Why does the post need to be perfectly straight? Hint: if the rail already tilts at the start, who will have to work harder?

      3

      The ball rail

      20 minutes
      40 cm strip2 round dowelsWood glue1 ball
      1. Lay the two dowels on the strip, nicely parallel, about 2.5 cm apart.
      2. Test with a ball: it must roll on the dowels without touching the strip.
      3. When the gap is right, glue the dowels and hold them with tape while they dry.
      4. Glue a small piece of cardboard on the right end: it's a stopper so the ball doesn't fly off.
      Tip

      Draw two pencil lines on the strip before gluing. The dowels will stay nice and straight.

      4

      The hinge

      15 minutes
      Hinge + screwsScrewdriver
      1. Screw one half of the hinge on top of the post.
      2. Screw the other half under the rail, about 2 cm from its left end.
      3. Lift the right end of the rail with your hand: it should go up and down easily, like a seesaw.
      Careful

      If the hinge rubs or squeaks, the motor will struggle. Loosen the screws just a tiny bit.

      5

      Wiring

      20 minutes · USB cable unplugged!

      Wires are like roads: each colour goes to one exact place. Use the breadboard so the motor and the sensor share the 5V and the GND.

      Arduino Uno 5VGND pin 9pin 8pin 7 Breadboard HC-SR04 sensor VCCTrigEchoGND Servo motor redbrownorange
      PartWireGoes to the Arduino
      Servo motorred5V (through the breadboard)
      Servo motorbrownGND (through the breadboard)
      Servo motororangepin 9
      SensorVCC5V (through the breadboard)
      SensorGNDGND (through the breadboard)
      SensorTrigpin 8
      SensorEchopin 7
      Golden rule

      We plug and unplug wires only with the USB cable unplugged. And we check twice before plugging it back in.

      6

      First program: the motor goes straight

      15 minutes · on the computer
      1. Connect the Arduino to the computer with the USB cable.
      2. In Arduino IDE, choose Tools → Board → Arduino Uno and the right Port.
      3. Copy this little program, then click the Upload arrow.
      motor_test.ino
      #include <Servo.h>
      
      Servo motor;
      
      void setup() {
        motor.attach(9);    // the orange wire is on pin 9
        motor.write(90);    // 90 degrees = the middle position
      }
      
      void loop() {
        // nothing: the motor stays in the middle
      }
      1. The motor moves a little, then stops: it's now exactly in the middle.
      2. Push the little plastic arm (the horn) onto the shaft, perfectly level.
      Why code first?

      If you fix the arm first, you don't know where the motor's "middle" is. The rail might never be flat.

      7

      The motor and the rod

      25 minutes
      Servo motor6 cm blockPaper clipScrew eyeHot glue
      1. Screw the screw eye under the rail, 35 cm from the hinge.
      2. Fix the servo onto its wooden block (hot glue or cable ties), shaft facing forward.
      3. Place the block on the board, right under the screw eye. Don't glue it yet!
      4. Unfold the paper clip into a straight rod and bend a small hook at each end with pliers.
      5. Hook one end into the outer hole of the horn, the other into the screw eye.
      6. Slide the block until the rail is perfectly flat. Check with a ball: it must not roll. Now you can glue the block.
      Stuck?

      If the rail is too high or too low, change the length of the rod instead of forcing the motor.

      8

      The robot's eyes

      20 minutes
      1. Glue the sensor at the left end of the rail, on the hinge side, its two "eyes" facing along the rail.
      2. The eyes should be at the height of the middle of the ball.
      3. Upload this program, then open Tools → Serial Monitor.
      sensor_test.ino
      const int PIN_TRIG = 8;
      const int PIN_ECHO = 7;
      
      void setup() {
        Serial.begin(9600);
        pinMode(PIN_TRIG, OUTPUT);
        pinMode(PIN_ECHO, INPUT);
      }
      
      void loop() {
        digitalWrite(PIN_TRIG, LOW);  delayMicroseconds(2);
        digitalWrite(PIN_TRIG, HIGH); delayMicroseconds(10);  // the shout!
        digitalWrite(PIN_TRIG, LOW);
        long duration = pulseIn(PIN_ECHO, HIGH, 25000);  // listen for the echo
        float cm = duration * 0.0343 / 2;               // there and back again
        Serial.print("Ball at ");
        Serial.print(cm);
        Serial.println(" cm");
        delay(100);
      }
      1. Roll the ball gently with your finger. Do the numbers change? Well done, your robot can see!
      Did you know?

      Sound travels at 343 metres per second. We divide by 2 because the sound goes to the ball and comes back.

      9

      The Balancer's big program

      20 minutes

      Here's the complete brain. Read the green comments: they explain every line. Upload it, put the ball on the rail and watch!

      balancer.ino
      #include <Servo.h>
      
      // ----- The wiring -----
      const int PIN_SERVO = 9;
      const int PIN_TRIG  = 8;
      const int PIN_ECHO  = 7;
      
      // ----- Lili's settings -----
      float TARGET     = 18.0;  // where the ball should stop (cm from the sensor)
      int   FLAT_ANGLE = 90;    // motor angle when the rail is flat
      int   DIRECTION  = 1;     // set to -1 if the ball runs away instead of coming back
      float Kp = 2.0;   // P: Push
      float Ki = 0.02;  // I: Insist
      float Kd = 0.8;   // D: Dampen
      
      Servo motor;
      float distance = TARGET;
      float lastError = 0;
      float sum = 0;
      unsigned long lastTime = 0;
      
      float measure() {
        digitalWrite(PIN_TRIG, LOW);  delayMicroseconds(2);
        digitalWrite(PIN_TRIG, HIGH); delayMicroseconds(10);
        digitalWrite(PIN_TRIG, LOW);
        long duration = pulseIn(PIN_ECHO, HIGH, 25000);
        if (duration == 0) return -1;           // no echo: ignore it
        return duration * 0.0343 / 2;
      }
      
      void setup() {
        Serial.begin(9600);
        pinMode(PIN_TRIG, OUTPUT);
        pinMode(PIN_ECHO, INPUT);
        motor.attach(PIN_SERVO);
        motor.write(FLAT_ANGLE);
        delay(1000);
        lastTime = millis();
      }
      
      void loop() {
        // 1. The eyes look
        float d = measure();
        if (d > 2 && d < 40) {
          distance = 0.7 * distance + 0.3 * d;   // smooth out jumpy readings
        }
      
        // 2. The brain thinks
        unsigned long now = millis();
        float dt = (now - lastTime) / 1000.0;
        lastTime = now;
      
        float error = distance - TARGET;                      // how far from the goal?
        sum = constrain(sum + error * dt, -50, 50);           // I
        float speed = (error - lastError) / dt;                // D
        lastError = error;
      
        float correction = Kp * error + Ki * sum + Kd * speed;
        correction = constrain(correction, -30, 30);         // no more than 30 degrees
      
        // 3. The muscle moves
        motor.write(FLAT_ANGLE + DIRECTION * correction);
      
        // For the Serial Plotter: the ball and the target
        Serial.print(distance); Serial.print(" "); Serial.println(TARGET);
        delay(40);
      }
      Ball running away?

      Don't panic, that's normal the first time! The motor may be mounted the other way round. Change DIRECTION = 1 to DIRECTION = -1 and upload again.

      10

      Tuning, like a real engineer

      As long as it takes!

      Open Tools → Serial Plotter: you'll see two lines, the ball and the target. Your goal: get the ball's line to meet the target and stay there. Change only one number at a time, upload, watch.

      1. P only

      Set Ki = 0 and Kd = 0. Raise Kp until the ball swings back and forth around the target.

      2. Add D

      Raise Kd little by little. The swinging calms down. Too much D? The motor shakes.

      3. A pinch of I

      If the ball always stops a little off, raise Ki very gently (0.01, 0.02…).

      Logbook

      Write down every try in a notebook: "Kp = 2, Kd = 0.8 → the ball swings 3 times". That's exactly what engineers do!

      Motor shaking and the Arduino restarting?

      The motor is asking for too much power from the USB cable. Ask a grown-up to add a 4×AA battery holder for the motor, with its "minus" connected to the Arduino's GND.

      Lili raising her arms, mission accomplished
      Mission accomplished

      Your Balancer holds the ball!

      You've built a real feedback control system, the same idea used by drones, walking robots and rockets that land standing up.

      • Challenge 1: change TARGET so the ball stops at 10 cm, then at 25 cm.
      • Challenge 2: give the ball a flick. How long does it take to come back?
      • Challenge 3: try a heavier ball. Do you need to change the settings?
      Well done!