Hardware as Objects: a gpiozero Preview

Lesson 7 of 8 in the Pre-COSMOS series, 37 slides, showing that real robot code has the SHAPE you already know. Motors and sensors are OBJECTS - Robot, Motor, DistanceSensor - that you make and then call methods on, exactly like the Rover from Lessons 1 to 3. Using a small fake gpiozero-style API, supplied so that everything runs without a Raspberry Pi, you see that motor.forward() and motor.stop() are methods you CALL, while sensor.distance is an ATTRIBUTE you READ - the world coming in. You then build a driver loop that reads the distance and stops when it drops below a threshold, and otherwise rolls forward. The two traps are writing sensor.distance() with parentheses, which raises TypeError: 'float' object is not callable, and treating real gpiozero as something to memorize rather than recognizing the object shape - and note that distance is measured in meters. There are five checks and a scaffolded your-turn Maze Rover driver. The goal is familiarity rather than mastery, since the camp teaches this best on the real robot. Every snippet was run on CPython 3.12, with the outputs copied verbatim.

Subject: Python · 66 slides · code lesson

Open the interactive version of this deck · Homework for this lesson

What this lesson covers

The lesson, slide by slide

1. Hardware as Objects: a gpiozero Preview

Title

Pre-COSMOS · Lesson 7 of 8

Real robot code looks scary - until you notice it's just motor.forward() and sensor.distance. Objects again. You already know this shape.

2. What you will be able to do

Objectives

This is a preview, not a final exam. The goal is to recognize the shape of real robot code - the camp robot will teach the rest. By the end you can:

3. What survived from Functions as Robot Decision Helpers?

Warm-up

Discussion prompt

Before we open Hardware as Objects: a gpiozero Preview: without looking back, what was the main idea of Functions as Robot Decision Helpers, and what could you do by the end of it that you could not do before?

Hint: One sentence for the idea, one for the skill. If the second one is blank, that is the part to revisit.

Answer:

def, parameters, and return taught deeply as building reusable decision helpers a robot's control loop calls: multiple parameters and argument order, return vs print (the hardest diagnostic topic) and the None trap, using a returned value, code-after-return is dead, functions calling functions, boolean helpers, default parameters, returning multiple values, and local scope. Real photos of the robot car and sensors, hand-built function-machine / data-flow / composition diagrams, three checks, three traps, and a fully scaffolded your-turn build of is_obstacle / choose_action / update_battery.

4. Real robot libraries hand you objects too

Concept

Figure (svg): Three boxes - Rover, Motor, DistanceSensor - each shown as an object with data inside and methods on the side, to show they share the same shape.

Different names, one shape: make it, then dot into it.

The library robots use at camp is called gpiozero. It gives you objects with names like Robot, Motor, and DistanceSensor.

You make one and call methods on it - exactly what you did with the Rover. Nothing new about the shape; only the names changed.

5. Break it if you can: Real robot libraries hand you objects too

Counterexample

Discussion prompt

The library robots use at camp is called gpiozero. It gives you objects with names like Robot, Motor, and DistanceSensor.

That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.

Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.

Answer:

You make one and call methods on it - exactly what you did with the Rover. Nothing new about the shape; only the names changed.

6. Today's roadmap

Concept

Four stops, each one a piece of the same picture you already know:

Same shape
Motor, sensor = objects.
Act
motor.forward() is a method.
Sense
sensor.distance is data.
Drive
Read, decide, go or stop.

7. Which is which: Today's roadmap

Matching

Match the pairs

From Today's roadmap — match each one to what it actually does. The descriptions have been shuffled.

  • c1. Act
  • c2. Sense
  • c3. Drive
  • b1. motor.forward() is a method.
  • b2. sensor.distance is data.
  • b3. Read, decide, go or stop.

Why: Act, Sense, Drive are easy to tell apart while they are sitting next to their descriptions and much harder afterwards, which is what this checks.

8. Hardware Is Just Objects

Section

Section 1

9. A motor is an object you control

Concept

A real motor spins a wheel. In code, that motor is an object: you make one and reach into it with a dot, just like the Rover.

