MicroPython Tutorial XIII

We did quite a few tutorials with the brick buttons and then switched to a more basic task, driving in a straight line. Lets focus on something different, something not present in the LEGO EDU kit the IR Remote and IR Sensor.

You need two lines to build an IR Sensor into your python code.

from pybricks.ev3devices import Motor, InfraredSensor
infra = InfraredSensor(Port.S4)

The first line simply names the class with the details of the device. The second defines the physical place the sensor is plugged into your brick.

Beyond this your going to be testing the values returned within it to see which buttons on your brick are being pressed. The basic code in a loop looks like this.

while True:
buttonPressed = infra.buttons(1)

The number in brackets, one in our case in the channel on which the remote is working. There are only 4 channels, which is challenge in itself in a class, controlled by the red switch on the remote itself.

Now what does it return. To try and keep some good coding practice in here I am going to define a whole set of returned values.

redHigh = 128
blueHigh = 512
redAndblueHigh = redHigh + blueHigh
redLow = 2
blueLow = 8
redAndBlueLow = redLow + blueLow
redCrossBlue = redHigh + blowLow
blueCrossRed = blueHigh + redLow
allRed = redHigh + redLow
allBlue = blueHigh + blueLow
beacon = 256

Cavet, the last value when you press the beacon button [top] behaves differently from all the rest. It is like switch that turns on or off [indicated by the LED on the switch itself]. When on it will signal being pressed again and again, a steam of 256s.

How to test, the buttons class returns a list of values; a list that can contain more than one element. An aspect that gives us several choices for coding. Here is our test code.

while True:     
buttonPressed = infra.buttons(1)
returns = len(buttonPressed)
if returns == 1:
une = buttonPressed[0]
if redHigh == une:
print("redHigh",returns)
wait(500)
if redLow == une:
print("redLow",returns)
wait(500)
if blueHigh == une:
print("blueHigh",returns)
wait(500)
if blueLow == une:
print("blueLow",returns)
wait(500)
if beacon == une:
print("beacon")
if returns == 2:
deux = buttonPressed[0] + buttonPressed[1]
if redAndblueHigh == deux:
print("redAndblueHigh",returns)
wait(500)
if redAndBlueLow == deux:
print("redAndBlueLow",returns)
wait(500)
if redCrossBlue == deux:
print("redCrossBlue",returns)
wait(500)
if blueCrossRed == deux:
print("blueCrossRed",returns)
wait(500)
if allRed == deux:
print("allRed",returns)
wait(500)
if allBlue == deux:
print("allBlue",returns)
wait(500)

So what is going on. We extract the values found in buttonstwo add them together if need be. We then simply test to see if our value returned matches the predefined values. Note like the brick buttons I added a wait to stop the buttons firing multiple times.

If we didn't need to worry about multiple buttons being pressed we could also have tested membership using a line like this.

    if redHigh in buttonPressed:  
print("redHigh")

Cavet. Finally a python note, the order of elements in a list is important so 128,512 is not the same as 512,128. I suspect the list returned is in order, so it doesn't matter... but if you decide to code differently and test for membership of multiple elements, make sure you test for them in the right order if not both.

But wait, we’re not quite finished with the IR sensor since the class can return two other values. It can return the distance between the IR remote and the sensor and the angle at which it sees it. The code look this.

print(infra.distance(),infra.beacon(1))

Assuming you got more than one remote the first will return multiple values when it sees multiple remotes. The second returns a tuple (None, None) if the beacon key is turned off and distance and an angle if it is turned on. The number in the brackets in the channel again. But bewarned it isn’t very consistent and will more often then not report anything.

You can for fun combine it with the drivebase command to get your bot to follow the remote, although it doesn’t work so well; take it with a pinch of salt. Here is the whole shebang for you to copy and paste, with the bot following code right at the end.

#!/usr/bin/env pybricks-micropython
from pybricks import ev3brick as brick
from pybricks.parameters import Color, Port
from pybricks.tools import wait
from pybricks.ev3devices import Motor, InfraredSensor
from pybricks.robotics import DriveBase
infra = InfraredSensor(Port.S3)leftMotor = Motor(Port.B)
rightMotor = Motor(Port.C)
pause = 500
robot = DriveBase(leftMotor, rightMotor, 56, 114)redHigh = 128
blueHigh = 512
redAndblueHigh = redHigh + blueHigh
redLow = 2
blueLow = 8
redAndBlueLow = redLow + blueLow
redCrossBlue = redHigh + blueLow
blueCrossRed = blueHigh + redLow
allRed = redHigh + redLow
allBlue = blueHigh + blueLow
beacon = 256
while True: buttonPressed = infra.buttons(1)
returns = len(buttonPressed)
if returns == 1:
une = buttonPressed[0]
if redHigh == une:
print("redHigh",returns)
wait(pause)
if redLow == une:
print("redLow",returns)
wait(pause)
if blueHigh == une:
print("blueHigh",returns)
wait(pause)
if blueLow == une:
print("blueLow",returns)
wait(pause)
if returns == 2:
deux = buttonPressed[0] + buttonPressed[1]
if redAndblueHigh == deux:
print("redAndblueHigh",returns)
wait(pause)
if redAndBlueLow == deux:
print("redAndBlueLow",returns)
wait(pause)
if redCrossBlue == deux:
print("redCrossBlue",returns)
wait(pause)
if blueCrossRed == deux:
print("blueCrossRed",returns)
wait(pause)
if allRed == deux:
print("allRed",returns)
wait(pause)
if allBlue == deux:
print("allBlue",returns)
wait(pause)
(distance, angle) = infra.beacon(1)
robot.drive(25,angle)

A final point on the distance, it’s range is very limited. The figures is returns a number between 1 and 100.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store