CITCODING ACADEMYROBOT MISSIONS · PYTHON & DATATello lessons ↗
GROUND ROBOT · 12 LESSONS

Python with
RoboMaster S1

Write a plan, trace each step, then test a short ground mission in RoboMaster Lab Python. Use observations to explain what the code can and cannot prove.

A route you can explore

Point or tap a waypoint. You can also focus the board and use the arrow keys. Trace the same ideas in the lessons.

Concept animation · no robot connection or measured results.

01Predict

Trace what your code will do.

02Build

Change one requirement.

03Observe

Separate commands from measurements.

04Explain

Show why the result makes sense.

Before the robot moves

Use the RoboMaster app → Lab → Python. Paste a complete S1 program, including def start(). These examples use the S1 controllers; the EP desktop SDK is not an S1 substitute.

Start on paper or with a dry-run log. A tutor checks the actual robot and marked area before any physical movement. The code was checked in software; these materials do not claim a hardware flight or classroom test.

Laptop setup and data work
python3.12 -m venv .venv
# macOS / Linux
source .venv/bin/activate
# Windows PowerShell: .venv\Scripts\Activate.ps1
python -m pip install -r requirements.txt

S1 motion code runs in the app’s Lab environment. Data analysis runs on the laptop. Keep invented, simulated and measured data labelled separately.

01One distance, two robots: variables and units

Convert a planned distance in metres into Tello centimetres and S1 metres, and explain why both commands represent the same target.

Start with a problem

Put two 30 cm tape marks on the floor. Show 30 and 0.30 on cards. Which value should each robot receive?

A named value lets us change the mission once. A unit conversion prevents the same number from requesting very different distances: Tello distance commands use centimetres; S1 distance commands use metres.

A bare number such as 30 hides its unit. Repeating that number in several commands makes a later route change easy to miss. A variable name documents the quantity, but a name alone does not convert it.

See the idea move

One distance, two units

Convert the unit before choosing the robot command.

  1. 01Plan

    The target distance is 0.30 m.

  2. 02Convert

    0.30 × 100 = 30 cm.

  3. 03Command

    0.30 m: the same planned distance.

Concept animation · no robot connection or measured results.

Read, predict, trace

Assignment stores a value under a name. Multiplying metres by 100 produces centimetres. int(round(...)) makes the whole-centimetre command explicit; the supplied distances have exact whole-centimetre targets.

  • variable: a name for a value
  • unit: what a number measures
  • conversion: express the same quantity in another unit
distance_m = 0.30
distance_cm = int(round(distance_m * 100))
print(distance_cm, distance_m)
Compare with the worked result
30 0.3
StepStateResult
distance_m = 0.30distance_m is 0.3 metresno output
multiply by 100; round; intdistance_cm is 30 centimetresno output
print both valuesthe quantities describe the same distance30 0.3

Practice before you run

These are formative practice prompts. A revealed or assisted answer stays practice; it is not a completed LMS lesson.

Before you begin

Predict the exact output before running it. Explain the result using variables, numbers, conversion and units.

print(20 / 100)
  1. 20
  2. 0.2
  3. 2000

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-01-diagnosis-v1 · 2026-11-02.2

Try with a hint

Predict the exact output before running it. Explain the result using variables, numbers, conversion and units.

length_m = 0.40
print(int(round(length_m * 100)))
  1. 0
  2. 400
  3. 40

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Hint

Write m or cm beside every value. Multiplying by 100 changes the numerical value, not the physical distance.

Task robot-hooks-01-guided-v1 · 2026-11-02.2

Try independently

Predict the exact output before running it. Explain the result using variables, numbers, conversion and units.

leg_m = 0.25
print(int(round(leg_m * 100)), leg_m)
  1. 25 0.25
  2. 0 25
  3. 25 25

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-01-independent-a-v1 · 2026-11-02.2

Change the context

Predict the exact output before running it. Explain the result using variables, numbers, conversion and units.

duration_ms = 250
print(duration_ms / 1000)
  1. 250
  2. 0.25
  3. 250000

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-01-transfer-v1 · 2026-11-02.2

Build your version

Complete command_units(distance_m). Valid inputs are 0.20 to 0.80 metres, in whole centimetres. Return (Tello centimetres, S1 metres). This function only prepares values; it does not connect to a robot.

def command_units(distance_m):
    return (None, None)

print(command_units(0.4))
Public checks for your code
assert command_units(0.2) == (20, 0.2)
assert command_units(0.4) == (40, 0.4)
assert command_units(0.8) == (80, 0.8)
  • Explain this goal with a concrete input and state trace: Convert a planned distance in metres into Tello centimetres and S1 metres, and explain why both commands represent the same target.
  • Modify the starter, pass the public tests, and add one meaningful new case with predicted and observed results.
  • Present a labelled artifact from the robot experiment or a declared simulation, with a limitation and an independent changed-context explanation.
RoboMaster S1 LAB

Observe the robot

Paste hardware/s1/01_units.py into a new Lab Python program. It moves 0.30 m out and back at 0.2 m/s. Change only distance_m after predicting both command values.

Open the complete S1 Lab program
# DJI RoboMaster S1 app > Lab > Python. No imports. Units: metres, m/s.
def start():
    chassis_ctrl.stop()
    robot_ctrl.set_mode(rm_define.robot_mode_free)
    chassis_ctrl.set_trans_speed(0.2)
    distance_m = 0.30
    chassis_ctrl.move_with_distance(0, distance_m)
    chassis_ctrl.move_with_distance(180, distance_m)
    chassis_ctrl.stop()

Change one thing and measure

Predict where each robot will finish. Measure the actual endpoint against the tape after it has stopped/landed. Record target and observed distance separately; equal requested distances do not promise equal accuracy.

Explain and transfer

Why would sending the unlabelled number 30 to both robots be a bad mission specification?

Convert a camera delay in milliseconds to seconds. Explain which unit belongs at the API boundary.

Save your code, prediction, actual result and one limitation. Label a command-log demonstration as simulated. Ask your tutor for a fresh review around day 2 and day 7, adjusted to your needs.

If your result is unexpected

Treating a number as if it carries a unit automatically

Write m or cm beside every value. Multiplying by 100 changes the numerical value, not the physical distance.

After a correction, explain the changed state and try the unopened independent variant. If it was exposed, use a tutor-authored changed-input task and give it a new ID; keep the original record.

02Should this mission start? if, comparisons and booleans

Implement and test a two-condition start rule, including values below, at and above the threshold.

Start with a problem

Show a mission with a clear lane but a low battery, then a charged robot with a blocked lane. Ask which one may start.

The same program needs different behaviour when its inputs change. Combining conditions makes the mission rule explicit and testable before motion.

Starting unconditionally ignores the inputs. Checking only one condition misses the other. A class battery threshold is a teaching policy, not a manufacturer guarantee.

See the idea move

Both checks must pass

An AND condition needs both inputs. These are classroom rules, not a safety certificate.

  1. 01First check

    Battery ≥ 40% (laptop example; not an S1 battery API).

  2. 02Area check

    A teacher confirms the marked area is clear.

  3. 03Both true

    The classroom AND rule evaluates to True.

  4. 04One false

    Keep the robot stopped; recheck the cause.

Concept animation · no robot connection or measured results.

Read, predict, trace

if chooses a branch. >= includes the boundary. A and B is True only when both are True. Use a 40% class preflight rule for Tello; classroom clearance still comes from the supervising person.

  • condition: a True/False test
  • boundary: the exact threshold
  • and: both tests must pass
battery = 40
clear = False
if battery >= 40 and clear:
    print("go")
else:
    print("stop")
Compare with the worked result
stop
StepStateResult
battery >= 4040 >= 40 is Trueno output
True and clearTrue and False is Falseelse selected
print in elsepermission refusedstop

Practice before you run

These are formative practice prompts. A revealed or assisted answer stays practice; it is not a completed LMS lesson.

Before you begin

Predict the exact output before running it. Explain the result using if/else, >= and and.

print(40 > 40)
  1. True
  2. 40
  3. False

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-02-diagnosis-v1 · 2026-11-02.2

Try with a hint

Predict the exact output before running it. Explain the result using if/else, >= and and.

battery = 41
clear = True
print(battery >= 40 and clear)
  1. True
  2. False
  3. 41

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Hint