It has actions: motor.forward() starts it, motor.stop() stops it. Those are methods - you call them with ().

10. By analogy: A motor is an object you control

Analogy

Discussion prompt

Explain A motor is an object you control by analogy to something with no Python in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.

Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.

Answer:

A real motor spins a wheel. In code, that motor is an object: you make one and reach into it with a dot, just like the Rover.

11. Three words for today

Concept

Motor — An object that controls one wheel's motor. Methods: forward() to roll it, stop() to halt it. Called WITH parentheses.

DistanceSensor — An object that measures how far away the nearest obstacle is. You READ its distance attribute - no parentheses.

Robot — An object that bundles a left and a right Motor. Its forward() and stop() drive both wheels at once.

12. Take the definitions apart: Motor vs DistanceSensor

Definition probe

Sort into buckets

Every line below is part of the definition of Motor or of DistanceSensor — one or the other, never both. Put each where it belongs.

Motor
An object that controls one wheel's motor.; forward() to roll it, stop() to halt it.
DistanceSensor
An object that measures how far away the nearest obstacle is.; You READ its distance attribute - no parentheses.
b1
An object that controls one wheel's motor. Methods: forward() to roll it, stop() to halt it. Called WITH parentheses.
b2
An object that measures how far away the nearest obstacle is. You READ its distance attribute - no parentheses.

13. Picture it first: Buttons to press, gauges to read

Picture it

Figure (svg): A dashboard: two buttons labeled forward and stop on the left, and a round gauge labeled distance on the right.

Press to act; glance to sense.

Discussion prompt

Read the picture before the words. What is this showing, and what is the one thing it is built to make obvious? Commit to an answer, then read on.

Hint: Name the parts, then say what changes between them — and if nothing changes, say what is being held still.

Answer:

Think of the robot's dashboard. The motors are buttons you press to act. The sensor is a gauge you glance at to sense. Pressing changes the world; glancing only reads it.

14. Buttons to press, gauges to read

Intuition

Think of the robot's dashboard. The motors are buttons you press to act. The sensor is a gauge you glance at to sense. Pressing changes the world; glancing only reads it.

Figure (svg): A dashboard: two buttons labeled forward and stop on the left, and a round gauge labeled distance on the right.

Press to act; glance to sense.

Pressing a button is calling a method (motor.forward()). Reading a gauge is reading an attribute (sensor.distance). Same dot, two jobs.

15. Teach it back: Buttons to press, gauges to read

Explain it

Discussion prompt

Explain Buttons to press, gauges to read to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.

Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.

Answer:

Think of the robot's dashboard. The motors are buttons you press to act. The sensor is a gauge you glance at to sense. Pressing changes the world; glancing only reads it.

16. A fake gpiozero - so it runs with no robot

Concept

You don't have a Raspberry Pi in front of you, so we use a tiny fake Motor that just prints instead of spinning a real wheel. The code you write looks identical to the real thing.

class Motor:
    def __init__(self, name):
        self.name = name
    def forward(self):
        print(f"{self.name} motor forward")
    def stop(self):
        print(f"{self.name} motor stop")
partwhat it ishow you use it
namean attribute (data)read: motor.name
forward()a method (action)call: motor.forward()
stop()a method (action)call: motor.stop()

17. Fill in: what it is for A fake gpiozero - so it runs with no robot

Comparison

Comparison matrix

From A fake gpiozero - so it runs with no robot: refill the what it is column from what you know. The rest of the table is as it appeared.

partwhat it ishow you use it
namean attribute (data)read: motor.name
forward()a method (action)call: motor.forward()
stop()a method (action)call: motor.stop()

18. Drive one fake motor

Worked example

Make a Motor named "left", then press its two buttons. Each call prints what a real motor would do.

m = Motor("left")
m.forward()
m.stop()

forward() and stop() both need () - they're actions.

callprints
m = Motor("left")(nothing)
m.forward()left motor forward
m.stop()left motor stop

19. What each one costs: Drive one fake motor

Trade off

Comparison matrix

