How to work

  1. Do the tasks in order; each one adds something to the previous one.
  2. For each task, open a new file in the simulation folder next to the library file (e.g. c_room/task01.c or py_room/task01.py) and include the library.
  3. Start the simulation first, then run your program. Stop programs with an endless loop using Ctrl+C.
  4. When you get stuck, check the hint first; open the answer last.

In this simulation the car always moves at the same speed (about 32 units per second on a straight road). There is no function to change the speed: drive() only sets forward, backward or stop, and steer() changes the direction (-60…+60 degrees). The lidar measures around the car every 2 degrees: lidar_read(0) right, lidar_read(90) front, lidar_read(180) left, lidar_read(270) back. The distance is 1–100 units; if there is no line within 100 units it returns 0.
While driving forward, if a line comes closer than 25 units in the wide area in front of the car (about 66°–114°), the simulation stops the car and collision_read() becomes 1.
Press Restart Sim in the menu before every task: the car starts at the lower part of the right straight of the track, facing up (right line about 15, left line about 52 units away). Ctrl+C stops your program but not the car; stop the car with the Stop button in the Manual Control panel or with Restart Sim.

1 Beginner

Connecting, switching outputs and waiting.
01

Connect and disconnect

See answer

Start the simulation. Write a program that connects to the simulation, prints Hello car! and closes the connection.
Run the program once more while the simulation is closed and look at what it prints.

Hint
sim_connect() returns 0 on success and 1 on failure. If it cannot connect, end the program at once.
sim_connect()sim_disconnect()printf / print
02

Drive forward and stop

See answer

Drive the car forward for 2 seconds and stop it. The car should move up the track a little and stop without hitting a line.

Hint
drive(DRIVE_FORWARD) starts the car, drive(DRIVE_STOP) stops it. To wait in between use Sleep(milliseconds) in C and time.sleep(seconds) in Python.
drive()DRIVE_FORWARDDRIVE_STOPSleep
03

Forward, wait, backward

See answer

Drive the car forward for 2 seconds, stop it for 1 second, then drive backward for 2 seconds and stop. The car should stop close to where it started.

Hint
Use DRIVE_BACKWARD to go backward. Backward the car is as fast as forward.
drive()DRIVE_BACKWARDSleep
04

Turn the steering wheel

See answer

Open the Manual Control panel from the menu. While the car is stopped, turn the steering 30° to the left, wait 2 seconds, turn it 30° to the right, wait 2 seconds and straighten it (0°).
You should see the steering slider and the angle value in the panel change. Does the car move?

Hint
For steer() a positive angle means left and a negative angle means right: steer(30) left, steer(-30) right.
steer()+ left / - right
05

Curve to the left

See answer

Turn the steering 30° to the left, then drive the car forward for 3 seconds and stop it. At the end straighten the steering.
The car should turn left on an arc and should not hit a line.

Hint
Combine Task 2 and Task 4: first steer(), then drive().
steer()drive()Sleep
06

An S-shaped path

See answer

Drive the car in this order:
1 second straight, 2 seconds 20° left, 2 seconds 20° right, 1 second straight, then stop.
The car should draw a path that looks like the letter S.

Hint
You can change the steering while the car is moving; writing drive(DRIVE_FORWARD) once is enough.
steer()drive()sequence

2 Basic

Reading sensors, printing and deciding with if/else.
07

First lidar reading

See answer

Press Restart Sim. Read the front (90°) and right (0°) lidar values and print them:
Front: ... and Right: ...
You should see about 15 for the right side and 0 for the front. What does 0 in front mean?

Hint
lidar_read(angle) returns a number; store it in a variable and print it.
lidar_read()variableprintf / print
08

Four directions and lane width

Your turn

Read and print the right (0°), front (90°), left (180°) and back (270°) distances. Then add the right and left distances to find the width of the road and print it as Lane width: ....
At the start position you should see about 15, 0, 52, 0 and a width of 67.

Hint
The angles are relative to the car and grow counter-clockwise: 0 right, 90 front, 180 left, 270 back.
lidar_read()+angles
09

Lidar scan

See answer

Read the lidar distance every 10 degrees from the right of the car to its left (0° to 180°) and print one angle per line, for example 40 deg: 19.
At which angles do you see 0? Where do these angles point?

Hint
Instead of writing the same line 19 times use a for loop: the angle starts at 0 and grows by 10 up to 180.
forlidar_read()
10

Read the commands back

See answer

Turn the steering 25° to the left and drive the car forward. After 1 second print drive_read() and steer_read() (you should see 1 and 25).
Then stop the car, straighten the steering and print the two values again (0 and 0).

Hint
drive_read() returns 0 = stopped, 1 = forward, -1 = backward.
drive_read()steer_read()
11

Which line is closer?

See answer