Make a four-row True/False table. Test 39, 40 and 41 separately; a clear lane cannot repair a failed battery test.

Task robot-hooks-02-guided-v1 · 2026-11-02.2

Try independently

Predict the exact output before running it. Explain the result using if/else, >= and and.

battery = 39
print("go" if battery >= 40 and True else "stop")
  1. go
  2. stop
  3. 39

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-02-independent-a-v1 · 2026-11-02.2

Change the context

Predict the exact output before running it. Explain the result using if/else, >= and and.

print("enter" if 12 >= 12 and False else "wait")
  1. enter
  2. True
  3. wait

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-02-transfer-v1 · 2026-11-02.2

Build your version

Write permit(battery, clear). Return "go" only for a battery of at least 40 AND a clear lane; otherwise return "stop". Inputs here are a numeric percentage and a boolean.

def permit(battery, clear):
    return "stop"

print(permit(40, True))
Public checks for your code
assert permit(39, True) == "stop"
assert permit(40, True) == "go"
assert permit(41, False) == "stop"
assert permit(90, True) == "go"
  • Explain this goal with a concrete input and state trace: Implement and test a two-condition start rule, including values below, at and above the threshold.
  • Modify the starter, pass the public tests, and add one meaningful new case with predicted and observed results.
  • Present a labelled artifact from the robot experiment or a declared simulation, with a limitation and an independent changed-context explanation.
RoboMaster S1 LAB

Observe the robot

02_decisions.py remains stationary and changes its LED using a real stop-marker condition. A missing marker never authorizes motion. The printed battery example is a laptop exercise, not an S1 battery API.

Open the complete S1 Lab program
# Observe a genuine DJI stop marker. LED only; no movement permission.
def start():
    chassis_ctrl.stop()
    vision_ctrl.enable_detection(rm_define.vision_detection_marker)
    time.sleep(0.5)
    stop_seen = vision_ctrl.check_condition(rm_define.cond_recognized_marker_trans_stop)
    if stop_seen:
        led_ctrl.set_top_led(rm_define.armor_top_all, 255, 0, 0, rm_define.effect_always_on)
    else:
        led_ctrl.set_top_led(rm_define.armor_top_all, 0, 0, 255, rm_define.effect_always_on)
    vision_ctrl.disable_detection(rm_define.vision_detection_marker)
    chassis_ctrl.stop()

Change one thing and measure

Use the four permission-table combinations in the simulation. On hardware, observe one normal reading and an S1 stop-marker response without making the lane unsafe. Record which inputs were measured and which were supplied by a person.

Explain and transfer

Why can the same code choose a different branch without being rewritten?

Design a library door rule using age and an adult permission flag. Include the exact age boundary.

Save your code, prediction, actual result and one limitation. Label a command-log demonstration as simulated. Ask your tutor for a fresh review around day 2 and day 7, adjusted to your needs.

If your result is unexpected

Reading and as or, or excluding the equal boundary

Make a four-row True/False table. Test 39, 40 and 41 separately; a clear lane cannot repair a failed battery test.

After a correction, explain the changed state and try the unopened independent variant. If it was exposed, use a tutor-authored changed-input task and give it a new ID; keep the original record.

03Four patrol legs: for loops and range

Trace range(4) and put both move and turn inside the repeated body.

Start with a problem

Show a four-leg square patrol. Ask students to change every leg from 30 to 40 cm, then to predict what an indented turn does.

One loop body describes a repeated patrol step. Changing the count or one parameter changes the repeated behaviour consistently.

Four copied blocks can work, but editing three and missing the fourth changes the route. A loop repeats only the indented body; a turn after the loop happens once.

See the idea move

Four legs, four turns

Each leg is 0.30 m; each clockwise turn is 90°. A closed plan does not prove a closed real path.

  1. 01Leg 1

    Move, then turn clockwise.

  2. 02Leg 2

    Repeat the same two actions.

  3. 03Leg 3

    Count the iteration, not just the turns.

  4. 04Leg 4

    Finish the plan; measure any drift.

Concept animation · no robot connection or measured results.

Read, predict, trace

for visits each item in an iterable. range(4) provides 0, 1, 2, 3. Each iteration of a square patrol moves forward and turns 90 degrees; code after the loop runs once.

  • iteration: one pass through the body
  • range: integers with an excluded stop
  • indentation: which lines belong to the body
for leg in range(2):
    print("move", leg)
    print("turn")
print("done")
Compare with the worked result
move 0
turn
move 1
turn
done
StepStateResult
leg = 0first iterationmove 0, then turn
leg = 1second iterationmove 1, then turn
range exhaustedleave loopdone

Practice before you run

These are formative practice prompts. A revealed or assisted answer stays practice; it is not a completed LMS lesson.

Before you begin

Predict the exact output before running it. Explain the result using for, range, indentation and repeated actions.

print(list(range(3)))
  1. [0, 1, 2]
  2. [1, 2, 3]
  3. [0, 1, 2, 3]

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-03-diagnosis-v1 · 2026-11-02.2

Try with a hint

Predict the exact output before running it. Explain the result using for, range, indentation and repeated actions.

for leg in range(3):
    print("move")
print("land")
  1. move land move land move land
  2. move move move land
  3. move move land

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Hint

Draw one box around the indented body. Copy that whole box once for every integer in range.

Task robot-hooks-03-guided-v1 · 2026-11-02.2

Try independently

Predict the exact output before running it. Explain the result using for, range, indentation and repeated actions.

count = 0
for leg in range(4):
    count = count + 2
print(count)
  1. 4
  2. 10
  3. 8

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-03-independent-a-v1 · 2026-11-02.2

Change the context

Predict the exact output before running it. Explain the result using for, range, indentation and repeated actions.

for photo in range(2):
    print("save")
print("close")
  1. save save close
  2. save close save close
  3. save close

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-03-transfer-v1 · 2026-11-02.2

Build your version

Complete square_commands(sides). Return alternating "move" and "turn" strings, once per side. The function prepares a plan; the real square demo always uses four sides.

def square_commands(sides):
    commands = []
    # Repeat a move and a turn for each side.
    return commands

print(square_commands(4))
Public checks for your code
assert square_commands(0) == []
assert square_commands(1) == ["move", "turn"]
assert square_commands(4) == ["move", "turn"] * 4
  • Explain this goal with a concrete input and state trace: Trace range(4) and put both move and turn inside the repeated body.
  • Modify the starter, pass the public tests, and add one meaningful new case with predicted and observed results.
  • Present a labelled artifact from the robot experiment or a declared simulation, with a limitation and an independent changed-context explanation.
RoboMaster S1 LAB

Observe the robot

03_for_square.py performs the same logical pattern with 0.30 m legs. Both commands belong inside the for body; speed and distance use S1 units.

Open the complete S1 Lab program
def start():
    chassis_ctrl.stop()
    robot_ctrl.set_mode(rm_define.robot_mode_free)
    chassis_ctrl.set_trans_speed(0.2)
    chassis_ctrl.set_rotate_speed(45)
    for leg in range(4):
        chassis_ctrl.move_with_distance(0, 0.30)
        chassis_ctrl.rotate_with_degree(rm_define.clockwise, 90)
    chassis_ctrl.stop()

Change one thing and measure

Trace a paper square before running one physical square. Mark the predicted endpoint and heading; measure closure error after stopping. A correct loop cannot eliminate drift or wheel slip.

Explain and transfer

Which edit changes all four legs, and which indentation error would produce four moves but only one turn?

Plan five photograph-and-log actions, followed by one final upload. Explain why upload belongs outside the loop.

Save your code, prediction, actual result and one limitation. Label a command-log demonstration as simulated. Ask your tutor for a fresh review around day 2 and day 7, adjusted to your needs.

If your result is unexpected

Counting the stop value or repeating a line outside the loop

Draw one box around the indented body. Copy that whole box once for every integer in range.

After a correction, explain the changed state and try the unopened independent variant. If it was exposed, use a tutor-authored changed-input task and give it a new ID; keep the original record.

04Wait for evidence: while loops and fresh readings

Explain and implement both a success exit and an exhausted-budget exit, refreshing the input each pass.

Start with a problem

Hold back a marker, then reveal it at an unpredictable time. Ask how many checks the program should make.