From Drive one fake motor: every row here is a choice with a cost. Fill the prints column, then say which row you would actually pick and what you give up for it.

callprints
m = Motor("left")(nothing)
m.forward()left motor forward
m.stop()left motor stop

20. A Robot bundles two motors

Concept

A Robot is an object that holds two Motor objects - a left and a right. Its forward() rolls both at once; its stop() halts both. An object made of objects.

class Robot:
    def __init__(self):
        self.left = Motor("left")
        self.right = Motor("right")
    def forward(self):
        self.left.forward()
        self.right.forward()
    def stop(self):
        self.left.stop()
        self.right.stop()
robot.forward() callswhich prints
self.left.forward()left motor forward
self.right.forward()right motor forward

21. Drive the whole Robot

Worked example

Make a Robot, roll forward, then stop. One method on the robot drives both wheels.

robot = Robot()
robot.forward()
robot.stop()

robot.forward() fires both motors' forward() in order.

callprints
robot.forward()left motor forward
right motor forward
robot.stop()left motor stop
right motor stop

22. Rebuild the recipe: How to use any hardware object

Ranking

Put in order

These are the steps of How to use any hardware object, scrambled. Put them back in order before the next slide shows you.

  1. Make the object: m = Motor("left"), robot = Robot().
  2. Act with a method and parentheses: m.forward(), robot.stop().
  3. Sense by reading an attribute, no parentheses: sensor.distance.
  4. Decide with an if on what you read, then act.

Why: This is the order the recipe itself gives. Recalling the sequence without the slide in front of you is the difference between recognising the method and being able to run it — most of what goes wrong in practice is a step done out of turn.

23. How to use any hardware object

Pattern

Motor, sensor, robot - the recipe is the same one you've used since Lesson 1:

  1. Make the object: m = Motor("left"), robot = Robot().
  2. Act with a method and parentheses: m.forward(), robot.stop().
  3. Sense by reading an attribute, no parentheses: sensor.distance.
  4. Decide with an if on what you read, then act.

24. Where does it stop working: How to use any hardware object

Edge cases

Discussion prompt

How to use any hardware object works on the cases you have just seen. Push it to the edge: what is the most degenerate input it still handles — empty, zero, one item, everything equal — and what is the first case where it stops being true? Name the case, not just "it breaks".

Hint: Try the smallest legal input, then the largest, then the one where two things collide. Methods are specified at their edges; the middle takes care of itself.

Answer:

Motor, sensor, robot - the recipe is the same one you've used since Lesson 1:

25. Sensing — Data Coming In

Section

Section 2

26. A sensor reading is an attribute you READ

Concept

A motor is something you do. A sensor is something you read. sensor.distance is the world coming in - data, like rover.energy. No parentheses.

Our fake DistanceSensor is built from a list of readings. Each time you read .distance, it hands you the next number in the list - a simple stand-in for a real sensor seeing the world change.

27. Teach it back: A sensor reading is an attribute you READ

Explain it

Discussion prompt

Explain A sensor reading is an attribute you READ to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.

Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.

Answer:

A motor is something you do. A sensor is something you read. sensor.distance is the world coming in - data, like rover.energy. No parentheses.

28. Read the fake sensor

Worked example

Build a DistanceSensor from a list, then read .distance twice. Each read returns the next reading - no parentheses, it's data.

sensor = DistanceSensor([1.0, 0.6])
print(sensor.distance)
print(sensor.distance)

Reading advances to the next number - the world moving closer.

readreturnsprints
sensor.distance (1st)readings[0]1.0
sensor.distance (2nd)readings[1]0.6

29. Distance is in meters

Intuition

Real gpiozero reports distance as a number between 0 and 1, in meters. So 0.15 means 15 centimeters away - close. 1.0 means a full meter - plenty of room.

That's why a threshold like 0.2 makes sense: 'if the obstacle is closer than 20 cm, stop.' Small number = close = danger.

30. By analogy: Distance is in meters

Analogy

Discussion prompt

Explain Distance is in meters by analogy to something with no Python in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.

Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.

Answer:

