MicroPython Tutorial XVI
Ok, lets do something different. Now LEGO has an iOS app that you can use as a remote. It is very good and lets you design your own controls. But to use it you need to be running the LEGO scratch interface. If you’re on MicroPython SD card you need something else.
But wait BEFORE you read on, be warned that the something else in this tutorial needs a Wifi connection. Something like LEGO recommended EDIMAX USB adaptor, without it this tutorial won’t work.
I should say too that is isn’t a tutorial like the others I posted to-date. This is a tutorial for those with quite a bit of experience in coding. All in all it will be around 120+ lines of code.
Here is a video showing what this does too.
It is also not a code base designed to work by itself, but in co-operation with the app remoteCode, that you can download here. OK done that, lets go.
from pybricks import ev3brick as brick
from pybricks.ev3devices import Motor, UltrasonicSensor, ColorSensor, GyroSensor, InfraredSensor
from pybricks.parameters import Port,Color
from pybricks.robotics import DriveBase
from pybricks.tools import print, wait, StopWatch
from time import sleep
import sysimport random
import os# Section 01hostname = os.popen('hostname -I').read().strip().split(" ")
hostIPA = hostname
port = random.randint(50000,50999)# Section 02left = Motor(Port.C)
right = Motor(Port.B)
# 56 is the diameter of the wheels in mm
# 114 is the distance between them in mm
robot = DriveBase(left, right, 56, 114)print("host ",hostIPA)
print("port",port)# Section 03online = Trueai = socket.getaddrinfo(hostIPA,port)
addr = ai[-1]backlog = 5
size = 1024
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.listen(backlog)# Section 0Etry:
res = s.accept()
client_s = res
#client_addr = res
print("data ",data)except AssertionError as error:
We have imported all the classes we will ultimately need for this code to work to keep this tutorial manageable. Ok, we begin in Section 01 by running a query agains’t the OS class to get the IP address of our robot that we’re running on and a random port number. We need to give both these bits of information to the app so that it can communicate with the robot.
Next in Section 02 we have simply defined the two connected motors declaring them in the process in a drive pair.
In Section 03 we setup the code needed to communicate with the iOS device, and indeed try and make that connection.
In Section 0E we launch the main loop thru which the app remoteCode and our MicroPython code will talk, printing out the conversation that is taking place. Yes, 0E doesn’t follow 03, we dropped a few sections to keep things to get you going.
Download the app remoteCode here and copy and paste this to a python code file on your robot, run it and then run remoteCode on your iOS device. Enter the IP address you’re of your robot into the iOS app and the port and they should start talking to each other.
Assuming you’re connected and it all works, you should see the work “data #:connected” appear on the screen. This is the app talking to your Python app. Now go and select one of the interfaces “Keyboard, Touchpad or Motion”. You should see more text appearing, assuming you choose “Keyboard” for example, it will sa “#:begin” followed by “#:keypad”. Swipe the iPad right and it’ll say “#:end” and then return to the main menu.
Note if you iOS device screen locks during the process, you’ll need to quit the Python and re-run the process. You can quit your connection on the iOS device by shaking it.
And there you have it, the basis of our remote app. But ok, where do you go from here. Here is some more code to add to the mix. These two procedures show subroutines to interpret the #: commands you just saw returned by the app.
# Section 07def actionTrigger(data, client):
if data[:5] == "#:end":
peerMode = False if data[:6] == "#:peer":
peerMode = True
if data[:7] == "#:begin":
pass if data[:8] == "#:keypad":
brick.light(Color.YELLOW) if data[:10] == "#:touchpad":
brick.light(Color.RED) if data[:8] == "#:motion":
brick.light(Color.ORANGE) if data[:5] == "#:con": # connected
brick.sound.beep()if data[:5] == "#:dis": # disconnect
s.close() if data[:8] == "#:short":
brick.sound.beep() if data[:6] == "#:long":
brick.sound.beep()# Section 08def stopMotors():
print("STOP STOP STOP ")
This code is reasonably self explicit. As you change to different interfaces, the colours of the robot will change in response to the different “#:” conversations the iOS code sends back to it.
We’re almost there. I am going to give you the last section which is the code bases you need for the tracker/motion interfaces and leave the keyboard one as an exercise for you to figure out. You should already have the general gist of the way it works now.
Firstly we add a method to interprete the streams of data that come back if you choose the motion or the tracker interface. Note the code here is a little more complicated since I want to ignore duplicate data packets sent by the app.
lastPitch = 0
lastRoll = 0# Section 09def joystick(pitch, roll):
calcPitch = int(round(pitch / 180 * 800,0)) # needs to be an integer
calcRoll = int(round(roll / 720 * 200,0)) # turns need to be slow and deliberate, this reduces roll by 4
if lastPitch != calcPitch or lastRoll != calcRoll:
lastPitch = calcPitch
lastRoll = calcRoll
And then I add an else to the if we added early on in the main loop, so after the call to the actionTrigger routine it acts on the data packets prefixed with a “@:” lead.
elif data[:2] == "@:":
mCommands = data.split("\n")
for mCommand in mCommands:
if len(mCommand) != 0:
cords = mCommand[2:]
cord = cords.split(":")
roll = float(cord)
pitch = float(cord)
When you’re all done, download the script and run it. Try using it with the touchpad or the motion interface and you’re be able to move you’re robot with your iOS device, under MicroPython!
Hint. If you’re in the motion interface, you need to keep the grey circle inside the red one to stop sending data, and indeed tap the circle itself to stop the robot. The touchpad is slightly easier, you just stop touching it.
I may publish a tutorial on getting the keyboard interface running in due time, but for now, its time to play :) A final final note, how do I know all this, well yes I confess I wrote the remoteCode app too. [Obviously it isn’t Python, it is in Swift].