The stopping point depends on incoming evidence rather than a fixed route length. A while condition expresses that dependency; a check budget prevents waiting forever.

A fixed for loop may keep checking after success. A while loop with an unchanged old reading cannot notice a new marker. The same behaviour can also be expressed with for and break; choose the form that makes the stop rule clearest.

See the idea move

A loop with an exit

Check for success and cap the number of attempts. A cached reading may be old.

  1. 01Read

    Read marker recognition while stationary.

  2. 02Test

    Does this observation meet the condition?

  3. 03Success exit

    Leave the loop as soon as the condition passes.

  4. 04Budget exit

    If no reading passes within 10 checks, stop and report it.

Concept animation · no robot connection or measured results.

Read, predict, trace

while checks its condition before each pass. Update progress and read new evidence inside the body. Stop on success or when the maximum checks are used. A sleep spaces samples; it is not a new sensor reading.

  • poll: ask for a new reading
  • stale: a previously captured reading
  • budget: the maximum checks allowed
readings = [False, False, True]
checks = 0
found = False
while not found and checks < 3:
    found = readings[checks]
    checks += 1
print(checks, found)
Compare with the worked result
3 True
StepStateResult
checks 0: read Falsefound False; checks becomes 1no output
checks 1: read Falsefound False; checks becomes 2no output
checks 2: read Truefound True; checks becomes 3; exit3 True

Practice before you run

These are formative practice prompts. A revealed or assisted answer stays practice; it is not a completed LMS lesson.

Before you begin

Predict the exact output before running it. Explain the result using while, state updates, break and bounded polling.

count = 0
while count < 2:
    count += 1
print(count)
  1. 0
  2. 2
  3. 3

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-04-diagnosis-v1 · 2026-11-02.2

Try with a hint

Predict the exact output before running it. Explain the result using while, state updates, break and bounded polling.

values = [False, True, False]
i = 0
found = False
while not found and i < 3:
    found = values[i]
    i += 1
print(i, found)
  1. 3 False
  2. 1 False
  3. 2 True

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Hint

Keep a table with check number, newly read value and next condition. Include a stream that never becomes ready.

Task robot-hooks-04-guided-v1 · 2026-11-02.2

Try independently

Predict the exact output before running it. Explain the result using while, state updates, break and bounded polling.

values = [False, False, False]
i = 0
found = False
while not found and i < 2:
    found = values[i]
    i += 1
print(i, found)
  1. 2 False
  2. 3 False
  3. 2 True

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-04-independent-a-v1 · 2026-11-02.2

Change the context

Predict the exact output before running it. Explain the result using while, state updates, break and bounded polling.

pages = ["busy", "ready", "ready"]
i = 0
while i < len(pages):
    state = pages[i]
    i += 1
    if state == "ready":
        break
print(i)
  1. 3
  2. 2
  3. 1

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-04-transfer-v1 · 2026-11-02.2

Build your version

Complete first_ready(readings, max_checks). Consume at most max_checks available booleans. Return (checks_used, found). Empty inputs and zero budget return (0, False). Recorded inputs simulate fresh polls; this is not an obstacle detector.

def first_ready(readings, max_checks):
    checks = 0
    found = False
    # Update both variables from the next reading.
    return checks, found

print(first_ready([False, True], 4))
Public checks for your code
assert first_ready([False, True, False], 3) == (2, True)
assert first_ready([False, False, True], 2) == (2, False)
assert first_ready([True], 0) == (0, False)
assert first_ready([], 4) == (0, False)
  • Explain this goal with a concrete input and state trace: Explain and implement both a success exit and an exhausted-budget exit, refreshing the input each pass.
  • Modify the starter, pass the public tests, and add one meaningful new case with predicted and observed results.
  • Present a labelled artifact from the robot experiment or a declared simulation, with a limitation and an independent changed-context explanation.
RoboMaster S1 LAB

Observe the robot

04_while_marker.py stays still and polls the built-in A-marker condition up to ten times. A green LED means observed; red means budget used. No response authorizes movement.

Open the complete S1 Lab program
# Remain stationary. Read a NEW marker condition on each pass.
def start():
    chassis_ctrl.stop()
    vision_ctrl.enable_detection(rm_define.vision_detection_marker)
    checks = 0
    found = False
    while not found and checks < 10:
        found = vision_ctrl.check_condition(rm_define.cond_recognized_marker_letter_A)
        checks = checks + 1
        if not found:
            time.sleep(0.2)
    if found:
        led_ctrl.set_top_led(rm_define.armor_top_all, 0, 255, 0, rm_define.effect_always_on)
    else:
        led_ctrl.set_top_led(rm_define.armor_top_all, 255, 0, 0, rm_define.effect_always_on)
    vision_ctrl.disable_detection(rm_define.vision_detection_marker)
    chassis_ctrl.stop()

Change one thing and measure

Try success on the first poll, delayed success and no success in a recorded stream. For S1, reveal the marker at different times. For Tello, compare the height log with the teacher observation without placing obstacles near the drone.

Explain and transfer

Why does repeating a condition on one old reading fail to detect a new event?

Monitor a print-job queue. Describe what is refreshed, what counts as success and what happens if the budget expires.

Save your code, prediction, actual result and one limitation. Label a command-log demonstration as simulated. Ask your tutor for a fresh review around day 2 and day 7, adjusted to your needs.

If your result is unexpected

Testing a frozen reading or forgetting the budget update

Keep a table with check number, newly read value and next condition. Include a stream that never becomes ready.

After a correction, explain the changed state and try the unopened independent variant. If it was exposed, use a tutor-authored changed-input task and give it a new ID; keep the original record.

05Change the route: lists, order and append

Edit an ordered route and append observations without losing earlier values.

Start with a problem

Give the robot a three-leg route, then swap the first and last distance cards without changing the movement code.

An ordered collection keeps route data separate from the code that executes each leg. A growing list also preserves multiple observations instead of overwriting one value.

Three separate variables require separate handling. Reassigning one variable loses the previous observation. A dictionary is better for named fields in one reading; a list is useful for the order of many readings.

See the idea move

A list keeps its order

Read the route from left to right. Reversing changes order, not the values.

  1. 01Index 0

    0.20 m

  2. 02Index 1

    0.30 m

  3. 03Index 2

    0.40 m

  4. 04Reverse

    0.40 m → 0.30 m → 0.20 m

Concept animation · no robot connection or measured results.

Read, predict, trace

A list preserves item order. Index 0 selects the first item and -1 selects the last. append adds one item at the end; iterating reads each route value in order.

  • index: an item position
  • append: add at the end
  • order: the sequence is meaningful
route_cm = [20, 30]
route_cm.append(40)
print(route_cm[0], route_cm[-1], sum(route_cm))
Compare with the worked result
20 40 90
StepStateResult
make routepositions 0,1 hold 20,30no output
append 40route becomes [20,30,40]no output
index and sumfirst 20; last 40; total 9020 40 90

Practice before you run

These are formative practice prompts. A revealed or assisted answer stays practice; it is not a completed LMS lesson.

Before you begin

Predict the exact output before running it. Explain the result using lists, indexing, iteration and mutation.

print([25, 35, 45][0])
  1. 35
  2. 0
  3. 25

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-05-diagnosis-v1 · 2026-11-02.2

Try with a hint

Predict the exact output before running it. Explain the result using lists, indexing, iteration and mutation.

log = [20]
log.append(30)
print(log)
  1. [20, 30]
  2. [30]
  3. [30, 20]

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Hint

Number the boxes starting at 0. Draw the list again after append; it keeps the original boxes.

Task robot-hooks-05-guided-v1 · 2026-11-02.2

Try independently

Predict the exact output before running it. Explain the result using lists, indexing, iteration and mutation.

route = [20, 40, 30]
print(route[1], route[-1])
  1. 20 30
  2. 40 30
  3. 40 20

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-05-independent-a-v1 · 2026-11-02.2

Change the context

Predict the exact output before running it. Explain the result using lists, indexing, iteration and mutation.

playlist = ["intro", "theme"]
playlist.append("end")
print(playlist[1])
  1. intro
  2. end
  3. theme

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-05-transfer-v1 · 2026-11-02.2

Build your version

Return (number_of_legs, total_cm, final_leg_cm) from route_summary(route_cm). An empty route returns (0, 0, None). These are distances, not flight coordinates.

