The Basketball Robot: a driving base with a spring-loaded launcher on a Medium Motor, and an Ultrasonic Sensor that measures how far away the hoop is.
Everything you have built since Lesson 5 could fix its own mistakes while it was making them. This one cannot. The instant the ball leaves the launcher, the program has no influence over where it lands.
By the end of the lesson your robot will spend all its accuracy before the shot and none after it — which is the right answer whenever a machine has one chance.
In the real world 5 min
Where you have seen it
A free throw is the same shot every time: same distance, same spot, nobody defending. Professionals still miss around a quarter of them. The reason is not that they cannot see the hoop — it is that once the ball leaves the fingertips, there is nothing left to do.
Mustafa Shakur shooting a free throw. Photo: Eric Chan / Wikimedia Commons (CC BY 2.0).
So all the work goes before the release. Watch a player’s routine: the same number of bounces, feet in the same place, the same breath. They are not superstitious — they are making the one uncontrollable moment as repeatable as they can.
Why it is built that way
Engineers call it a ballistic action: launched, then left to physics. A thrown ball, a fired dart, a stamped part, a poured casting — all of them have a moment after which the machine is a spectator.
The response is always the same shape. Be as accurate as possible up to the commit point, make the committed action as repeatable as possible, and then measure the result so the next one can be better.
What would go wrong without it
A machine that assumes it can always correct will leave its accuracy until too late — aiming while it launches, adjusting while it pours. Everything it does after the commit point is wasted effort, and the effort it should have spent beforehand was not spent.
Find the moment after which nothing can be changed. Put all your accuracy before it.
The main concept — where the loop stops working 6 min
A closed loop needs three things: a target, a measurement, and the ability to still do something about it. Take away the third and it is not a loop at all — it is a launch.
Part of the shot
Can it be corrected while it happens?
So use
Driving to the shooting spot
Yes — the sensor sees the hoop the whole way.
Closed loop (Lesson 5)
Aiming the launcher
Yes — the motor holds a position it can adjust.
Closed loop + mapping (Lesson 17)
The launch itself
No. Nothing can reach the ball.
Open loop, made as repeatable as possible
The ball in flight
No. Physics owns it.
Watch, and learn for the next shot.
The commit point is where the sensor stops being connected to the outcome. Before it, measuring helps. After it, measuring only tells you what happened — which is still worth having, but it is a different thing from control.
What replaces feedback
You cannot correct a launch, so the only remaining lever is repeatability — Level 2’s closing question. If the same command produces the same shot every time, then one adjustment fixes every future shot. If it does not, no adjustment fixes anything.
Symptom over five shots
Diagnosis
What to do
All five land in the same wrong place
Repeatable and mis-set. Good news.
Change one number; all five move together.
Five scattered landings
Not repeatable.
Fix the machine, not the number — a loose arm, a ball that sits differently, an inconsistent start position.
The pre-shot routine
Everything a player does before releasing has a direct equivalent here, and each one removes a source of variation:
Home the launcher against a stop, so every shot starts from the same place — not from wherever the last one ended.
Drive to a measured distance with a closed loop, so the range is the same every time rather than roughly right.
Stop completely and pause. A robot still rocking from its approach launches at whatever angle it happens to be at.
Then commit — one launch, full speed, no conditions inside it.
ComponentMotion4 min
Brake or coast
Telling a motor to stop does not say how it should stop. There are two very different behaviours, and which one you want depends entirely on what the mechanism is holding up.
Brake — the motor actively holds its position. A lifted arm stays lifted; a robot stops dead where it is.
Coast — the motor lets go. A lifted arm sags under its own weight; a moving robot rolls on a little before stopping.
When this motor is told to stop, it either holds its shaft still or lets it spin freely. Which one it does is the whole of this module.
Watch what happens after the stop
Both arms below are lifted by the same program and stopped at the top. The only difference is one word in the stop block. Everything worth seeing here happens after the movement has finished.
when program starts
A run clockwise for 1rotations
A stop motor brake
the only change on the other arm
A stop motor coast
0%braked, held0%coasting
Brake: still where it was putCoast: back on the floor
Two identical arms, each with a weight on the end.Both motors lift their arm to the top. So far the two are the same.Both are now told to stop — one set to brake, the other set to coast.The braked arm holds. The coasting arm lets go and falls under the weight.Same lift, same stop block, opposite results.Finished — it will run again in a moment.
stopped
If a mechanism you just lifted sags the moment it stops, the stop action is the first thing to check — not the lifting movement.
The coasting arm does not slide down steadily — it starts slowly and picks up speed, because it is gravity pulling it and not a motor lowering it. That is also why a coasting robot rolls a little past where its measured movement ended.
Which to choose
If gravity is pulling on the mechanism, you almost always want brake — otherwise the thing you just lifted comes back down on its own. If you want a smooth, natural halt, or you want to be able to push the robot by hand afterwards, coast is friendlier.
Coasting also makes a robot travel slightly further than its measured movement, because it keeps rolling after the motor has finished. On a precise task that error matters.
Why it matters
A crane must brake — a coasting crane drops its load. A train coasts into a station rather than stopping dead, because passengers would be thrown forward. The same choice, made differently, for good reasons.
ComponentSensing6 min
The Ultrasonic Sensor
The Ultrasonic Sensor measures distance. It sends out a burst of sound too high for people to hear, listens for the echo, and works out how far away the surface is from how long the echo took — exactly how a bat finds a moth, and how a submarine uses sonar.
front
side
The two round openings on the front are the point of this sensor: one sends the burst of sound out, the other listens for the echo coming back.
Blocks reference
Block
What it does
([4 v] distance in [cm v] :: sensors)
Reports how far away the nearest thing in front of the sensor is, as a number in centimetres.
wait until <([4 v] distance in [cm v] :: sensors) < (15)>
Holds the program until something comes closer than 15 cm.
A number, not a yes or no
This is the important step up from the Touch Sensor. Touch gives you true or false; the Ultrasonic gives you a number, and the deciding is left to you. Pick a threshold below and watch where the robot ends up.
when program starts
start moving straight: 0
4 wait until distance <15cm
stop moving
60cm · reading15cm · threshold
Nothing is close. The sensor reports about 60 cm and the program waits.The robot drives forward. The sensor is sending a burst of sound and timing its echo, over and over, and the number falls.The reading has dropped past the threshold. The condition is true, so the robot stops.Try another threshold. The program is identical — only that one number is different.Finished. The threshold is yours to choose — the sensor only supplies the number.
stopped
The black line on the bar is the threshold; the blue fill is the reading. The robot stops the instant the fill crosses the line.
Three different robots, and only one number is different between them. That is what having a number rather than a yes-or-no buys you: the behaviour is tuned by editing one slot, not by rebuilding the program. It also means the sensor can never tell you it is “close” — close is a decision you make about a reading.
Why it matters
Car parking sensors, automatic doors at a shopping centre, and the sensor that stops a lift door closing on somebody all work this way. Reacting before contact is what makes a machine feel safe.
If your set has an Infrared Sensor instead
The Home/Retail EV3 set (31313) ships an Infrared Sensor and a Beacon in place of the Ultrasonic and Gyro sensors. The Infrared Sensor also measures distance, so the programs in this module work with it — but it reports a rough 0–100 proximity rather than real centimetres, and it is affected by sunlight and by dark surfaces in ways the Ultrasonic is not.
IR Sensor
Beacon
The Infrared Sensor and its Beacon, from the Home set. If your kit has these, expect proximity numbers rather than centimetres — and retune any threshold accordingly.
ComponentData6 min
Variables
Why anybody needs one
Long before there were computers, people had exactly this problem. A shepherd counting sheep through a gate, a trader counting sacks of grain, a builder counting days — none of them can hold the number in their head while they get on with the work. So they scratched a mark on a wall, cut a notch in a stick, or wrote a number on a piece of paper. The number lived outside the person, in a place they had agreed on, and they could go back to it, read it, and change it.
Better still, once the number is written down somebody else can use it. Watch these two: one of them counts and writes, the other never sees a single animal and simply reads the wall.
Abby never remembers the numberBen never sees a henThe wall holds it for both
Abby has a gate and a wall. Before a single hen comes through she chalks 0 on the wall — that is where the number is going to live.A hen goes through. Abby rubs out the 0 and chalks 1. Another goes through, and she does it again.Three hens have been through, and the wall says 3. Abby is not remembering the number — she is reading her own wall each time and writing the next one.Ben has been at the market all morning. He has not seen one hen. He walks up, reads the wall, and knows the answer — without asking Abby anything.That is a variable. Not a number in somebody's head, but a place both of them agreed on: one writes to it, the other reads from it, and it keeps the number in between.Finished. Abby wrote, Ben read, and the wall is what joined them up.
the wall holds it
Notice what never happens: Ben never asks Abby. He does not need to — the number is not in her head, it is on the wall, and the wall is there for anyone who needs it.
Neither Abby nor Ben is holding the number — the wall is. And notice what never happens: Ben does not ask Abby. He does not need to, because the count is not in her head. It is in a place they both agreed on, which is what makes it useful to more than one of them.
That is all a variable is. The robot cannot hold a number in its head either, so you give it a wall of its own, write a name at the top so everyone knows which wall is which — score, count, degree_turn — and the program can read what is on it and write something new. One part of the program writes; another part reads. Exactly Abby and Ben.
The paper, and the two things you can do to it
Say we are counting rotations of a motor. Before we start we write 0 on the paper. Every time the motor completes a turn we cross out what is there and write one more: 0 becomes 1, then 2, then 3. That is change — it has to read the old number to work out the new one.
set is the other thing you can do, and it is completely different: rub the whole paper out and write the number you want. It does not care what was there. Press the buttons and watch what happens to the crossings-out.
score
0
The paper starts blank, so we write 0 on it. That is what a variable is: a place to keep a number while the robot works.
change leaves a trail — every value follows from the one before it. This is what counting is.
set wipes the sheet. Use it to start a count, never to continue one.
Press set score to 0 after counting up a few times and watch the whole history vanish. That is what happens to a count when a set block ends up in the wrong place — and it is the commonest variable bug there is.
Blocks reference
Block
What it does
set [count v] to (0)
Puts a value in, replacing whatever was there.
change [count v] by (1)
Adds to what is already there.
(count)
Reports the current value, for use in a comparison or on the display.
Set, or change?
set replaces; change adds. Counting things needs change. Starting a count needs set. Both programs below have both blocks — the only difference is whether the set block is inside the loop or above it.
set before the loop
when program starts
set count to 0
repeat 4
A run clockwise for 1rotations
change count by 1
set inside it
repeat 4
set count to 0
A run clockwise for 1rotations
change count by 1
Before the loop: counted 0Inside the loop: stuck at 0
Both programs count the turns of a motor. The left sets the count to zero before the loop; the right sets it inside.Turn 1. Both counters read 1, and so far the two programs agree.Turn 2. The left count is 2. The right was set back to zero at the top of the loop, so it is 1 again.Turn 3. The left reads 3. The right still reads 1.Turn 4. The motor turned four times on both robots — only one of them counted them.Finished. Four turns, and one of the two counts is fiction.
stopped
Both programs contain both blocks. Only the position of set [count] to 0 is different.
The count on the right is not broken; it is being told to start again on every pass. Each time round the loop it is wiped back to zero and then changed by one, so the honest answer is always 1 — while the motor cheerfully turns four times. A counter stuck at 1 almost always means a set block that has slipped inside the loop.
Anything oval is a number you can pick up
EV3 Classroom tells you what a block does by its shape, and once you have noticed that, a whole set of questions answers itself:
Oval — reports a number. The blue degrees counted, the timer, a distance, your own variable.
Pointed — reports true or false. These go in an if or a wait until, not in a variable.
Block-shaped — does something. These stack up; they do not fit inside anything.
So when a slot is oval, any oval fits it — and it does not matter in the least where that number came from. You can take the motor’s own A degrees counted and keep it in a variable you named degree_turn, then compare that with a number later. Pick an oval below and watch the same one drop into all three kinds of slot.
pick an oval
the same oval fits all three
set degree_turn to A degrees countedkeep it in a variable of your own
A degrees counted+10do arithmetic with it
A degrees counted>50compare it with a number
Every one of those slots is oval-shaped, and A degrees counted is an oval — so it drops in. Nothing about where the number came from matters.
This is what makes a variable more than a counter. A sensor reading is true only at the instant you read it; copying it into a variable freezes it, so the robot can compare where it is now against where it was when something happened:
when program starts :: events hat
[A v] reset degrees counted :: motors
set [degree_turn v] to ([A v] degrees counted :: sensors)
start moving [right: 30] :: movement
wait until <(([A v] degrees counted :: sensors) - (degree_turn)) > (400)>
stop moving :: movement
Read the condition aloud: how far the motor has gone now, minus where it was when we started, is more than 400. Both are ovals, so both can go into a subtraction, and the subtraction is an oval too — which is why it can go into a comparison. Ovals nest inside ovals as deep as you need.
Reset at the start, every time
A variable keeps its value after the program ends. Run the program again without setting it back and the second run begins where the first left off — the count starts at 14, the robot thinks it has already done the job. Every variable a program changes must be set to its starting value at the top.
Why it matters
A variable is the difference between a machine that repeats a fixed routine and one that responds to how things have gone — counting parts, tracking a score, remembering where it started.
Closed loop up to the commit point. Repeatable open loop after it. Measure the result to improve the next one.
▶RepeatabilityFrom Level 2, Lesson 48 — spread first, then aim. It is what you have instead of feedback.Show meHide
ComponentMotion4 min
Brake or coast
Telling a motor to stop does not say how it should stop. There are two very different behaviours, and which one you want depends entirely on what the mechanism is holding up.
Brake — the motor actively holds its position. A lifted arm stays lifted; a robot stops dead where it is.
Coast — the motor lets go. A lifted arm sags under its own weight; a moving robot rolls on a little before stopping.
When this motor is told to stop, it either holds its shaft still or lets it spin freely. Which one it does is the whole of this module.
Watch what happens after the stop
Both arms below are lifted by the same program and stopped at the top. The only difference is one word in the stop block. Everything worth seeing here happens after the movement has finished.
when program starts
A run clockwise for 1rotations
A stop motor brake
the only change on the other arm
A stop motor coast
0%braked, held0%coasting
Brake: still where it was putCoast: back on the floor
Two identical arms, each with a weight on the end.Both motors lift their arm to the top. So far the two are the same.Both are now told to stop — one set to brake, the other set to coast.The braked arm holds. The coasting arm lets go and falls under the weight.Same lift, same stop block, opposite results.Finished — it will run again in a moment.
stopped
If a mechanism you just lifted sags the moment it stops, the stop action is the first thing to check — not the lifting movement.
The coasting arm does not slide down steadily — it starts slowly and picks up speed, because it is gravity pulling it and not a motor lowering it. That is also why a coasting robot rolls a little past where its measured movement ended.
Which to choose
If gravity is pulling on the mechanism, you almost always want brake — otherwise the thing you just lifted comes back down on its own. If you want a smooth, natural halt, or you want to be able to push the robot by hand afterwards, coast is friendlier.
Coasting also makes a robot travel slightly further than its measured movement, because it keeps rolling after the motor has finished. On a precise task that error matters.
Why it matters
A crane must brake — a coasting crane drops its load. A train coasts into a station rather than stopping dead, because passengers would be thrown forward. The same choice, made differently, for good reasons.
Say this back before moving on: “After the release, all I can do is watch.”
What’s in this build 4 min
Load and fire the launcher by hand five times. Does the ball sit the same way each time? Every difference you can feel is a shot you will miss.
Part
What it is doing here
EV3 Intelligent Brick
The chassis, and the scoreboard — it will report the measured range and the shot power it chose, so a missed shot can be diagnosed.
Large Motor ×2 — the drive
A movement pair. Their job is entirely before the commit point: putting the robot at a known distance.
Medium Motor — the launcher
The committed action. Medium because a launch is a fast flick, and speed at release is what sends the ball.
Ultrasonic Sensor — range to hoop
Useful right up to the moment of release and useless after it. Worth noticing that a sensor can be excellent and still not help.
The launcher arm and cradle (not electronic)
Where your accuracy is won or lost. A ball that rolls to one side of the cradle leaves at a different angle, and no program can know or fix it.
Spend your build time on the cradle and the stop. A launcher that returns to exactly the same start position, holding the ball in exactly the same place, is worth more than any amount of clever code — because it is the only thing that makes the shot repeatable.
Ports — and the rule 4 min
Sensors go in ports 1, 2, 3, 4. Motors go in ports A, B, C, D. They are not interchangeable, and nothing will tell you politely if you swap them.
Part
Port
Why this one
Launcher (Medium)
A
The committed action gets the first port.
Left drive (Large)
B
The movement pair.
Right drive (Large)
C
The other half.
Range (Ultrasonic)
4
Ultrasonic stays on 4 across the course.
Check your own build now:
Launcher in A, drive in B and C, sensor in 4.
Find the launcher’s home stop and mark it. Every shot begins there, and the program will drive to it before each attempt.
Point the Ultrasonic at the backboard, level, not at the floor or the rim.
Mark a shooting line on the floor with tape. You will be measuring landings against it.
Connect the Brick 4 min
Two routes, and either is fine. USB is the reliable one and the one to fall back on when a room’s Bluetooth is busy; Bluetooth leaves the robot free to move, which some models need.
▶How to connect the BrickUSB and Bluetooth, step by step, with a photograph of every screen. Open it if you have not done this before — or if pairing is not working.Show meHide
USB — the reliable one
Switch the Brick on with the dark grey centre button.
Cable into the Brick’s PC port — the small square socket beside the numbered ports, not one of the numbered ones.
Other end into the computer.
Bluetooth — name it first
Do these in order. Naming the Brick after you go looking for it in the list is how groups end up driving each other’s robots.
Name your Brick. On the Brick: Settings (the spanner) → Brick Name. Type something nobody else will pick, then press the tick. Every Brick is called EV3 until somebody changes it.
Turn Bluetooth on. Settings → Bluetooth. Tick Bluetooth and Visibility. Leave iPhone/iPad/iPod unticked.
Connect from EV3 Classroom. Click the Brick icon at the top of the programming area, find your Brick by name, and click Connect.
Say yes on the Brick. It asks “Connect?” with the computer’s name — choose the tick, then accept the passkey, which is already 1234.
Where to read it. The name sits in the bar across the very top of the screen, on every screen — so you can check which Brick you are holding at any moment without going into a menu. This one is EV3VE. A Brick nobody has renamed says EV3.Step 3, and the reason step 1 exists. Three Bricks in range — read the name before you click Connect. Pairing with the wrong one is not an error: it works perfectly, on somebody else’s robot.
Step 2.Bluetooth switches the radio on; Visibility is what lets the computer find you. With Visibility off your Brick works perfectly and simply never appears in the list.Step 4. Look at the Brick. It asks whether to accept and names the computer. Choose the tick.Then the passkey, already 1234. Press the tick again and you are connected.
The two failures, every class, every time. The Brick has gone to sleep while you were building — press the centre button to wake it. Or you have paired with the group at the next table, which is why the name matters.
The long version, including Port View and how to read the port tiles, is in the Brick & Bluetooth guide.
Bluetooth, and it matters more than usual. Today you are measuring how repeatable the machine is, and a trailing cable adds a slightly different pull on every approach — a source of scatter you invented yourself.
Confirm the connection 2 min
Check the Brick icon: connected, or not.
Three motor tiles — A, B and C.
One sensor tile — 4.
Fire five shots by hand from the same spot at the same launcher power. Mark where each lands. The spread of those five marks is your machine’s honest accuracy before you have written anything — and no program will beat it.
Stuck? The long version, with a photograph of every screen, is in the Brick & Bluetooth guide.
Make it move 10 min
The whole program is a pre-shot routine and one committed action. Notice how much happens before the launch and how little after it.
when program starts :: events hat
set movement motors to [B v] and [C v] :: movement
set [target range v] to (40) :: variables
set [band v] to (2) :: variables
clear display :: display
// ---- BEFORE THE COMMIT POINT: closed loop, correct everything ----
// 1. home the launcher against its stop, so every shot starts identically
[A v] set motor to [hold position v] at stop :: motors
[A v] run [counterclockwise v] for (200) [degrees v] at (20) % speed :: motors
[A v] reset degrees counted :: motors
// 2. drive to a measured distance, correcting all the way
forever
set [range v] to ([4 v] distance in cm) :: variables
set [error v] to ((range) - (target range)) :: variables
write (range) at line (2) :: display
if <([abs v] of (error)) < (band)> then
stop moving :: movement
write [SET] at line (4) :: display
stop [this stack v] :: control
end
start moving [forward v] at ((error) * (2)) % speed :: movement
end
Everything above is correctable, so all of it is a closed loop. The robot does not shoot until it is genuinely at 40 cm.
when I receive [shoot v] :: events hat
// 3. settle. a robot still rocking launches at a random angle
wait (1) seconds :: control
// 4. work out the power from the measured range (Lesson 17)
set [power v] to ((40) + (((range) - (25)) * (((90) - (40)) / ((60) - (25))))) :: variables
if <(power) > (90)> then
set [power v] to (90) :: variables
end
if <(power) < (40)> then
set [power v] to (40) :: variables
end
write (power) at line (6) :: display
// ---- THE COMMIT POINT ----
// one action, full commitment, nothing conditional inside it
[A v] run [clockwise v] for (200) [degrees v] at (power) % speed :: motors
// ---- AFTER: nothing can be changed. only recorded. ----
add (power) to [shots v] :: list
[A v] run [counterclockwise v] for (200) [degrees v] at (20) % speed :: motors
Settle, compute, commit, record. There is not a single sensor read between the launch and the ball landing, because there is nothing one could do.
Homing comes first, always. Without it, shot two starts from wherever shot one finished, and the two are not the same shot.
The one-second settle is doing real work. Take it out and the launch happens while the robot is still rocking from its approach.
Nothing is conditional inside the launch. No sensor check, no adjustment — those would only add variation to the one action that must not vary.
The shot power is recorded. After the commit point, measuring is for the next shot, and a list of what you tried is how that happens.
What success looks like: the robot drives up, stops at 40 cm, pauses, and launches — and five consecutive shots land close together, whether or not they go in.
Landing together matters more than going in, today. A tight group in the wrong place is one number away from correct. A scattered group is a mechanical problem, and changing numbers will not touch it.
Change it and test 8 min
One change at a time. Predict, then run, then look. Fire five shots for each and mark the landings — one shot tells you nothing.
Measure the spread as it stands. Five shots, five marks, measure across them. Write it on the board. That is your baseline.
Remove the homing move. Fire five more. The spread should grow — every shot now starts from a slightly different place.
Remove the one-second settle. Five more. Launching while rocking adds scatter you can see.
Loosen the drive band from 2 cm to 8. The robot now shoots from anywhere in a 16 cm window. Same launcher, much worse shooting — which shows how much of a shot is decided before it.
Now the honest one: adjust for the miss. With homing and settle back in, if the group is short, raise the power mapping by 5 and fire five more. If the group is tight, all five will move together — and that is what repeatability buys you.
Tight and wrong is fixable. Scattered is not. Measure the spread before you change a number.
Where this goes 3 min
There is a wait (1) seconds in your shooting routine, and it is the right thing to do — but look at what it costs.
For that whole second the stack is frozen. It cannot check the sensor, respond to a button, or notice that somebody has walked in front of the hoop. A wait does not pause time; it pauses that stack, and everything that stack was responsible for.
A machine that must keep watching while it waits cannot use a wait block at all. It has to note the time it started and keep going round its loop, checking whether enough has passed — which sounds like a small change and rearranges the whole program.
Waiting is easy and blind. Next: keeping time with your eyes open.
Build it 15 min
Build the model before you read any further. Everything after this is about making it do something, and none of it will make much sense with nothing on the table in front of you.
Use the viewer's own controls to zoom and turn pages. Fullscreen makes it big enough to build from.
Check the finished build against the picture before you switch anything on. A motor mounted the wrong way round is far easier to spot now than it is to debug later, when it looks like a program fault.
Challenges & mission 27 min
Work through the challenges in order — each is harder than the last. The mission comes after all three, and it is meant to make you plan before you build.
Challenge 1
Measure the spread before you aim.
Fire five shots from the same spot at the same power and mark where each lands. Measure across the five marks.
That number is your machine's honest accuracy. Write it on the board — you cannot beat it with any program.
Challenge 2
Prove the pre-shot routine earns its place.
Fire five shots with the homing move removed, then five with the settle removed, then five with both back.
Three spreads, three numbers. Say which of the two mattered more on your machine.
Challenge 3
Tight and wrong, then right.
Get your five shots landing close together, even if they all miss the same way. Then change the power mapping by one step and fire five more.
All five should move together. Explain why that would not have worked if the group had been scattered.
Mission
Score from three different distances with no adjustment between them.
Mark three shooting lines. The robot must drive to each in turn, work out its own shot power from the measured range, and take the shot — with nobody touching a number between attempts.
Two rules:
1. Every part of the shot that CAN be corrected is a closed loop. Every part that cannot is made as repeatable as you can manage. Be ready to point at the exact block where the commit point is.
2. The robot records what it tried at each range, so a miss can be diagnosed rather than guessed at.
The honest measure is not how many go in. It is whether the three groups are tight. A machine that misses consistently at all three ranges is one mapping change from working; a machine that scatters is not fixable by programming at all, and knowing which one you have built is the point of the lesson.
This is what you are building: the Basketball Robot.