Real gpiozero reports distance as a number between 0 and 1, in meters. So 0.15 means 15 centimeters away - close. 1.0 means a full meter - plenty of room.

31. Something is wrong here: sensor.distance() with parentheses

Anomaly

Predict first

A student writes this, and it looks reasonable:

You add () to the distance, as if reading the sensor were an action.

It is wrong. Say what breaks — and say it before you turn the page.

Correct: distance is a number you READ - data, like energy.

Read the gauge with no parentheses.

Why: distance is a number you READ - data, like energy. The () tells Python to call that number, which makes no sense.

32. Trap: sensor.distance() with parentheses

Trap

The trap

You add () to the distance, as if reading the sensor were an action.

Write sensor.distance()

Why: distance is a number you READ - data, like energy. The () tells Python to call that number, which makes no sense.

Crashes: TypeError: 'float' object is not callable

Why: Same error family as Lesson 1's rover.energy(). You can't 'run' a number. Sensing is reading, not calling.

The fix

Read the gauge with no parentheses.

Write sensor.distance

Why: Just the attribute name - Python hands back the reading, e.g. 1.0.

print(sensor.distance) -> 1.0

Why: Data gets no (); actions get (). 'object is not callable' means you added () to data.

33. Break it on purpose: sensor.distance() with parentheses

Break the constraint

Discussion prompt

The rule this trap just fixed:

Just the attribute name - Python hands back the reading, e.g. 1.0.

Now break it on purpose. Build a case that violates it and follow the consequences until something visibly fails. Where does the failure first show up — and would you have noticed it if you had not been looking?

Hint: The dangerous rules are the ones whose violation still produces an answer. If yours fails loudly, try to find one that fails quietly.

Answer:

distance is a number you READ - data, like energy. The () tells Python to call that number, which makes no sense.

34. Rule out three: Check: act or sense?

Elimination

Eliminate the wrong options

Which line crashes with TypeError: 'float' object is not callable?

3 of these 4 are wrong. Strike them one at a time, and say what rules each one out before you strike the next. The survivor is the answer.

  • A. sensor.distance()
  • B. sensor.distance
  • C. motor.forward()
  • D. print(sensor.distance)

Survives elimination: A

Why: distance is data you read - it gives back a float like 1.0. Adding () tries to CALL that float, which Python refuses: 'float' object is not callable. Sense with no parentheses.

35. Check: act or sense?

Check

One of these reads the sensor; one tries to call it.

Check your understanding

Which line crashes with TypeError: 'float' object is not callable?

  • A. sensor.distance() (correct)
  • B. sensor.distance
  • C. motor.forward()
  • D. print(sensor.distance)

Answer: A

Why: distance is data you read - it gives back a float like 1.0. Adding () tries to CALL that float, which Python refuses: 'float' object is not callable. Sense with no parentheses.

Why B tempts people
sensor.distance with no () correctly reads the next reading - that's exactly how you sense, no crash.
Why C tempts people
forward is a real method, so motor.forward() is a valid call - it runs the action, no error.
Why D tempts people
print(sensor.distance) reads the float and prints it. The () belongs to print, not to distance, so it's fine.

36. Answer it before you see the options: Check: is a motor an object?

Prediction

Predict first

You write m = Motor("left"), then m.forward(). What is m, and what is forward()?

Answer it in your own words, now, with nothing to choose from. The options are on the next slide — and picking the right one off a list is an easier skill than producing it.

Correct: m is an object; forward() is a method (action) you call on it

Why: Motor("left") makes an object, just like Rover("Rex"). forward() is one of its methods - an action you call with parentheses. Same shape as everything since Lesson 1.

37. Check: is a motor an object?

Check

Think back to the Rover. What kind of thing is a motor in this code?

Check your understanding

You write m = Motor("left"), then m.forward(). What is m, and what is forward()?

  • A. m is an object; forward() is a method (action) you call on it (correct)
  • B. m is a function; forward is its return value
  • C. m is an attribute of the Motor class you read with no parentheses
  • D. forward() is data stored on m that you read like a gauge

Answer: A