def route_summary(route_cm):
    return (0, 0, None)

print(route_summary([20, 30, 40]))
Public checks for your code
assert route_summary([20, 30, 40]) == (3, 90, 40)
assert route_summary([50]) == (1, 50, 50)
assert route_summary([]) == (0, 0, None)
  • Explain this goal with a concrete input and state trace: Edit an ordered route and append observations without losing earlier values.
  • Modify the starter, pass the public tests, and add one meaningful new case with predicted and observed results.
  • Present a labelled artifact from the robot experiment or a declared simulation, with a limitation and an independent changed-context explanation.
RoboMaster S1 LAB

Observe the robot

05_list_route.py iterates over [0.20, 0.30, 0.40] m and returns using the reverse index order. Compare sequence and total with the laptop plan.

Open the complete S1 Lab program
def start():
    chassis_ctrl.stop()
    robot_ctrl.set_mode(rm_define.robot_mode_free)
    chassis_ctrl.set_trans_speed(0.2)
    route_m = [0.20, 0.30, 0.40]
    for distance_m in route_m:
        chassis_ctrl.move_with_distance(0, distance_m)
    for index in range(len(route_m) - 1, -1, -1):
        chassis_ctrl.move_with_distance(180, route_m[index])
    chassis_ctrl.stop()

Change one thing and measure

Predict total outbound distance and the ordered command log. Change only the order, then only one leg. Explain which edit changes the endpoint and which changes only intermediate stops.

Explain and transfer

Why does append preserve more evidence than repeatedly assigning reading = new_value?

Store a playlist or a sequence of experiment readings and explain when order changes the meaning.

Save your code, prediction, actual result and one limitation. Label a command-log demonstration as simulated. Ask your tutor for a fresh review around day 2 and day 7, adjusted to your needs.

If your result is unexpected

Starting indices at 1 or treating append as replacement

Number the boxes starting at 0. Draw the list again after append; it keeps the original boxes.

After a correction, explain the changed state and try the unopened independent variant. If it was exposed, use a tutor-authored changed-input task and give it a new ID; keep the original record.

06Name each measurement: dictionaries and records

Build a record with meaningful keys, distinguish missing from zero and preserve successive records.

Start with a problem

Show [70, 80] and ask whether 70 is battery or height. Replace it with a labelled record.

Named fields keep unlike measurements distinguishable. A list of dictionaries represents many observations with the same named columns.

A positional list depends on everyone remembering the same field order. A dictionary gives fields names; it does not validate units or prove that a sensor actually measured the value.

See the idea move

A value needs a label

A dictionary separates the command, observation and source. A missing value is not zero.

  1. 01Robot

    RoboMaster S1

  2. 02Command

    0.30 m

  3. 03Missing

    None: no observation was obtained.

  4. 04Zero

    0: an actual recorded value of zero.

Concept animation · no robot connection or measured results.

Read, predict, trace

A dictionary maps a key to a value. Reusing the same key replaces its value. Separate reading dictionaries belong in a list when you need a time sequence. None marks a missing quantity; zero is a measured value.

  • key: a field name
  • record: one observation with named fields
  • missing: not measured, rather than zero
reading = {"battery_pct": 70, "height_cm": 80}
reading["height_cm"] = 85
print(reading["battery_pct"], reading["height_cm"])
Compare with the worked result
70 85
StepStateResult
create recordbattery_pct 70; height_cm 80no output
update height_cmbattery unchanged; height 85no output
read by keysnames determine the fields70 85

Practice before you run

These are formative practice prompts. A revealed or assisted answer stays practice; it is not a completed LMS lesson.

Before you begin

Predict the exact output before running it. Explain the result using dictionaries, keys, values and lists of records.

print({"height_cm": 90, "battery_pct": 60}["battery_pct"])
  1. 60
  2. 90
  3. 0

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-06-diagnosis-v1 · 2026-11-02.2

Try with a hint

Predict the exact output before running it. Explain the result using dictionaries, keys, values and lists of records.

r = {"count": 1}
r["count"] = 4
print(r["count"])
  1. 1
  2. 4
  3. 5

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Hint

Write the schema as key: meaning (unit). Check whether a change updates one record or adds a new observation.

Task robot-hooks-06-guided-v1 · 2026-11-02.2

Try independently

Predict the exact output before running it. Explain the result using dictionaries, keys, values and lists of records.

r = {"robot": "s1", "height_cm": None}
print(r["height_cm"] is None)
  1. False
  2. 0
  3. True

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-06-independent-a-v1 · 2026-11-02.2

Change the context

Predict the exact output before running it. Explain the result using dictionaries, keys, values and lists of records.

weather = {"temp_c": 0, "rain_mm": None}
print(weather["temp_c"] is None)
  1. False
  2. True
  3. 0

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-06-transfer-v1 · 2026-11-02.2

Build your version

make_record(robot, sample, battery_pct, height_cm) returns a new dictionary with exactly those four keys. Missing measurements stay None. Call it twice and show that the dictionaries are separate objects.

def make_record(robot, sample, battery_pct, height_cm):
    return {}

print(make_record("s1", 1, None, None))
Public checks for your code
a = make_record("tello", 1, 80, 90)
b = make_record("s1", 2, None, None)
assert a == {"robot": "tello", "sample": 1, "battery_pct": 80, "height_cm": 90}
assert b["height_cm"] is None
assert a is not b
assert set(b) == {"robot", "sample", "battery_pct", "height_cm"}
  • Explain this goal with a concrete input and state trace: Build a record with meaningful keys, distinguish missing from zero and preserve successive records.
  • Modify the starter, pass the public tests, and add one meaningful new case with predicted and observed results.
  • Present a labelled artifact from the robot experiment or a declared simulation, with a limitation and an independent changed-context explanation.
RoboMaster S1 LAB

Observe the robot

06_dictionary.py stores a marker-observed flag in named fields. It does not fabricate Tello-style height or battery readings for the S1.

Open the complete S1 Lab program
# The named record lives in robot memory. Observer records the LED result.
def start():
    chassis_ctrl.stop()
    vision_ctrl.enable_detection(rm_define.vision_detection_marker)
    time.sleep(0.5)
    observation = {"robot": "s1", "sample": 0, "marker_seen": False}
    observation["marker_seen"] = vision_ctrl.check_condition(rm_define.cond_recognized_marker_letter_A)
    if observation["marker_seen"]:
        led_ctrl.set_top_led(rm_define.armor_top_all, 0, 255, 0, rm_define.effect_always_on)
    else:
        led_ctrl.set_top_led(rm_define.armor_top_all, 255, 0, 0, rm_define.effect_always_on)
    vision_ctrl.disable_detection(rm_define.vision_detection_marker)
    chassis_ctrl.stop()

Change one thing and measure

Write one schema before collecting anything. Capture at least two observations. For each key, identify whether it came from a sensor, a person or a derived calculation; leave unavailable quantities blank.

Explain and transfer

Why does putting height_cm in a key help readers, and what does that key still fail to guarantee?

Design a weather record with one true zero and one missing value, and explain the difference.

Save your code, prediction, actual result and one limitation. Label a command-log demonstration as simulated. Ask your tutor for a fresh review around day 2 and day 7, adjusted to your needs.

If your result is unexpected

Using a positional index as a key or replacing history with one updated record

Write the schema as key: meaning (unit). Check whether a change updates one record or adds a new observation.

After a correction, explain the changed state and try the unopened independent variant. If it was exposed, use a tutor-authored changed-input task and give it a new ID; keep the original record.

07Teach a reusable move: functions, parameters and methods

Separate a pure conversion function from an action method, and explain what each call returns or changes.

Start with a problem

Ask for a short patrol, then a longer one. Should the student copy the whole program or give the same move a different input?

A function gives a meaningful name to reusable behaviour. Parameters vary the input. Return values let calculations be tested before a hardware method performs an action.

Copying movement code creates multiple places to fix. Printing a converted distance does not return it to another function. tello.move_forward(...) is a method on a particular device object; a plain conversion function needs no device.

See the idea move

Input → function → result

A pure conversion function returns a value. A device method is a separate action.

  1. 01Argument

    Pass 0.30 m into the conversion function.

  2. 02Return

    The function returns 30 cm.

  3. 03Device action

    Use the reviewed value in the device-specific command.