Read the right (0°) and left (180°) distances. If the right is closer print Right line is closer, if the left is closer print Left line is closer, and if they are equal print Centered.
At the start the right is closer. Then drive the car a bit to the left with the Manual Control panel, stop it and run the program again.

Hint
Use if, else if (elif in Python) and else for the three cases.
if / elsecompare
12

The zero trap

Your turn

Drive the car straight for 9.5 seconds and stop it. Then read the front distance and print:
Nothing ahead (more than 100) if it is 0,
Line ahead is close: ... if it is less than 50,
otherwise Line ahead: ....
What would happen if the program did not check for 0 first?

Hint
0 is less than 50! So check the 0 case first.
if / else if0 = nothing
13

Collision sensor

See answer

First print collision_read() (it should be 0). Then drive the car straight forward and wait 12 seconds. After the wait print collision_read() and drive_read().
At about 10 seconds the car hits the outer line of the top curve. Which values do you see? Why did the car stop?

Hint
Your program does not stop the car; someone else does.
collision_read()drive_read()

3 Intermediate

Loops, continuous control and tracking state.
14

Stop when you see the line

See answer

Drive the car straight forward. Wait until the front distance is greater than 0 and less than 80, then stop the car and print the last front distance.
The car should stop after about 9.5 seconds without crashing. Using Task 13, explain why we use 80 and not 25.

Hint
You do not know how long to wait, so use a while loop and read the distance again in every round. Wait 20 ms in the loop.
whilelidar_read()&& / and
15

Count the time

See answer

Change Task 14: wait 100 ms in the loop and count how many times the loop runs. When the car stops print Stopped after ... s (counter × 0.1).
You should see about 9.5 seconds. Run the same program a few times (Restart Sim each time): is the result the same?

Hint
The counter is an integer that starts at 0 and is increased by 1 inside the loop.
counterwhile
16

Stay in the middle (side rays)

Your turn

Drive the car forward and in a loop read the right (0°) and left (180°) distances:
if left is more than 5 bigger than right turn 15° left, if right is more than 5 bigger than left turn 15° right, otherwise go straight.
The loop should end when collision_read() is 1 and print Crash!. Wait 50 ms in the loop.
The car moves to the middle on the straight. But what happens in the curve? Watch where it crashes.

Hint
Turn towards the side that has more room. Turning left is a positive angle.
whileif / elsebang-bangcollision_read()
17

Look ahead

See answer

In Task 16 use the diagonal rays instead of 0° and 180°: front right 45°, front left 135°.
This time there are only two cases: if the front left is farther turn 20° left, otherwise 20° right.
The car should zigzag through the curves and keep going around. Stop the program with Ctrl+C and the car with the Stop button.

Hint
A diagonal ray sees the curve before the car gets there: in a left curve the front left opens and the front right closes.
look aheadlidar_read(45)lidar_read(135)
18

Add a dead zone

See answer

Add a third case to Task 17: if the difference between front left and front right is 5 or less, go straight (0°).
The car should drive on the straights without zigzag. Time one lap with a stopwatch: it should be about 72 seconds (about 2 minutes in Task 17).

Hint
Use the three-case structure of Task 16 with the rays of Task 17.
dead zoneif / else if / else
19

Left, right, straight: count

See answer

Run the driver of Task 18 for 600 rounds (about 30 seconds) instead of forever. Count which decision is made in each round: left, right, straight.
At the end stop the car and print the three numbers. In 30 seconds the car passes the straight and most of the top curve; which number is the biggest, and why?

Hint
Define three counters and increase the right one next to every steer() call. The number of rounds is known, so for fits.
forcounters

4 Advanced

Functions, timing, state machines and robustness.
20

Tidy up with functions

See answer

Rewrite Task 18 with two functions:
distance(angle): reads the lidar and returns 100 if it gets 0 (0 = farther than 100).
follow_lane(): gets the 45° and 135° distances with distance() and sets the steering as in Task 18.
Only follow_lane() and the wait should stay in the main loop. The car should drive as in Task 18.

Hint
In C write the functions before main: int distance(int angle) and void follow_lane(void).
functionreturn
21

Find the closest line

See answer

Read all rays from the right of the car to its left (0°–180°, every 2 degrees, 91 values) into an array. Find the smallest non-zero distance in the array and its angle, print it like Closest: 0 deg, 15 and add (right) if the angle is less than 90 or (left) if it is more.
Repeat this every half second. While the program runs, drive the car with the Manual Control panel and watch how the values change.

Hint
Element i of the array is 2 * i degrees. When searching for the smallest, start with a number no reading can reach, like 101.
arrayminimumfor
22

An average instead of one ray

Your turn

Instead of trusting one ray, use the average of several rays. Write a function average(from, to) that reads the angles between from and to every 2 degrees with distance() and returns their average.
In the driver of Task 20 use average(30, 60) for the front right and average(120, 150) for the front left. The car should still go around the track.