Why: Motor("left") makes an object, just like Rover("Rex"). forward() is one of its methods - an action you call with parentheses. Same shape as everything since Lesson 1.

Why B tempts people
Motor(...) builds an object, not a plain function call returning a value. m is the motor object you then call methods on.
Why C tempts people
m is the object itself, not an attribute. Attributes are read FROM an object (like m.name); m is the thing you read them from.
Why D tempts people
forward() is an action you call (it prints), not data you read. Data with no () would be something like sensor.distance.

38. The Driver Loop

Section

Section 3

39. Read, decide, act

Concept

A driver ties sensing and acting together. Each step: read the distance, decide with an if, then act - stop if too close, otherwise roll forward.

driver loop — A loop that repeatedly senses then acts: read sensor.distance, compare to a threshold, call stop() or forward(). The heartbeat of an autonomous robot.

40. Term to definition: Hardware as Objects: a gpiozero Preview

Matching

Match the pairs

Match each term to the definition this lesson gave it — not the one you would guess from the word.

  • t1. Motor
  • t2. DistanceSensor
  • t3. Robot
  • t4. driver loop
  • d1. An object that controls one wheel's motor. Methods: forward() to roll it, stop() to halt it. Called WITH parentheses.
  • d2. An object that measures how far away the nearest obstacle is. You READ its distance attribute - no parentheses.
  • d3. An object that bundles a left and a right Motor. Its forward() and stop() drive both wheels at once.
  • d4. A loop that repeatedly senses then acts: read sensor.distance, compare to a threshold, call stop() or forward(). The heartbeat of an autonomous robot.

Why: These are the working definitions of Motor, DistanceSensor, Robot, driver loop as Hardware as Objects: a gpiozero Preview uses them. Pairing them correctly is the test of whether you could state each one with the slide switched off.

41. It's just an if you already know

Intuition

There's nothing magic here. It's the same if/else you've written all camp - the only new part is that the condition reads a sensor and the branches call motors.

if distance < 0.2: stop() else: forward(). Small distance means an obstacle is close, so play it safe and stop.

42. Break it if you can: It's just an if you already know

Counterexample

Discussion prompt

if distance < 0.2: stop() else: forward(). Small distance means an obstacle is close, so play it safe and stop.

That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.

Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.

43. One driver step

Worked example

Read once, decide once. Threshold is 0.2 meters. The first reading is 1.0 - far away - so the robot rolls forward.

sensor = DistanceSensor([1.0, 0.6])
robot = Robot()
d = sensor.distance
if d < 0.2:
    robot.stop()
else:
    robot.forward()

d is 1.0, which is NOT < 0.2, so the else branch runs.

linevalue / result
d = sensor.distanced = 1.0
if d < 0.21.0 < 0.2 is False
else: robot.forward()left motor forward
right motor forward

44. Fill in: value / result for One driver step

Comparison

Comparison matrix

From One driver step: refill the value / result column from what you know. The rest of the table is as it appeared.

linevalue / result
d = sensor.distanced = 1.0
if d < 0.21.0 < 0.2 is False
else: robot.forward()left motor forward
right motor forward

45. The full driver loop (full trace)

Worked example

Now loop over four readings: [1.0, 0.6, 0.15, 0.4]. Each pass reads the next distance and decides. Watch the one reading below 0.2 trigger the stop.

sensor = DistanceSensor([1.0, 0.6, 0.15, 0.4])
robot = Robot()
for i in range(4):
    d = sensor.distance
    if d < 0.2:
        robot.stop()
    else:
        robot.forward()

Only 0.15 is below the 0.2 threshold, so only pass 3 stops.

passd (meters)d < 0.2?actionprints
11.0Falseforward()left motor forward / right motor forward
20.6Falseforward()left motor forward / right motor forward
30.15Truestop()left motor stop / right motor stop
40.4Falseforward()left motor forward / right motor forward

46. Something is wrong here: memorizing gpiozero instead of seeing the shape

Anomaly

Predict first

A student writes this, and it looks reasonable:

Panicking that real gpiozero is a huge new thing you must memorize.