Concept animation · no robot connection or measured results.

Read, predict, trace

def defines a function; calling it runs its body. return sends a value to the caller. A method is accessed through an object, as in samples.append(value) or drone.move_forward(cm). These are both calls, but their owners and effects differ.

  • parameter: a name for a supplied input
  • return: send a result to the caller
  • method: a function accessed through an object
def to_cm(metres):
    return int(round(metres * 100))

commands = []
commands.append(to_cm(0.4))
print(commands)
Compare with the worked result
[40]
StepStateResult
define to_cmno body execution yetno output
call to_cm(0.4)returns 40 to the callerno output
commands.append(40); printlist method changes commands[40]

Practice before you run

These are formative practice prompts. A revealed or assisted answer stays practice; it is not a completed LMS lesson.

Before you begin

Predict the exact output before running it. Explain the result using functions, arguments, return values and object methods.

def leg():
    print("move")
print("ready")
  1. move ready
  2. ready
  3. move

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-07-diagnosis-v1 · 2026-11-02.2

Try with a hint

Predict the exact output before running it. Explain the result using functions, arguments, return values and object methods.

def double(x):
    return x * 2
print(double(3))
  1. 3
  2. None
  3. 6

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Hint

Mark definition, call, return and side effect separately. A returned number is not a movement command.

Task robot-hooks-07-guided-v1 · 2026-11-02.2

Try independently

Predict the exact output before running it. Explain the result using functions, arguments, return values and object methods.

def to_cm(m):
    return int(round(m * 100))
print(to_cm(0.25) + to_cm(0.35))
  1. 60
  2. 0.6
  3. 2535

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-07-independent-a-v1 · 2026-11-02.2

Change the context

Predict the exact output before running it. Explain the result using functions, arguments, return values and object methods.

def seconds(milliseconds):
    return milliseconds / 1000
print(seconds(500))
  1. 500
  2. 0.5
  3. None

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-07-transfer-v1 · 2026-11-02.2

Build your version

out_and_back(distance_m) returns [("forward", cm), ("back", cm)]. The parameter is 0.20-0.80 m in whole centimetres. Use a conversion function; do not import a robot library or send motion.

def to_cm(distance_m):
    return 0

def out_and_back(distance_m):
    return []

print(out_and_back(0.3))
Public checks for your code
assert to_cm(0.2) == 20
assert out_and_back(0.3) == [("forward", 30), ("back", 30)]
assert out_and_back(0.6) == [("forward", 60), ("back", 60)]
  • Explain this goal with a concrete input and state trace: Separate a pure conversion function from an action method, and explain what each call returns or changes.
  • Modify the starter, pass the public tests, and add one meaningful new case with predicted and observed results.
  • Present a labelled artifact from the robot experiment or a declared simulation, with a limitation and an independent changed-context explanation.
RoboMaster S1 LAB

Observe the robot

07_functions.py defines travel(distance_m), then calls it with two different values. Its S1 controller method accepts metres directly.

Open the complete S1 Lab program
def travel(distance_m):
    chassis_ctrl.move_with_distance(0, distance_m)
    chassis_ctrl.move_with_distance(180, distance_m)


def start():
    chassis_ctrl.stop()
    robot_ctrl.set_mode(rm_define.robot_mode_free)
    chassis_ctrl.set_trans_speed(0.2)
    travel(0.20)
    travel(0.30)
    chassis_ctrl.stop()

Change one thing and measure

Test the conversion and returned plan without a robot. On hardware run the unchanged helper with 0.20 and 0.30 m targets. Explain how one function serves two requests.

Explain and transfer

How is calling to_cm(0.3) different from calling drone.move_forward(30)?

Write a reusable photo filename function; keep generating the name separate from saving a file.

Save your code, prediction, actual result and one limitation. Label a command-log demonstration as simulated. Ask your tutor for a fresh review around day 2 and day 7, adjusted to your needs.

If your result is unexpected

Assuming definition runs the body or print supplies a return value

Mark definition, call, return and side effect separately. A returned number is not a movement command.

After a correction, explain the changed state and try the unopened independent variant. If it was exposed, use a tutor-authored changed-input task and give it a new ID; keep the original record.

08Inspect every cell: nested loops and grids

Enumerate each grid cell exactly once and distinguish logical coordinates from physical travel.

Start with a problem

Lay out a 2 by 3 paper inspection grid. Students predict whether two loops produce five or six inspections.

Two dimensions require visiting every row/column combination. An inner loop handles columns for each row selected by the outer loop.

Adding row and column counts does not enumerate their combinations. A logical grid coordinate is not automatically a flight or wheel command; a route planner must define the geometry.

See the idea move

Two loops, four stops

This 2 × 2 serpentine route uses 0.30 m steps. Visiting a logical cell does not prove camera coverage.

  1. 01Row 0 · Col 0

    Start at the first cell.

  2. 02Row 0 · Col 1

    Cross the first row.

  3. 03Row 1 · Col 1

    Change rows at the edge.

  4. 04Row 1 · Col 0

    Traverse the next row in reverse.

Concept animation · no robot connection or measured results.

Read, predict, trace

For each outer row, the inner column loop starts again. A 2-row, 3-column grid has 2 * 3 cells. A physical scan can traverse alternate rows in opposite directions to avoid extra return trips.

  • outer loop: chooses one row
  • inner loop: visits columns in that row
  • coordinate: a row/column pair
for row in range(2):
    for col in range(2):
        print(row, col)
Compare with the worked result
0 0
0 1
1 0
1 1
StepStateResult
row = 0col visits 0 then 10 0; 0 1
row = 1col restarts at 0 then 11 0; 1 1

Practice before you run

These are formative practice prompts. A revealed or assisted answer stays practice; it is not a completed LMS lesson.

Before you begin

Predict the exact output before running it. Explain the result using nested for loops and row/column coordinates.

print(2 * 3)
  1. 5
  2. 23
  3. 6

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-08-diagnosis-v1 · 2026-11-02.2

Try with a hint

Predict the exact output before running it. Explain the result using nested for loops and row/column coordinates.

n = 0
for row in range(2):
    for col in range(3):
        n += 1
print(n)
  1. 6
  2. 5
  3. 3

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Hint

Write the row once, then list all columns next to it. Repeat for the next row.

Task robot-hooks-08-guided-v1 · 2026-11-02.2

Try independently

Predict the exact output before running it. Explain the result using nested for loops and row/column coordinates.

for row in range(1):
    for col in range(3):
        print(row, col)
  1. 0 0 1 1 2 2
  2. 0 0 0 1 0 2
  3. 1 1 1 2 1 3

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-08-independent-a-v1 · 2026-11-02.2

Change the context

Predict the exact output before running it. Explain the result using nested for loops and row/column coordinates.

for day in range(2):
    for sensor in ["A", "B"]:
        print(day, sensor)
  1. 0 A 1 B
  2. A 0 B 1
  3. 0 A 0 B 1 A 1 B

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-08-transfer-v1 · 2026-11-02.2

Build your version

grid_cells(rows, cols) returns row-major (row, col) pairs. Valid inputs are nonnegative integers. Test zero rows and zero columns. The result is a checklist; it must not move a robot.

def grid_cells(rows, cols):
    cells = []
    return cells

print(grid_cells(2, 3))
Public checks for your code
assert grid_cells(2, 3) == [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]
assert grid_cells(0, 3) == []
assert grid_cells(2, 0) == []
  • Explain this goal with a concrete input and state trace: Enumerate each grid cell exactly once and distinguish logical coordinates from physical travel.
  • Modify the starter, pass the public tests, and add one meaningful new case with predicted and observed results.
  • Present a labelled artifact from the robot experiment or a declared simulation, with a limitation and an independent changed-context explanation.
RoboMaster S1 LAB

Observe the robot

08_nested_grid.py uses two loops and reverses column labels on the second row. A 0.30 m sideways translation enters the next row. Match command order to the paper grid.

Open the complete S1 Lab program
# Logical 2x2 inspection grid, serpentine traversal, no camera coverage claim.
def start():
    chassis_ctrl.stop()
    robot_ctrl.set_mode(rm_define.robot_mode_free)
    chassis_ctrl.set_trans_speed(0.2)
    visited = []
    for row in range(2):
        for visit in range(2):
            col = visit
            if row == 1:
                col = 1 - visit
            visited.append([row, col])
            if visit < 1:
                if row == 0:
                    chassis_ctrl.move_with_distance(0, 0.30)
                else:
                    chassis_ctrl.move_with_distance(180, 0.30)
        if row < 1:
            chassis_ctrl.move_with_distance(90, 0.30)
    chassis_ctrl.stop()

