Arduino Learning Studiorobotics pathway

R14-U2 · usually age 14 · Robotics Engineers

Feedback Control

Can we keep the robot moving straight?

Pilot unit plan · 5 sessions · not yet classroom-validated

Build: Closed-loop wheel-speed controller

Closing the loop: the rover measures each wheel's speed from its encoder and corrects its motor command to hold a target. Proportional control first (correction = Kp × error), with the target and error in cm/s, tuned by a written procedure from the learners' own floor speed table, clamped to the floor ceiling, run inside the rover's DRIVE state, and compared with open-loop runs for repeatability. Integral and derivative are named as later ideas.

  • Sense
  • Decide
  • Act

Who it is for

Age is a starting point, never a limit. A learner who can show what this unit starts from can begin here at any age.

How they learn
By reading and changing real Arduino sketches, predicting, testing in a model, then building and testing the real circuit.
The adult's role
An adult checks every circuit and anything that moves before it is powered.
Session
75–90 minutes
Hardware
Arduino Uno R3 or compatible (5 V). The adult checks the power circuit and the motor driver. Motors never run from a pin; share GND between supplies.

Starts from

Builds, and what it is the input for

In the studio today

The labs run a model of each sketch in the browser. They prepare the real build; they never count as a working circuit.

Sessions

  1. Session 1 · 90 min

    How straight is open loop?

    Open loop: one analogWrite() value to both wheels and no correction. If R14-U1's table shows the two wheels at different speeds for the same value, the rover curves, and how much can change from run to run. A baseline for the unit: the sideways drift after 2 m and its spread over five runs. Straightness is measured in cm: the drift on the floor, and in the log each wheel's distance (its counts × its own cm per count), never the raw count difference, since the two wheels' cm per count can differ.

    In the studio

    No studio lab: this session is off-screen.

    Hands-on

    Lay a 2 m tape line on the floor with a start cross. Start from your R14-U1 session 5 sketch, driving both wheels at one value until the average distance reaches 200 cm, with the stall rule in the drive state, and logging both counts and both distances every 100 ms. Upload, open the Serial Monitor before the motor battery goes on (opening it restarts the UNO), lift the rover, wheels in the air, and check that both wheels turn forward. Then run five trials on the floor, never above 160 of 255, the front-centre mark on the start cross each time: measure how far the mark ends from the line (left or right, in cm) and note the final left − right distance difference in cm.

    Starting code: The learner's own sketch from R14-U1 session 5, set to drive 200 cm, with its stall rule.

    Pins

    D2
    left wheel encoder SIG (photo interrupter breakout)
    D3
    right wheel encoder SIG (photo interrupter breakout)
    D4
    driver AIN1 (left motor)
    D5
    driver PWMA (left motor)
    D6
    driver PWMB (right motor)
    D7
    driver AIN2 (left motor)
    D8
    driver STBY moved from D3
    D9
    HC-SR04 Trig (wired, not read; kept OUTPUT and LOW)
    D10
    HC-SR04 Echo (wired, not read in these sketches)
    D11
    driver BIN2 (right motor)
    D12
    driver BIN1 (right motor)
    A0
    STOP button (other side to GND) moved from D2

    Evidence to collect

    An open-loop table: five runs, the sideways drift at 2 m (cm, left or right), the final left − right distance difference (cm), and the spread of the drift (largest minus smallest).

    Predict
    Which way will the rover curve, judging from your R14-U1 speed table?
    Debug
    If it curves a different way on each run, check the castor and the floor before the code: the same input should give a similar run.
    Reflect
    Would a fixed change to one wheel's value fix the curve for good? Why or why not?

    ⚠ Adult checks before power-on: Before every upload: setup() never sets pin 2 or 3 as OUTPUT (the encoders drive those pins). The motor battery reaches the driver's VM only, through its power-off switch; the board's 5V goes to the driver's VCC only; every GND is joined. Lifted for the first run of every new sketch; then the first run on the floor at the lowest value that starts both wheels, never above 160 of 255; later runs stay within that ceiling, on a clear floor with the power-off switch in reach. The stall rule: in every driving state, go to STOPPED if a wheel's count is unchanged for 5 samples while its value is above its measured start value, or if the segment runs over twice its measured time. The USB cable is held clear of the wheels by the adult. Fingers and hair clear of wheels and discs while the motor battery is on. Lift the rover (wheels in the air) before switching the motor battery back on: the sketch keeps running on USB, so the wheels take its last command at once.

    Works towards: Feedback control

  2. Session 2 · 80 min

    What is feedback?

    The loop: a target speed in cm/s, a measurement (the encoder: the counts since the last sample × cm per count ÷ the interval in seconds), the error (target − measured, in cm/s), a correction to the motor command, then measure again. Open loop sets a command and hopes; closed loop checks and corrects on every sample. Proportional control: value = base + Kp × error, clamped to 0–160 with constrain(). Because the target and the error are per second, a different sample interval later changes how noisy the speed is, not what Kp means. Where it lives: in the rover's DRIVE state, on a millis() timer; BRAKE and STOPPED set both values to 0 and the controller does nothing. The studio's labs still put STBY on D3 and STOP on D2: never paste a lab's pin lines into the rover's sketch; take every pin from the plan's pin table.

    In the studio

    Hands-on

    In Sense, decide, act, follow one pass of loop(): which lines sense, which decide, which act, and how often does it repeat? On paper, draw the speed loop for one wheel as boxes and arrows: target, error, Kp × error, base + correction, the clamp, the motor, the encoder and back to the error. Then play it at the table with your own R14-U1 speed table: one learner is the wheel (reads the speed in cm/s the table gives for a value), one is the controller (works out the next value), for six samples. Use Kp₁ from the tuning procedure (from your floor table: the change in value between two rows ÷ their change in speed in cm/s, halved), then half and double it. Nothing is powered in this session.

    Evidence to collect

    The loop drawing with every arrow labelled, and six-sample tables for three values of Kp, with a sentence on what too small and too large a Kp did on paper.

    Predict
    With double the Kp, will the paper wheel reach the target sooner, or swing past it?
    Debug
    If the paper wheel moves away from the target, check the sign: a wheel that is too slow must get a larger value.
    Reflect
    What does the controller know on every sample that the open-loop sketch never did?

    Works towards: Feedback control

  3. Session 3 · 90 min

    Can one wheel hold its speed?

    A proportional speed controller on one wheel, tuned by a procedure, never by a guessed number. (1) Kp = 0: open loop; note the error and the noise: how far the logged speed moves, in counts per sample, over 10 samples of steady running. (2) Kp₁ from your speed table: the change in value between two rows ÷ their change in speed in cm/s, halved. (3) Double Kp each run, three runs each, until the logged speed swings or the value jumps between 0 and 160. A swing is a regular back-and-forth more than 2 counts per sample beyond the step-1 noise that does not die out within 10 samples. (4) Keep the largest Kp that settled without swinging. (5) Check it on the floor: if it swings there, halve it and check again. Integral (I) and derivative (D) are named here and built later: I adds up the error over time to remove a gap that stays; D reacts to how fast the error changes, to calm the swings.

    In the studio

    No studio lab: this session is off-screen.

    Hands-on

    Start from your session 1 sketch. Choose the target: a speed in cm/s the slower wheel reached on the floor in your R14-U1 speed table at a value below 160, so the controller has room to push up (its output is clamped at 160, and a wheel already there cannot speed up); that value is the base. Write the controller for the left wheel only: every 100 ms copy the counts with interrupts off, work out the speed and the error in cm/s, and set the value to constrain(base + Kp × error, 0, 160); the right wheel stays at its base value. Keep the stall rule in the drive state. Print the time, target, speed, counts in the sample and value on one line. Upload, open the Serial Monitor before the motor battery goes on (opening it restarts the UNO), lift the rover, wheels in the air, and follow the procedure to step 4. Then on the floor, never above 160 of 255, do step 5, and drive 150 cm from a smooth floor onto a mat with Kp = 0 and with your Kp, and compare the logged speed after the change of surface.

    Starting code: The learner's session 1 sketch, with a speed controller for the left wheel only.

    Pins

    D2
    left wheel encoder SIG (photo interrupter breakout)
    D3
    right wheel encoder SIG (photo interrupter breakout)
    D4
    driver AIN1 (left motor)
    D5
    driver PWMA (left motor)
    D6
    driver PWMB (right motor)
    D7
    driver AIN2 (left motor)
    D8
    driver STBY moved from D3
    D9
    HC-SR04 Trig (wired, not read; kept OUTPUT and LOW)
    D10
    HC-SR04 Echo (wired, not read in these sketches)
    D11
    driver BIN2 (right motor)
    D12
    driver BIN1 (right motor)
    A0
    STOP button (other side to GND) moved from D2

    Evidence to collect

    A tuning table: the step-1 noise, each Kp tried (and how it was worked out), three runs each, the error after it settled and whether it swung, lifted and on the floor; the chosen Kp; and a before/after from the mat: the speed after the change of surface with Kp = 0 and with the chosen Kp.

    Predict
    At which Kp will the logged speed start to swing above and below the target?
    Debug
    If the speed runs away from the target, the error's sign is reversed: target − measured, not measured − target.
    Reflect
    After it settled, was the speed exactly on target? What would the integral term do about the gap?

    ⚠ Adult checks before power-on: Before every upload: setup() never sets pin 2 or 3 as OUTPUT (the encoders drive those pins). The motor battery reaches the driver's VM only, through its power-off switch; the board's 5V goes to the driver's VCC only; every GND is joined. Every value the controller can send passes through constrain(…, 0, 160): check that line before the upload. Lifted for the first run of every new sketch; on the floor never above 160 of 255, on a clear floor with the power-off switch in reach. Every tuning run is lifted, wheels in the air. The stall rule: in every driving state, go to STOPPED if a wheel's count is unchanged for 5 samples while its value is above its measured start value, or if the segment runs over twice its measured time. The USB cable is held clear of the wheels by the adult. Fingers and hair clear of wheels and discs while the motor battery is on. Lift the rover (wheels in the air) before switching the motor battery back on: the sketch keeps running on USB, so the wheels take its last command at once.

    Works towards: Feedback control

  4. Session 4 · 90 min

    Can both wheels keep it straight?

    Two controllers, one per wheel, with the same target in cm/s, each wheel's speed worked out with its own cm per count, so each wheel is held to that speed whatever its motor does at a given value. They run only in DRIVE, a state of the rover's controller; BRAKE and STOPPED set both values to 0, STOP on A0 is checked first on every pass, and the stall rule can end DRIVE. The log adds the left − right distance difference in cm (each wheel's counts × its own cm per count): if it keeps growing while both speeds sit near the target, the small leftover errors are adding up, which is what the integral term would remove later.

    In the studio

    No studio lab: this session is off-screen.

    Hands-on

    Start from your session 3 sketch and give the right wheel its own controller, with the same target and a Kp found for it by the same procedure (lifted, a few runs). Put both controllers in the DRIVE case of your state machine with STOP checked first, with the stall rule in DRIVE, and print the time, both speeds, both values and the distance difference. Upload and open the Serial Monitor before the motor battery goes on (opening it restarts the UNO). Test the stall rule safely first: motor battery off, on USB only, start the drive: the counts stay at 0, so the rule must go to STOPPED within 5 samples, and the Serial Monitor must show it. Then lift the rover, wheels in the air, switch the motor battery on and test every state: DRIVE, BRAKE when 200 cm is reached, STOPPED when STOP is pressed. Then on the 2 m line, never above 160 of 255, run it three times and measure the drift.

    Starting code: The learner's session 3 sketch, with a second controller and both inside the DRIVE state.

    Pins

    D2
    left wheel encoder SIG (photo interrupter breakout)
    D3
    right wheel encoder SIG (photo interrupter breakout)
    D4
    driver AIN1 (left motor)
    D5
    driver PWMA (left motor)
    D6
    driver PWMB (right motor)
    D7
    driver AIN2 (left motor)
    D8
    driver STBY moved from D3
    D9
    HC-SR04 Trig (wired, not read; kept OUTPUT and LOW)
    D10
    HC-SR04 Echo (wired, not read in these sketches)
    D11
    driver BIN2 (right motor)
    D12
    driver BIN1 (right motor)
    A0
    STOP button (other side to GND) moved from D2

    Evidence to collect

    A transition table (state, input, next state, STOP pressed in every state, and the stall test's STOPPED), three runs' drift on the 2 m line, and a log extract with both speeds near the target and the distance difference.

    Predict
    Will the drift be smaller than in session 1's open-loop runs?
    Debug
    If one wheel's value sits at 0 or 160 for many samples, its target is out of reach: lower the target, not the clamp.
    Reflect
    What does your distance-difference column say the rover is still doing wrong?

    ⚠ Adult checks before power-on: Before every upload: setup() never sets pin 2 or 3 as OUTPUT (the encoders drive those pins). The motor battery reaches the driver's VM only, through its power-off switch; the board's 5V goes to the driver's VCC only; every GND is joined. Every value the controller can send passes through constrain(…, 0, 160): check that line before the upload. Lifted for the first run of every new sketch; on the floor never above 160 of 255, on a clear floor with the power-off switch in reach. The stall rule: in every driving state, go to STOPPED if a wheel's count is unchanged for 5 samples while its value is above its measured start value, or if the segment runs over twice its measured time. The USB cable is held clear of the wheels by the adult. Fingers and hair clear of wheels and discs while the motor battery is on. Lift the rover (wheels in the air) before switching the motor battery back on: the sketch keeps running on USB, so the wheels take its last command at once.

    Works towards: Feedback control

  5. Session 5 · 90 min

    Is closed loop more repeatable?

    A fair comparison: the same start cross, line, distance, surface and battery check for both, changing only the controller, and the two alternated, so a battery running down or a floor getting dusty affects both alike. Repeatability is the spread of the drift over five runs; a rover can be repeatable and still wrong, so the mean drift is reported too.

    In the studio

    No studio lab: this session is off-screen.

    Hands-on

    Start from your session 4 sketch and do not change it during the trials; save a copy under a new name with Kp = 0 for both wheels (each wheel at its base value). Measure the motor battery on DC volts at the breadboard rails it feeds: below 5.0 V, replace the cells before any run (the driver's 1.0 A rating needs VM≥5V; a run-down alkaline pack also falls below 5 V). Open the Serial Monitor before the motor battery goes on (opening it restarts the UNO). Run five closed-loop trials and five open-loop trials with the Kp = 0 copy, in the same session, alternating them (closed, open, closed, open, …), logged, on the 2 m line, never above 160 of 255; both copies keep the stall rule. Measure the drift each time.

    Starting code: The learner's session 4 sketch, unchanged during the trials, and a copy saved with Kp = 0.

    Pins

    D2
    left wheel encoder SIG (photo interrupter breakout)
    D3
    right wheel encoder SIG (photo interrupter breakout)
    D4
    driver AIN1 (left motor)
    D5
    driver PWMA (left motor)
    D6
    driver PWMB (right motor)
    D7
    driver AIN2 (left motor)
    D8
    driver STBY moved from D3
    D9
    HC-SR04 Trig (wired, not read; kept OUTPUT and LOW)
    D10
    HC-SR04 Echo (wired, not read in these sketches)
    D11
    driver BIN2 (right motor)
    D12
    driver BIN1 (right motor)
    A0
    STOP button (other side to GND) moved from D2

    Evidence to collect

    The unit's evidence: compare repeatability with open-loop control. A table of five closed-loop and five open-loop runs from the same start, in the order run (drift at 2 m, final distance difference in cm), the mean and spread of each, the battery readings, and a conclusion saying which was more repeatable and by how many cm, or that the data cannot tell.

    Predict
    Predict the spread of the drift with and without the controller.
    Debug
    If the closed-loop runs are not better, read the log: are the values pinned at 0 or 160, or is a wheel slipping?
    Reflect
    Which mattered more for repeatability: the controller, the floor or the battery?

    ⚠ Adult checks before power-on: Before every upload: setup() never sets pin 2 or 3 as OUTPUT (the encoders drive those pins). The motor battery reaches the driver's VM only, through its power-off switch; the board's 5V goes to the driver's VCC only; every GND is joined. For the reading: red lead in the V/Ω socket, never 10A; probes go on breadboard rows or rails, not at the header pins. The battery reads at least 5.0 V before the trials. Every value the controller can send passes through constrain(…, 0, 160): check that line before the upload. Lifted for the first run of every new sketch; on the floor never above 160 of 255, on a clear floor with the power-off switch in reach. The stall rule: in every driving state, go to STOPPED if a wheel's count is unchanged for 5 samples while its value is above its measured start value, or if the segment runs over twice its measured time. The USB cable is held clear of the wheels by the adult. Fingers and hair clear of wheels and discs while the motor battery is on. Lift the rover (wheels in the air) before switching the motor battery back on: the sketch keeps running on USB, so the wheels take its last command at once.

    Works towards: Feedback control

Materials

  • The encoder rover from R14-U1 (Uno, TB6612FNG, two gear motors, two photo interrupter encoders; motor battery: 4 × AA alkaline cells (1.5 V each, about 6 V fresh) in a holder whose on/off switch is the power-off switch)
  • Masking tape for a 2 m line and a start cross, a tape measure, a mat or rug for a change of surface
  • A digital multimeter
  • A computer with the Arduino IDE and a long USB cable for the tether

⚠ Safety before any session

  • Motors run from their own battery through the driver, never from a pin; every GND is joined.
  • To rewire: switch off and disconnect the motor battery first, then unplug USB. Never move a wire while powered.
  • Wheels lifted for the first run of every new sketch and for every tuning run; then on the floor never above 160 of 255.
  • Every controller's output passes through constrain(…, 0, 160): no gain can drive a wheel above the floor ceiling.
  • Lift the rover (wheels in the air) before switching the motor battery back on: the sketch keeps running on USB, so the wheels take its last command at once.
  • The power-off switch on the motor battery is the stop that always works; STOP on A0 is extra. Test both before every floor run.
  • The stall rule: in every driving state, go to STOPPED if a wheel's count is unchanged for 5 samples while its value is above its measured start value, or if the segment runs over twice its measured time.
  • Fingers and hair clear of wheels and discs while the motor battery is on.
  • The USB cable is held clear of the wheels by the adult.
  • Motor battery: AA alkaline cells only; no NiMH, Li-ion, LiPo, RC packs or 18650 cells.
  • If anything gets warm: switch off or unplug at the holder, don't touch it, tell the adult.

Notes for the adult

  • Introductory control: proportional only. Integral and derivative are named so the words are familiar, not built; there are no gains in this plan, only a procedure that works them out from the learners' own speed table.
  • Ask for the loop drawing before the code, and for the sign of the error before the first run: most first controllers push the wrong way.
  • A swinging wheel is the procedure working, not a failure: it shows where Kp is too large. Judge a swing against the step-1 noise, never by eye alone, and re-check the chosen Kp on the floor: a wheel under load can swing where a lifted one did not.
  • Speeds, targets and errors are in cm/s, each wheel with its own cm per count, so the two wheels are held to the same real speed and a later change of sample interval does not change what Kp means.
  • The studio's labs still put STBY on D3 and STOP on D2: never paste a lab's pin lines into the rover's sketch; take every pin from the plan's pin table.
  • The stall rule stays in every driving state: a controller pushes a wheel whose counts have stopped up to the clamp, so a loose SIG wire would otherwise mean a run at 160.
  • Each session lists a line to predict before power-on, a first check when it goes wrong, and a question to reflect on before tidying up.
  • Before the first upload, test an upload on each computer (Blink, with its own board and cable), so the session starts on time.
  • Learners who are ready can start here at any age once they can measure travel with encoders (R14-U1) and program states (R13-U3).
  • No studio lab models a controller yet; the Sense, decide, act lab is watched only, for the loop and the states. The rover's logs and the tape measure are the evidence.

Planned studio features

Not built yet. The unit runs without them.

  • A wheel-speed P-controller lab: a modelled wheel with a target speed, Kp as a code setting and a change of surface as a simulated input, with the logged speed drawn as it runs.
  • A tuning worksheet: each Kp tried, how it was worked out, and the settled error, kept in the browser only.

Sources

The facts this plan relies on, in each source's own words.