Unit 4 · Big Idea 1
The Model
Student Lab · Teaching the Robot to Predict Distance
Student PIN:
Overview
Up to now, when you wanted the robot to drive somewhere, you guessed at a count and tested until it looked right. That works, but it’s slow — and the ticks mean nothing to a human. Today you’ll teach your robot something powerful: the relationship between ticks and inches. Once it knows that, you can tell it to drive “12 inches” and it will predict the right number of ticks on its own. You’re building a model — and that’s one of the most important ideas in all of robotics and AI.
Core Insight
A model is a relationship the robot can use to predict. If it knows how many ticks make one inch, it can predict the ticks for any distance — without guessing.
By the end of this activity you will be able to:
- Use division to build a number with a decimal part, and understand why that precision matters.
- Explain what
ticks_per_inchis and why it’s a model. - Build a calibration that measures your robot’s
ticks_per_inch. - Write a
Drive(inches)function that predicts ticks from inches, converting the result deliberately.
Phase 1 — New Tool: Division Keeps Its Decimal
The relationship between ticks and inches won’t be a whole number — it might be 41.7 ticks per inch. When you divide two numbers with /, Python keeps the full decimal result automatically. You don’t have to ask for it or set anything up — it just happens:
print(250 / 6) # The decimal is kept: 41.666666666666664.Whole numbers (like 250 and 6) are called ints. A number with a decimal point (like 41.7) is called a float. You can check which one you have with type():
print(type(250)) # <class 'int'>
print(type(250 / 6)) # Division produced a float: <class 'float'>.Division keeps the decimal for free. Going back to a whole number does not happen automatically — you have to choose how. Python gives you two tools for it, and they don’t agree:
print(int(41.7)) # This prints 41 by removing everything after the decimal point.
print(round(41.7)) # This prints 42 by rounding to the NEAREST whole number.int() always rounds down toward zero, no matter how close the decimal is to the next whole number — even int(41.99) is still 41. round() looks at the decimal and picks whichever whole number is actually closer. For something like a predicted tick count, that difference is a real, measurable amount of driving distance — so which one you pick actually matters.
Why would using int() to convert every predicted tick count introduce a small, consistent error in one direction? Use the 41.7 example.
Phase 2 — Concept: A Model Is a Relationship
Your counts ticks. You measure the world in inches. A model connects the two with a single number: how many ticks happen in one inch.
ticks_per_inch = ____ # the MODEL: ticks in a single inchIf you drive a known distance and count the ticks, you can compute that number:
The model is built by dividing
Example: if the robot counted 250 ticks while traveling 6 inches, then ticks_per_inch = 250 ÷ 6 = 41.7
Flip the math around, and the model predicts ticks for any distance you want:
ticks = inches * ticks_per_inch # predict ticks for ANY distanceWant to drive 12 inches? Predict: 12 × 41.7 = 500 ticks. No more guessing — the model does the work.
In your own words, what does ticks_per_inch let the robot do that a plain tick count never could?
Phase 3 — Build: The Calibration Function
To find your robot’s ticks_per_inch, you let the robot measure itself. Set the robot against the back wall of the right starting box, with the black line ahead of it. The robot drives straight forward until its Tophat reaches the black line, counting ticks the whole way. You measure the real distance it traveled, in inches, and the function does the division.
Measure first
Before running, use your ruler to measure the distance from where the Tophat sensor starts (robot against the back wall) to the black line. That real-world distance, in inches, is what you’ll pass into the function.
#!/usr/bin/python3
# Unit 4, Big Idea 1: The Model
# Name: _______________________ Date: ___________
import os, sys
sys.path.append("/usr/lib")
import _kipr as k
MIDPOINT = ____ # your Tophat threshold from before
ticks_per_inch = 0 # Calibration will set this model value.
def main():
global ticks_per_inch
# robot starts against the back wall of the right starting box
calibrate_ticks_per_inch(____) # pass in YOUR measured inches to the line
print(f"ticks_per_inch = {ticks_per_inch}") # see your model
def calibrate_ticks_per_inch(inches):
global ticks_per_inch
k.cmpc(0) # clear the tick counter
while k.analog(0) < MIDPOINT: # drive while sensor sees WHITE (low)...
k.motor(0, 50) # ...straight forward...
k.motor(3, 50)
# ...stops when it hits BLACK (high)
k.motor(0, 0); k.motor(3, 0); k.msleep(50) # brake
ticks_per_inch = k.gmpc(0) / inches # MODEL = ticks measured / inches known
main()Remember your convention: black reads higher than white, so k.analog(0) < MIDPOINT is true on white and the robot keeps driving — then stops the instant it crosses onto black.
Record Your Calibration
| Measurement | Value |
|---|---|
| Inches you measured (sensor start → black line) | |
| Ticks the robot counted (gmpc 0) | |
| ticks_per_inch the program printed |
Check the math yourself
Does your hand calculation match what the program printed? It should.
Phase 4 — Build: The Drive Function
Now the payoff. With ticks_per_inch known, Drive takes a distance in inches, predicts the ticks, and drives. You command in human units; the model handles the rest. Notice the predicted ticks come out as a decimal — Drive has to deliberately convert that before it can count against it.
def Drive(inches):
ticks = round(inches * ticks_per_inch) # PREDICT ticks from the model, then round to a whole tick
k.cmpc(0) # clear the counter
while k.gmpc(0) < ticks: # drive until we reach the predicted ticks
k.motor(0, 50)
k.motor(3, 50)
k.motor(0, 0); k.motor(3, 0); k.msleep(50) # brakeTest it: after calibrating, call Drive(12.0) and measure how far the robot actually went. Then try a few more distances.
| Try | You asked for (inches) | Actual distance traveled (inches) |
|---|---|---|
| 1 | 12.0 | |
| 2 | ||
| 3 | ||
| 4 |
How close was the actual distance to what you asked for? If it was off, what might make the prediction imperfect?
Phase 5 — A Model Can Go Stale
⚠ Your ticks_per_inch will change over time
The number you just measured is true right now — but it won’t stay true forever. Your ticks_per_inch can drift as your robot changes:
- Battery level — a fresh battery drives stronger than a low one, changing how far each tick carries.
- Grease and wear in the motors — a freshly greased or broken-in motor behaves differently than a dry or stiff one.
- Motor aging — over weeks and months, motors simply change.
So if your driving starts going long or short for no obvious reason, recalibrate. Running your calibration function again rebuilds the model for your robot’s condition today.
To keep track, add a comment to your ticks_per_inch variable with the last date you calibrated it.
Your robot was driving perfectly last week, but today it always stops a little short. Nothing in your code changed. What probably happened, and what should you do?
Phase 6 — Add to & Connect
Add ticks_per_inch, calibrate_ticks_per_inch, and Drive to your library, fully commented. From now on you can drive in inches in any mission.
AI Literacy Thread
Intelligent systems use models to predict what should happen next.
You just built a model and used it to predict. This is everywhere in intelligent systems: a weather model predicts tomorrow’s temperature; a self-driving car models how far it travels at a given speed; an AI predicts the next word from patterns it measured. And like your ticks_per_inch, real models must be recalibrated when the world changes — a model trained on old data slowly stops matching reality. Measuring a relationship, using it to predict, and refreshing it when conditions shift is the heartbeat of how machines reason about the world.
Read each scenario. Think it through, then write your answer.
A plain tick count only works for one exact distance. Why is a model like ticks_per_inch more powerful than memorizing tick counts for each distance?
Real AI models also go stale and need retraining when the world changes. How is that like recalibrating your ticks_per_inch?
Phase 7 — Individual Reflection
Complete this section on your own.
1. Why does dividing with / keep the decimal automatically, but converting a decimal back to a whole tick count take a deliberate choice? Why did Drive use round() instead of int()?
2. Explain how the calibration function builds the ticks_per_inch model.
3. How does Drive use the model to predict ticks from inches?
4. Complete in 2–3 sentences: “Intelligent systems use models to predict what should happen next. This means a robot can plan its actions by…”
Extension Challenges
Finished early? Try one or more of these.
Extension A — Calibrate Twice
- Run your calibration two or three times and compare the
ticks_per_inchvalues. Are they identical? What does the spread tell you about measurement?
Extension B — Low Battery Test
- If you can, calibrate with a full battery and again with a lower one. Did
ticks_per_inchchange? By how much?
Extension C — A Turn Model
- Your turns still use raw ticks. Could you build a
ticks_per_degreemodel the same way, so you could callTurn(90.0)? Sketch how you’d measure it.
Extension D — Rewrite a Mission in Inches
- Take your double-stack mission and replace the raw
Tick_Drivecalls withDrivein inches. Is the mission easier to read and plan now? Why?
Extension E — The Same Idea, Somewhere Else
- The calibration idea you built today — measure once, build a numeric model from that measurement, then reuse the model going forward — isn’t unique to robots.
- Name two other fields (cooking, medicine dosing, engineering, sports, anything) where that same idea would apply, and explain one of them in 2-3 sentences.
Extension F — Average Your Calibration
- You calibrated 2-3 times in Extension A and got slightly different
ticks_per_inchvalues each time. Write a few lines of code that take those readings and compute their average (sum divided by count) instead of eyeballing which one to use. - Use that averaged value as your real
ticks_per_inchgoing forward. Does it change your accuracy on a test drive?
Extension G — Type In a Test Value
- This extension requires running the program manually via SSH or the terminal. While testing (not during a competition run), use
input()to read a number typed by a teammate instead of hard-coding it.input()always gives you back text, even if someone types a number — wrap it infloat()to turn that text into an actual decimal number you can do math with.
distance = float(input("Enter a distance to drive (inches): "))
Drive(distance)- Try it for a couple of different distances. Why is typing in a test value faster for testing than editing your code and re-running it each time?
When you are finished, press the button to turn in your work and save a copy.
KIPR · Botball Explorer · Unit 4 Big Idea 1 — Student Lab