Change one thing and measure

Mark each paper cell as the dry-run log visits it. Check uniqueness and count. Then mark physical positions after one supervised pass; distinguish visiting a label from verifying an actual image footprint.

Explain and transfer

Why is the number of inspections rows times columns, and why are grid labels insufficient to command a physical robot?

Schedule each sensor on each day; explain which loop restarts and how many readings are planned.

Save your code, prediction, actual result and one limitation. Label a command-log demonstration as simulated. Ask your tutor for a fresh review around day 2 and day 7, adjusted to your needs.

If your result is unexpected

Adding loop counts or failing to restart the inner loop

Write the row once, then list all columns next to it. Repeat for the next row.

After a correction, explain the changed state and try the unopened independent variant. If it was exposed, use a tutor-authored changed-input task and give it a new ID; keep the original record.

09Keep the evidence: files, CSV and data provenance

Save and reload trial records with field names, units, origin and unsuccessful outcomes.

Start with a problem

Close a program that only printed its results. Ask what evidence the next class can inspect.

A saved table survives program exit and can be reopened by another tool. A stable schema and provenance label make the measurements interpretable.

A list in memory disappears when the process ends. Copying only successful trials creates a biased record. The S1 Lab cannot write a laptop CSV, so the observer records physical trials through the supplied laptop tool.

See the idea move

From a trial to a CSV row

Keep interrupted trials and label invented, simulated and measured data separately.

  1. 01Plan

    Record target, robot and condition.

  2. 02Observe

    Measure travel independently of the command log.

  3. 03Save

    Store source, outcome and any missing values.

  4. 04Audit

    Retain the raw row, including aborted trials.

Concept animation · no robot connection or measured results.

Read, predict, trace

CSV stores one record per row and named columns in a header. DictWriter uses a field list to align values. CSV text is not typed data: numeric strings need conversion when read back.

  • schema: expected columns and meanings
  • provenance: where a value came from
  • CSV: comma-separated tabular text
import csv
from io import StringIO
text = "robot,target_cm\ntello,30\ns1,30\n"
rows = list(csv.DictReader(StringIO(text)))
print(len(rows), rows[0]["target_cm"])
Compare with the worked result
2 30
StepStateResult
CSV headerrobot and target_cm become keysno output
DictReadertwo dictionaries; values are stringsno output
len and first target2 records; text value "30"2 30

Practice before you run

These are formative practice prompts. A revealed or assisted answer stays practice; it is not a completed LMS lesson.

Before you begin

Predict the exact output before running it. Explain the result using file I/O, CSV, rows, schemas and provenance.

import csv
from io import StringIO
r = list(csv.DictReader(StringIO("x\n3\n4\n")))
print(len(r))
  1. 2
  2. 3
  3. 1

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-09-diagnosis-v1 · 2026-11-02.2

Try with a hint

Predict the exact output before running it. Explain the result using file I/O, CSV, rows, schemas and provenance.

import csv
from io import StringIO
r = next(csv.DictReader(StringIO("cm\n30\n")))
print(type(r["cm"]).__name__)
  1. int
  2. str
  3. float

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Hint

Separate the header from data rows. DictReader values are strings; cast them before arithmetic.

Task robot-hooks-09-guided-v1 · 2026-11-02.2

Try independently

Predict the exact output before running it. Explain the result using file I/O, CSV, rows, schemas and provenance.

import csv
from io import StringIO
r = list(csv.DictReader(StringIO("cm\n20\n35\n")))
print(sum(int(x["cm"]) for x in r))
  1. 2035
  2. 2
  3. 55

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-09-independent-a-v1 · 2026-11-02.2

Change the context

Predict the exact output before running it. Explain the result using file I/O, CSV, rows, schemas and provenance.

import csv
from io import StringIO
r = list(csv.DictReader(StringIO("day,rain_mm\nMon,0\nTue,2\n")))
print(r[0]["rain_mm"])
  1. 0
  2. 2
  3. None

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-09-transfer-v1 · 2026-11-02.2

Build your version

Read CSV text with header target_cm and return the numeric targets in order. Inputs contain valid integer strings. Then use record_trial.py to save a complete or aborted physical trial with origin=measured; do not edit the synthetic fixture to masquerade as measurements.

import csv
from io import StringIO

def read_targets(text):
    return []

print(read_targets("target_cm\n30\n40\n"))
Public checks for your code
assert read_targets("target_cm\n30\n40\n") == [30, 40]
assert read_targets("target_cm\n") == []
assert read_targets("target_cm\n0\n") == [0]
  • Explain this goal with a concrete input and state trace: Save and reload trial records with field names, units, origin and unsuccessful outcomes.
  • Modify the starter, pass the public tests, and add one meaningful new case with predicted and observed results.
  • Present a labelled artifact from the robot experiment or a declared simulation, with a limitation and an independent changed-context explanation.
RoboMaster S1 LAB

Observe the robot

Use 09_trial.py for one measured 0.30 m move. An observer measures after stopping and enters the value using record_trial.py. The Lab program neither imports csv nor writes files.

Open the complete S1 Lab program
# ONE forward trial; measure only after it stops, then manually reset the start.
# Keep target 0.30 m. Conditions: slow=0.20 m/s, fast=0.30 m/s.
SPEED_M_S = 0.20


def start():
    chassis_ctrl.stop()
    robot_ctrl.set_mode(rm_define.robot_mode_free)
    chassis_ctrl.set_trans_speed(SPEED_M_S)
    chassis_ctrl.move_with_distance(0, 0.30)
    chassis_ctrl.stop()

Change one thing and measure

Collect one short-travel trial for each available robot. Use the same target and record the robot, condition, pair number, order, method, outcome and target even if the run is aborted. Compare terminal output with the reopened CSV.

Explain and transfer

Why does a saved row need both an outcome and a measurement method?

Log a weather observation with origin and units so another student can read it a week later.

Save your code, prediction, actual result and one limitation. Label a command-log demonstration as simulated. Ask your tutor for a fresh review around day 2 and day 7, adjusted to your needs.

If your result is unexpected

Counting the header as a trial or assuming CSV has numeric types

Separate the header from data rows. DictReader values are strings; cast them before arithmetic.

After a correction, explain the changed state and try the unopened independent variant. If it was exposed, use a tutor-authored changed-input task and give it a new ID; keep the original record.

10Missing is not zero: cleaning data with pandas

Convert numeric text, identify missing/impossible values and preserve unsuccessful trial counts.

Start with a problem

Show an empty distance measurement and the number 0. Ask whether filling every blank with zero would improve the robot.

A machine-readable file can still contain unusable or missing values. Explicit conversion and reason flags keep cleaning decisions visible and prevent invented measurements.

Replacing missing distances with zero manufactures a huge error. Deleting all failures makes the robot appear better. Preserve the raw file and write a separate audit of every row.

See the idea move

Missing, invalid, or measured?

Keep the raw data and record each cleaning decision. Never replace every missing value with zero.

  1. 01Measured zero

    0 → retain when it is a valid observation.

  2. 02Missing

    Blank → mark missing; investigate the source.

  3. 03Invalid

    Text in a distance field → flag for review.

  4. 04Audit trail

    Keep the raw row and the reason for each change.

Concept animation · no robot connection or measured results.

Read, predict, trace

pd.to_numeric(errors="coerce") turns invalid numeric text into missing data. isna detects it. A boolean mask selects eligible records; the excluded rows and their reasons must remain inspectable.

  • DataFrame: a table with named columns
  • mask: one True/False choice per row
  • coerce: convert invalid numeric text to missing
import pandas as pd
s = pd.to_numeric(pd.Series(["30", "bad", "0"]), errors="coerce")
print(int(s.isna().sum()), int(s.dropna().sum()))
Compare with the worked result
1 30
StepStateResult
convert numeric text30.0, missing, 0.0no output
isna().sum()one unknown measurementfirst result is 1
sum observed values with dropna30 + 0; missing value stays unknown in the original series1 30