It is wrong. Say what breaks — and say it before you turn the page.

Correct: Treats the library as trivia. You'll forget it, and you'll miss that it's the same object shape you already know.

Recognize the shape; look up the names when you need them.

Why: Treats the library as trivia. You'll forget it, and you'll miss that it's the same object shape you already know.

47. Trap: memorizing gpiozero instead of seeing the shape

Trap

The trap

Panicking that real gpiozero is a huge new thing you must memorize.

Try to memorize every class and method name

Why: Treats the library as trivia. You'll forget it, and you'll miss that it's the same object shape you already know.

Also forget distance is in METERS and use 20 as the threshold

Why: A units slip: real distance is 0 to 1 in meters, so d < 20 is always true - the robot would never roll.

The fix

Recognize the shape; look up the names when you need them.

See Motor/DistanceSensor/Robot as objects: make them, call methods, read attributes

Why: That's the whole skill. Real gpiozero is Robot(), .forward(), sensor.distance - the same moves.

Keep the threshold in meters: d < 0.2

Why: 0.2 m = 20 cm. Match your numbers to the sensor's units and the logic works.

48. Which of these survive contact with Hardware as Objects: a gpiozero Preview?

Two truths and a lie

Sort into buckets

Some of these hold up and some are the exact mistakes this lesson is built to prevent. Sort them.

Holds up
The library robots use at camp is called gpiozero. It gives you objects with names like Robot, Motor, and DistanceSensor.; Four stops, each one a piece of the same picture you already know:; A real motor spins a wheel. In code, that motor is an object: you make one and reach into it with a dot, just like the Rover.
Breaks
You add () to the distance, as if reading the sensor were an action.; Panicking that real gpiozero is a huge new thing you must memorize.
sound
These are stated as this lesson states them — each one survives the edge cases Hardware as Objects: a gpiozero Preview puts it through.
flawed
Each of these is lifted from a trap in this deck: reasonable-sounding, and wrong in a way that only shows up once you rely on it.

49. How sure are you: Check: which reading stops the robot?

Commit first

Predict first

In the driver loop over [1.0, 0.6, 0.15, 0.4] with if d < 0.2: stop(), on which pass does the robot STOP?

Commit to an answer, then rate it — certain, fairly sure, or guessing — and write the rating down before you turn the page.

Correct: Pass 3 (d = 0.15)

Why: 0.15 is the only reading below the 0.2 threshold, so 0.15 < 0.2 is True and stop() runs on pass 3. The other readings are all >= 0.2, so they roll forward.

The rating matters as much as the answer: confident-and-wrong is the combination that survives revision, because nothing about it feels like it needs revisiting.

50. Check: which reading stops the robot?

Check

Threshold is 0.2 meters. Readings come in order: 1.0, 0.6, 0.15, 0.4.

Check your understanding

In the driver loop over [1.0, 0.6, 0.15, 0.4] with if d < 0.2: stop(), on which pass does the robot STOP?

  • A. Pass 3 (d = 0.15) (correct)
  • B. Pass 2 (d = 0.6)
  • C. Pass 4 (d = 0.4)
  • D. It never stops

Answer: A

Why: 0.15 is the only reading below the 0.2 threshold, so 0.15 < 0.2 is True and stop() runs on pass 3. The other readings are all >= 0.2, so they roll forward.

Why B tempts people
0.6 is bigger than 0.2, so 0.6 < 0.2 is False - the robot rolls forward on pass 2, it doesn't stop.
Why C tempts people
0.4 is also bigger than 0.2, so pass 4 rolls forward. The robot already had its close call on pass 3.
Why D tempts people
0.15 IS below 0.2, so the stop condition fires on pass 3. It does stop - just once.

51. Answer it before you see the options: Check: read the if/else

Prediction

Predict first

sensor = DistanceSensor([0.6]) robot = Robot() d = sensor.distance if d < 0.2: robot.stop() else: robot.forward() What prints?

Answer it in your own words, now, with nothing to choose from. The options are on the next slide — and picking the right one off a list is an easier skill than producing it.

Correct: left motor forward / right motor forward