Hint
Keep the sum and the number of readings separately; at the end sum / count.
functionparametersaverage
23

Proportional steering (P control)

See answer

Until now the steering was only -20, 0 or +20. Now make the angle proportional to the error:
error = front left (135°) − front right (45°), angle = 0.5 × error.
Write a function limit() that keeps the angle between -60 and +60. The car should go around smoothly without zigzag.

Hint
A big error means a big turn, a small error a small turn, and 0 means straight. Convert the decimal result to an integer ((int) in C, int() in Python).
P controllergainlimit
24

Smooth the error

Your turn

In Task 23, instead of using the error directly, use the average of the last 4 errors. Keep the last 4 errors in an array of 4 elements; in every round write the new error over the oldest one.
The steering should change more calmly and the lap should get a few seconds shorter (about 95 instead of 105 seconds).

Hint
Keep a position number for writing: index = (index + 1) % 4. This way it goes back to 0 after 3.
arraymoving average%
25

Recover after a crash

See answer

The side-ray driver of Task 16 crashed in the curve. Add a recovery behavior: if collision_read() is 1, increase the crash count, turn the steering 30° right (-30), go backward for 1 second and then continue driving forward.
The program should run for 60 seconds (1200 rounds × 50 ms) or stop at 5 crashes; at the end stop the car and print the crash count. Can the car pass the curve, even with crashes?

Hint
When backing up the steering works the other way: a car backing up with the steering turned right swings its nose to the left. All curves on the track turn left.
collision_read()DRIVE_BACKWARDrecovery
26

Curve detector

See answer

The 76° ray, which looks to the front right of the car, reads 0 on a straight (the line is farther than 100) and sees the outer line in a curve.
While running the driver of Task 20, use this ray to track whether the car is in a curve or on a straight, and print CURVE or STRAIGHT only when the state changes.
To ignore sudden single readings: print CURVE as soon as 76° > 0, but for STRAIGHT the 76° ray must read 0 for 20 readings in a row (about 1 second).
In one lap you should see two CURVE and two STRAIGHT. One extra STRAIGHT appears right after the start, because the car starts right at the end of a curve.

Hint
Keep two variables: in_curve (the current state, 0/1) and quiet (how many 0 readings in a row). At the start take in_curve from the first reading of the ray: the car starts right at the end of a curve.
statechange detectiondebounce

5 Project

Complete systems that combine everything.
27

Drive one lap and stop

Your turn

Using the curve detector of Task 26, drive the car one full lap and stop it close to where it started.
At the start the car is on the right straight; one lap = top curve + left straight + bottom curve. When the car leaves the second curve (the second STRAIGHT) the lap is done.
When it stops print One lap done!. The car should never crash and should stop after about 72 seconds.

Hint
Count the curves entered. The first STRAIGHT at the start is not a curve entry, so it is not counted. Leave the endless loop with break.
statecounterbreak
28

A faster lap

Your turn

Add time measurement to Task 27: when the lap ends print Lap time: ... s (GetTickCount() in C, time.time() in Python).
Move the turning angle (20) to a constant called TURN at the top of the program and measure the lap time for 20, 30, 45 and 60.
Goal: under 70 seconds without any crash. With 20° you should see about 72 seconds, with 45° about 66 seconds.

Hint
GetTickCount() gives the milliseconds since the computer started; save the value at the start and subtract it from the value at the end. Why could a sharper turn be faster? Remember the answer of Task 18.
GetTickCount / time.timeconstanttuning
29

Robust driver: 3 laps

Your turn

Drive 3 laps with the driver of Task 28 and print the time of each lap separately (Lap 1: ... s).
Add the recovery of Task 25 to the driver: if there is a collision, count it, back up for 1 second with -30° steering and continue. At the end print the total time and the number of crashes.
With a good driver the crash count should be 0; the recovery only works when something goes wrong (for example if someone interferes with Manual Control).

Hint
Every time a lap ends, renew the start time of the lap and reset the curve counter. Count the laps with a separate counter.
lapsrecoverytiming
30

Project: autonomous race mission

Your turn

Write the final program that combines everything:
1. The program asks the user for the number of laps (1–5). If an invalid number is entered it asks again.
2. The car drives as in Task 29 and recovers from collisions.
3. Every second it prints a status line: Lap 1/3 | CURVE | 23 s | crashes 0.
4. When the requested laps are done it stops the car and prints a summary: the time of each lap, the fastest lap and the total crashes.

Hint
Store the lap times in an array (at most 5). For the status line keep the time of the last print and print again when more than 1 second has passed. In C read a number with scanf("%d", &laps), in Python with int(input()).
scanf / inputarrayfunctionsstatetiming