# 2. Speed Calculation¶

As described in 1. Introduce Speed Module, the speed module’s speed measurement principle is to count the number of times the infrared light pass through the encode disk per unit time.

Note

• The complete script `speed_2_get_speed.py` is in the path `pico_4wd_car\examples\learn_modules`.

• Before running the following scripts, it is recommended to hang the car in the air so that the 4 wheels can turn freely.

Here are the steps to implement the speed calculation, which you can copy into Thonny to run.

1. Counting

Let’s count how many times the infrared rays pass through the encode disk in a minute.

```from machine import Timer, Pin

def on_left(ch):
global left_count
left_count += 1

def on_timer(ch):
global left_count
print(left_count)
left_count = 0

# Interrupter, used to count
left_count = 0
left_pin = Pin(8, Pin.IN, Pin.PULL_UP)
left_pin.irq(trigger=Pin.IRQ_FALLING, handler=on_left)

# Timer, print count every 1000ms
tim = Timer()
tim.init(period=1000, mode=Timer.PERIODIC, callback=on_timer)

# motor run
import motors
import time

try:
while True:
#         for i in range(20,100,10):
motors.move("forward",50)
#             time.sleep(1)
finally:
motors.stop()
time.sleep(0.2)
```

Copy the above code into Thonny and click the button or press `F5` to run it.

After powering up the Pico 4WD car, you will see the 4 motors turning (forward) while seeing the count in the Shell.

2. Calculate the RPM

Now let’s calculate the RPM based on the counts. To improve the accuracy of the calculation, the calculation period is set to 200ms.

```from machine import Timer, Pin
import math

duration = 200

def on_left(ch):
global left_count
left_count += 1

def on_timer(ch):
global left_count
# revolutions per second
times = left_count * 1000 /duration
rps=times/20.0
print(rps)

# clear count
left_count = 0

# Interrupter, used to count
left_count = 0
left_pin = Pin(8, Pin.IN, Pin.PULL_UP)
left_pin.irq(trigger=Pin.IRQ_FALLING, handler=on_left)

# Timer, print speed
tim = Timer()
tim.init(period=duration, mode=Timer.PERIODIC, callback=on_timer)

# motor run
import motors
import time

try:
while True:
for i in range(20,100,10):
motors.move("forward",i)
time.sleep(1)
finally:
motors.stop()
time.sleep(0.2)
```

After running the script, click View -> Plotter to view the RPM curve, and you can see that the higher the power, the faster the RPM.

3. Calculate moving speed

Next, the RPM is converted to moving speed (unit:cm/s). Here the moving speed is actually the RPM multiplied by the circumference of the wheel.

```from machine import Timer, Pin
import math

WP = 2 * math.pi * 3.3 # wheel_perimeter(cm): 2 * pi * r
duration = 200

def on_left(ch):
global left_count
left_count += 1

def on_timer(ch):
global left_count
# revolutions per second
rps = left_count * 1000 /duration /20.0
# speed
speed = rps * WP
print(speed)
# clear count
left_count = 0

# Interrupter, used to count
left_count = 0
left_pin = Pin(8, Pin.IN, Pin.PULL_UP)
left_pin.irq(trigger=Pin.IRQ_FALLING, handler=on_left)

# Timer, print speed
tim = Timer()
tim.init(period=duration, mode=Timer.PERIODIC, callback=on_timer)

# motor run
import motors
import time

try:
while True:
for i in range(20,100,10):
motors.move("forward",i)
time.sleep(1)
finally:
motors.stop()
time.sleep(0.2)
```

4. Calculate the speed on both sides

In the case of a turn, there may be a situation where one side of the wheel is not rotating, but the car is actually moving. Then we can use both sides of the speed module to reduce error.

```from machine import Timer, Pin
import math

WP = 2 * math.pi * 3.3 # wheel_perimeter(cm): 2 * pi * r
duration = 200

def on_left(ch):
global left_count
left_count += 1

def on_right(ch):
global right_count
right_count += 1

def on_timer(ch):
global left_count,right_count
# revolutions per second
rps = (left_count + right_count) * 1000 /duration /20.0 /2
# speed
speed = rps * WP
print(speed)
# clear count
left_count = 0
right_count = 0

# Interrupter, used to count
left_count = 0
right_count = 0
left_pin = Pin(8, Pin.IN, Pin.PULL_UP)
left_pin.irq(trigger=Pin.IRQ_FALLING, handler=on_left)
right_pin = Pin(9, Pin.IN, Pin.PULL_UP)
right_pin.irq(trigger=Pin.IRQ_FALLING, handler=on_right)

# Timer, print speed
tim = Timer()
tim.init(period=duration, mode=Timer.PERIODIC, callback=on_timer)

# motor run
import motors
import time

try:
while True:
for i in range(20,100,10):
motors.move("forward",i)
time.sleep(1)
finally:
motors.stop()
time.sleep(0.2)
```