Practice before you run

These are formative practice prompts. A revealed or assisted answer stays practice; it is not a completed LMS lesson.

Before you begin

Predict the exact output before running it. Explain the result using DataFrame, numeric conversion, masks and missing values.

import pandas as pd
print(pd.isna(None))
  1. False
  2. True
  3. 0

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-10-diagnosis-v1 · 2026-11-02.2

Try with a hint

Predict the exact output before running it. Explain the result using DataFrame, numeric conversion, masks and missing values.

import pandas as pd
s = pd.to_numeric(pd.Series(["20", "oops", "40"]), errors="coerce")
print(int(s.notna().sum()))
  1. 3
  2. 1
  3. 2

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Hint

Track measured zero, blank and invalid text separately. A numeric conversion failure is a reason to flag, not a reason to silently invent a value.

Task robot-hooks-10-guided-v1 · 2026-11-02.2

Try independently

Predict the exact output before running it. Explain the result using DataFrame, numeric conversion, masks and missing values.

import pandas as pd
s = pd.Series([0.0, None, 30.0])
print(int(s.isna().sum()), int((s == 0).sum()))
  1. 1 1
  2. 2 0
  3. 0 2

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-10-independent-a-v1 · 2026-11-02.2

Change the context

Predict the exact output before running it. Explain the result using DataFrame, numeric conversion, masks and missing values.

import pandas as pd
s = pd.to_numeric(pd.Series(["0", "", "2"]), errors="coerce")
print(int(s.notna().sum()))
  1. 3
  2. 2
  3. 1

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-10-transfer-v1 · 2026-11-02.2

Build your version

clean_distances(values) converts strings with pandas, drops missing or negative values, and returns the remaining numeric values in input order. This tiny exercise does not remove rows from the trial audit. In the full experiment, outcome counts retain every trial.

import pandas as pd

def clean_distances(values):
    return []

print(clean_distances(["30", "", "-2", "0"]))
Public checks for your code
assert clean_distances(["30", "", "-2", "0"]) == [30, 0]
assert clean_distances(["bad", None]) == []
assert clean_distances([]) == []
assert clean_distances(["12.5"]) == [12.5]
  • Explain this goal with a concrete input and state trace: Convert numeric text, identify missing/impossible values and preserve unsuccessful trial counts.
  • Modify the starter, pass the public tests, and add one meaningful new case with predicted and observed results.
  • Present a labelled artifact from the robot experiment or a declared simulation, with a limitation and an independent changed-context explanation.
RoboMaster S1 LAB

Observe the robot

Use observer-entered S1 trial measurements. A blank height or battery field is expected when that quantity is unavailable; it is not zero.

Open the complete S1 Lab program
# ONE forward trial; measure only after it stops, then manually reset the start.
# Keep target 0.30 m. Conditions: slow=0.20 m/s, fast=0.30 m/s.
SPEED_M_S = 0.20


def start():
    chassis_ctrl.stop()
    robot_ctrl.set_mode(rm_define.robot_mode_free)
    chassis_ctrl.set_trans_speed(SPEED_M_S)
    chassis_ctrl.move_with_distance(0, 0.30)
    chassis_ctrl.stop()

Change one thing and measure

Run analyze_trials.py on data/synthetic_trials.csv. Inspect row_audit.csv alongside the raw rows. Explain why the malformed, missing, aborted and origin-mismatched rows have different flags.

Explain and transfer

Why can keeping a measured zero and excluding a missing value both be correct?

Clean a rainfall column without turning an unobserved day into a dry day.

Save your code, prediction, actual result and one limitation. Label a command-log demonstration as simulated. Ask your tutor for a fresh review around day 2 and day 7, adjusted to your needs.

If your result is unexpected

Equating missing with zero or erasing aborted trials

Track measured zero, blank and invalid text separately. A numeric conversion failure is a reason to flag, not a reason to silently invent a value.

After a correction, explain the changed state and try the unopened independent variant. If it was exposed, use a tutor-authored changed-input task and give it a new ID; keep the original record.

11Which setting works better? grouping, charts and fair trials

Compare repeated, paired settings within one robot using counts, absolute error, spread and outcome rate without claiming more than the sample supports.

Start with a problem

Show two settings with the same average error but different spreads. Ask which evidence is missing from a single average.

Grouping compares like trials while counts and spread reveal how much evidence supports a summary. A graph with individual points exposes variation hidden by a mean.

One impressive run is weak evidence. Pooling robots hides different mechanics. Comparing slow runs on one surface with fast runs on another confounds speed with surface.

See the idea move

Opposite errors can cancel

Illustrative errors in cm. Compare robot × condition with counts, outcome rates and spread.

  1. 01Trial A

    +4 cm: farther than the target.

  2. 02Trial B

    −4 cm: shorter than the target.

  3. 03Signed mean

    (+4 − 4) ÷ 2 = 0 cm.

  4. 04Mean absolute error

    (|+4| + |−4|) ÷ 2 = 4 cm.

Concept animation · no robot connection or measured results.

Read, predict, trace

Signed error is measured minus target; absolute error measures miss size. Group by robot and condition. Count all trial outcomes, then calculate distance statistics only for complete valid measurements. Plot every valid point and report how many trials were excluded.

  • group: comparable rows
  • absolute error: size of the miss
  • confound: another changing factor
  • spread: variation between trials
import pandas as pd
df = pd.DataFrame({"setting": ["slow", "slow", "fast", "fast"], "error_cm": [1, -1, 4, -4]})
df["abs_error"] = df["error_cm"].abs()
print(df.groupby("setting")["abs_error"].mean().to_dict())
Compare with the worked result
{'fast': 4.0, 'slow': 1.0}
StepStateResult
take absolute errorsslow: 1,1; fast: 4,4no output
group by settingtwo groups with two observations eachno output
mean in each groupfast 4.0; slow 1.0{'fast': 4.0, 'slow': 1.0}

Practice before you run

These are formative practice prompts. A revealed or assisted answer stays practice; it is not a completed LMS lesson.

Before you begin

Predict the exact output before running it. Explain the result using groupby, aggregates, variability and controlled comparison.

print((4 + -4) / 2)
  1. 4.0
  2. 8
  3. 0.0

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-11-diagnosis-v1 · 2026-11-02.2

Try with a hint

Predict the exact output before running it. Explain the result using groupby, aggregates, variability and controlled comparison.

errors = [3, -5]
print(sum(abs(e) for e in errors) / len(errors))
  1. 4.0
  2. -1.0
  3. 8.0

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Hint

Do not average signed misses before taking absolute values: +4 and -4 cancel. Write the denominator of every rate.

Task robot-hooks-11-guided-v1 · 2026-11-02.2

Try independently

Predict the exact output before running it. Explain the result using groupby, aggregates, variability and controlled comparison.

import pandas as pd
df = pd.DataFrame({"condition": ["a", "a", "b"], "error": [2, 4, 9]})
print(float(df.groupby("condition")["error"].mean()["a"]))
  1. 5.0
  2. 3.0
  3. 2.0

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-11-independent-a-v1 · 2026-11-02.2

Change the context

Predict the exact output before running it. Explain the result using groupby, aggregates, variability and controlled comparison.

waits = [1, 1, 7]
print(max(waits) - min(waits))
  1. 3
  2. 7
  3. 6

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-11-transfer-v1 · 2026-11-02.2

Build your version

error_summary(target_cm, observed_cm) returns count, mean signed error, mean absolute error and range of signed errors. The observations are complete, valid numbers. An empty list returns count 0 and None for the three statistics. Then inspect the full grouped CSV and plot from analyze_trials.py.

def error_summary(target_cm, observed_cm):
    return {"n": 0, "bias_cm": None, "mae_cm": None, "range_cm": None}

print(error_summary(30, [29, 31]))
Public checks for your code
assert error_summary(30, [29, 31]) == {"n": 2, "bias_cm": 0, "mae_cm": 1, "range_cm": 2}
assert error_summary(30, []) == {"n": 0, "bias_cm": None, "mae_cm": None, "range_cm": None}
assert error_summary(30, [34])["mae_cm"] == 4
  • Explain this goal with a concrete input and state trace: Compare repeated, paired settings within one robot using counts, absolute error, spread and outcome rate without claiming more than the sample supports.
  • Modify the starter, pass the public tests, and add one meaningful new case with predicted and observed results.
  • Present a labelled artifact from the robot experiment or a declared simulation, with a limitation and an independent changed-context explanation.