Why: d is 0.6. 0.6 < 0.2 is False, so the else branch runs: robot.forward() fires both motors, printing left motor forward then right motor forward.

52. Check: read the if/else

Check

One driver step. The first reading from this sensor is 0.6.

Check your understanding

sensor = DistanceSensor([0.6])
robot = Robot()
d = sensor.distance
if d < 0.2:
robot.stop()
else:
robot.forward()

What prints?

  • A. left motor forward / right motor forward (correct)
  • B. left motor stop / right motor stop
  • C. Nothing - 0.6 doesn't match either branch
  • D. TypeError: 'float' object is not callable

Answer: A

Why: d is 0.6. 0.6 < 0.2 is False, so the else branch runs: robot.forward() fires both motors, printing left motor forward then right motor forward.

Why B tempts people
stop() runs only when d < 0.2 is True. 0.6 is not below 0.2, so the if branch is skipped and forward() runs instead.
Why C tempts people
An if/else always takes exactly one branch - if the if is False, the else runs. forward() prints; nothing is silent here.
Why D tempts people
That error comes from sensor.distance() with parentheses. Here distance is read correctly with no (), so there's no crash.

53. Rule out three: Check: what is this lesson for?

Elimination

Eliminate the wrong options

What's the right takeaway from this gpiozero preview?

3 of these 4 are wrong. Strike them one at a time, and say what rules each one out before you strike the next. The survivor is the answer.

  • A. Recognize that motors and sensors are objects - make them, call methods, read attributes; the camp robot teaches the details
  • B. Memorize every gpiozero class and method before camp, or you'll be lost
  • C. gpiozero works completely differently from the Rover, so forget what you learned
  • D. Sensors are called like methods: sensor.distance()

Survives elimination: A

Why: This is a familiarity preview, not a memorization test. The win is recognizing the object shape you already know - make it, call methods, read attributes - so the real robot feels familiar, not foreign.

54. Check: what is this lesson for?

Check

Be honest about the goal - it changes how you study this.

Check your understanding

What's the right takeaway from this gpiozero preview?

  • A. Recognize that motors and sensors are objects - make them, call methods, read attributes; the camp robot teaches the details (correct)
  • B. Memorize every gpiozero class and method before camp, or you'll be lost
  • C. gpiozero works completely differently from the Rover, so forget what you learned
  • D. Sensors are called like methods: sensor.distance()

Answer: A

Why: This is a familiarity preview, not a memorization test. The win is recognizing the object shape you already know - make it, call methods, read attributes - so the real robot feels familiar, not foreign.

Why B tempts people
It's a preview for familiarity, not mastery. You look library names up; what matters is recognizing the shape, which you already have.
Why C tempts people
It's the SAME shape as the Rover - objects with methods and attributes. That's the entire point; nothing you learned is wasted.
Why D tempts people
distance is data you read with no parentheses. Calling it with () is the exact trap that crashes with 'float' object is not callable.

55. Your Turn: Maze Rover Driver

Section

Section 4 · build it yourself

56. The build: drive on sensed distance

Concept

You'll write a driver for the Maze Rover: it rolls forward but stops when the wall gets too close. The fake DistanceSensor, Motor, and Robot are given to you. Type every line yourself, run after each one, and read errors - don't erase them.

#do thistool you'll use
1make a sensor from a list of readingsDistanceSensor([...])
2loop and read the distance each passfor, sensor.distance
3stop when too close, else go forwardif d < 0.2, robot.stop()/forward()
4run it over four readingsthe full loop

57. Milestone 1 — make a sensor and read it

Worked example

Your turn: make a DistanceSensor from [1.0, 0.6, 0.15, 0.4] and print its first reading. Say out loud what number you expect before you run it.

Hint: DistanceSensor([...]) builds it; read .distance with no parentheses.

sensor = DistanceSensor([1.0, 0.6, 0.15, 0.4])
print(sensor.distance)
lineprints
print(sensor.distance)1.0

58. Milestone 2 — loop and read each pass

Worked example

Your turn: loop four times, reading the next distance each pass and printing it. Predict the four numbers first.