RoboMaster S1 LAB

Observe the robot

Set 09_trial.py SPEED_M_S to 0.20 or 0.30, leaving distance and the marked surface unchanged. Stop before measurement. Do not compare its numeric speed units directly to Tello units.

Open the complete S1 Lab program
# ONE forward trial; measure only after it stops, then manually reset the start.
# Keep target 0.30 m. Conditions: slow=0.20 m/s, fast=0.30 m/s.
SPEED_M_S = 0.20


def start():
    chassis_ctrl.stop()
    robot_ctrl.set_mode(rm_define.robot_mode_free)
    chassis_ctrl.set_trans_speed(SPEED_M_S)
    chassis_ctrl.move_with_distance(0, 0.30)
    chassis_ctrl.stop()

Change one thing and measure

Plan at least three slow/fast pairs per robot. Alternate order slow-fast, fast-slow, slow-fast (or randomize and record order). Record aborted runs too. Keep target 30 cm, surface, battery band, measurement ruler and start position fixed; note battery drift and order as remaining limitations. This is exploratory classroom evidence, not a population-level speed claim.

Explain and transfer

Why must a report show trial counts and unsuccessful runs alongside mean error?

Compare two queue policies with repeated waits, documenting the workload and order rather than showing only the best wait.

Save your code, prediction, actual result and one limitation. Label a command-log demonstration as simulated. Ask your tutor for a fresh review around day 2 and day 7, adjusted to your needs.

If your result is unexpected

Treating cancellation as accuracy or ignoring failed/omitted trials

Do not average signed misses before taking absolute values: +4 and -4 cancel. Write the denominator of every rate.

After a correction, explain the changed state and try the unopened independent variant. If it was exposed, use a tutor-authored changed-input task and give it a new ID; keep the original record.

12Build and defend an inspection mission

Choose and justify each structure, demonstrate bounded behaviour and present reproducible evidence with limitations.

Start with a problem

Give a client request: inspect four marked stations and explain whether a revised setting improved reliability. Students choose the code structures before seeing a solution.

Real tasks combine planning, execution and evidence. Each structure should solve a named problem: lists order stations, dictionaries label readings, loops repeat or wait, and functions isolate reusable decisions.

A moving robot is not proof that every station was inspected. A passing public test is not proof of reasoning or physical reliability. A graph of synthetic data is not a hardware result.

See the idea move

Review the whole route first

Execution follows a reviewed plan. An animation or command receipt is not measured completion.

  1. 01Plan

    Describe the route and its limits.

  2. 02Validate

    Check every route element before any motion.

  3. 03Execute

    Use only the reviewed commands and limits.

  4. 04Record

    Keep the result, including interruption.

  5. 05Explain

    Compare the plan with independent observations.

Concept animation · no robot connection or measured results.

Read, predict, trace

Separate mission data from control logic and recorded evidence. Validate the complete route before executing any leg. Test a normal case, an empty route and a refused value. Use a fixed patrol for known stations and a bounded wait only when completion depends on evidence.

  • requirement: an observable success condition
  • integration: parts working together
  • reproducibility: another person can rerun the analysis
route_cm = [20, 30]
records = []
for station, distance_cm in enumerate(route_cm):
    records.append({"station": station, "target_cm": distance_cm})
print(len(records), records[1]["target_cm"])
Compare with the worked result
2 30
StepStateResult
station 0, distance 20append one labelled recordno output
station 1, distance 30append second recordno output
inspect evidence2 records; second target 302 30

Practice before you run

These are formative practice prompts. A revealed or assisted answer stays practice; it is not a completed LMS lesson.

Before you begin

Predict the exact output before running it. Explain the result using choosing structures, testing, integration and evidence.

route = [20, 30, 40]
print(len(route))
  1. 3
  2. 90
  3. 2

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-12-diagnosis-v1 · 2026-11-02.2

Try with a hint

Predict the exact output before running it. Explain the result using choosing structures, testing, integration and evidence.

rows = []
for station in range(2):
    rows.append({"station": station})
print(rows[-1]["station"])
  1. 2
  2. 1
  3. 0

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Hint

Map each requirement to a data field, control rule and observable check. Do not start movement before the whole plan passes validation.

Task robot-hooks-12-guided-v1 · 2026-11-02.2

Try independently

Predict the exact output before running it. Explain the result using choosing structures, testing, integration and evidence.

route = [20, 0, 30]
print(all(20 <= x <= 80 for x in route))
  1. True
  2. 0
  3. False

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-12-independent-a-v1 · 2026-11-02.2

Change the context

Predict the exact output before running it. Explain the result using choosing structures, testing, integration and evidence.

queue = ["A", "B"]
receipts = []
for job in queue:
    receipts.append({"job": job, "done": False})
print(receipts[1]["done"])
  1. False
  2. True
  3. B

Write your prediction, confidence and reasoning before running the code. Record any help you used.

Task robot-hooks-12-transfer-v1 · 2026-11-02.2

Build your version

mission_plan(route_cm) validates the entire route before building any records. Accept only exact int values 20-80 cm (not booleans), at most four legs and at most 200 cm total; otherwise raise ValueError. Return one {station, target_cm} dictionary per leg. Then demonstrate a reviewed fixed-route program using the supplied robot runner, record every trial and write a claim supported by its evidence.

def mission_plan(route_cm):
    return []

print(mission_plan([20, 30]))
Public checks for your code
assert mission_plan([20, 30]) == [{"station": 0, "target_cm": 20}, {"station": 1, "target_cm": 30}]
assert mission_plan([]) == []
for route in ([0], [81], [True], [20.5], ["30"], [80, 80, 80], [20] * 5):
    try:
        mission_plan(route)
    except ValueError:
        pass
    else:
        raise AssertionError("invalid route accepted: " + repr(route))
  • Explain this goal with a concrete input and state trace: Choose and justify each structure, demonstrate bounded behaviour and present reproducible evidence with limitations.
  • Modify the starter, pass the public tests, and add one meaningful new case with predicted and observed results.
  • Present a labelled artifact from the robot experiment or a declared simulation, with a limitation and an independent changed-context explanation.
RoboMaster S1 LAB

Observe the robot

Combine the patterns in 03_for_square.py, 04_while_marker.py and 07_functions.py only after paper tracing. The S1 program owns its motion; the laptop analysis does not control an S1 through the EP SDK.

Open the complete S1 Lab program
def start():
    chassis_ctrl.stop()
    robot_ctrl.set_mode(rm_define.robot_mode_free)
    chassis_ctrl.set_trans_speed(0.2)
    route_m = [0.20, 0.30, 0.40]
    for distance_m in route_m:
        chassis_ctrl.move_with_distance(0, distance_m)
    for index in range(len(route_m) - 1, -1, -1):
        chassis_ctrl.move_with_distance(180, route_m[index])
    chassis_ctrl.stop()

Change one thing and measure

Submit a route plan and concept-to-requirement table, predicted log, tested code, raw trial CSV with origin, cleaning audit, grouped chart and a 90-second explanation. Include an unsuccessful case and a changed-context task. If hardware is unavailable, mark the whole demonstration simulated and leave physical reliability undecided.

Explain and transfer

Choose one loop, one collection and one function. Explain the requirement each solves, an alternative, and a case where you would choose differently.

Apply the plan-execute-record separation to a photo-processing queue. State which claims transfer and which require new evidence.

Save your code, prediction, actual result and one limitation. Label a command-log demonstration as simulated. Ask your tutor for a fresh review around day 2 and day 7, adjusted to your needs.

If your result is unexpected

Confusing command completion with measured mission success

Map each requirement to a data field, control rule and observable check. Do not start movement before the whole plan passes validation.

After a correction, explain the changed state and try the unopened independent variant. If it was exposed, use a tutor-authored changed-input task and give it a new ID; keep the original record.

Sources and teaching notes

This workbook uses CIT’s existing Python and data-science topics, with separate RoboMaster S1 activities. Learning content revision: 2026-11-02.2. Choose EN or KO for every lesson.

Primary references

For a fresh independent variant or a later review, ask your tutor. This page does not award a score, mark an LMS lesson complete, or schedule a review.