Hint: a for i in range(4): loop; inside it, d = sensor.distance reads the next one.

sensor = DistanceSensor([1.0, 0.6, 0.15, 0.4])
for i in range(4):
    d = sensor.distance
    print(d)
passprints
11.0
20.6
30.15
40.4

59. Watch it run: Milestone 2 — loop and read each pass

Pattern

Step through it

Step through Milestone 2 — loop and read each pass one row at a time. What is driving the change, and what would the row after the last one be?

  1. Step 1: pass is 1
  2. Step 2: pass is 2
  3. Step 3: pass is 3
  4. Step 4: pass is 4

60. Milestone 3 — add the stop condition

Worked example

Your turn: make a Robot, and inside the loop decide: stop if d < 0.2, else go forward. Predict which pass stops before running.

Hint: the tool is if d < 0.2: calling robot.stop(), with else: calling robot.forward().

robot = Robot()
d = 0.15
if d < 0.2:
    robot.stop()
else:
    robot.forward()
dd < 0.2?prints
0.15Trueleft motor stop
right motor stop

61. What each one costs: Milestone 3 — add the stop condition

Trade off

Comparison matrix

From Milestone 3 — add the stop condition: every row here is a choice with a cost. Fill the prints column, then say which row you would actually pick and what you give up for it.

dd < 0.2?prints
0.15Trueleft motor stop
right motor stop

62. Milestone 4 — full driver program

Worked example

Your turn: put it together - sensor, robot, loop, decide. Predict the full output before running.

sensor = DistanceSensor([1.0, 0.6, 0.15, 0.4])
robot = Robot()
for i in range(4):
    d = sensor.distance
    if d < 0.2:
        robot.stop()
    else:
        robot.forward()
passdprints
11.0left motor forward / right motor forward
20.6left motor forward / right motor forward
30.15left motor stop / right motor stop
40.4left motor forward / right motor forward

If pass 3 is the only stop in your output - you just wrote an autonomous driver.

63. Fill in: prints for Milestone 4 — full driver program

Comparison

Comparison matrix

From Milestone 4 — full driver program: refill the prints column from what you know. The rest of the table is as it appeared.

passdprints
11.0left motor forward / right motor forward
20.6left motor forward / right motor forward
30.15left motor stop / right motor stop
40.4left motor forward / right motor forward

64. Show it off

Worked example

Explain your driver out loud: point to the line that senses (reads sensor.distance, no parentheses) and the lines that act (call robot.stop() / robot.forward(), with parentheses).

The real camp robot's code looks almost identical: from gpiozero import Robot, DistanceSensor, then the same make it, read distance, if too close stop loop. You've already written the shape.

You can now beat both of today's traps: sensor.distance() with parentheses crashes (data isn't an action), and gpiozero isn't trivia to memorize - it's the object shape you already know, in meters.

65. Connect it up: Hardware as Objects: a gpiozero Preview

Connect it up

Draw it

One page, no notation unless you need it: draw how these connect — Hardware Is Just Objects · Sensing — Data Coming In · The Driver Loop · Your Turn: Maze Rover Driver. Put an arrow wherever one of them is what makes another possible, and label the arrow with why.

66. What you can do now

Recap

you want to...you write
make a motorm = Motor("left")
act (drive)robot.forward() (parens)
sense (read)sensor.distance (no parens)
decideif d < 0.2: robot.stop()

Next time (Lesson 8): the finale - we put the whole camp together and build a small object-oriented robot brain from scratch.

Sources

  1. gpiozero API - Robots (Robot, motors as objects with forward()/stop())
  2. gpiozero API - Input Devices (DistanceSensor.distance, a value you read in meters)
  3. All snippets executed on CPython 3.12; output copied verbatim. Author verification run, 2026-06-24 (Pre-COSMOS Lesson 7 of 8). — Author verification run, 2026-06-24 (Pre-COSMOS Lesson 7 of 8).

Want this taught 1-on-1? Alexander tutors Python — $55/session, free consultation.

Book on Wyzant · Text (657) 465-8108