Raspberry PI and the Lego EV3 connected by bluetooth

Executive summary

Here is how to interact between Raspberry PI 3 and Lego EV3 using Bluetooth.   There will be a python 3.6 script presented and sample EV3 programs.  All of this is stock stuff on both platforms.

The key is how to interpret the bytes.  The script presented takes care of all of that.  Here is the EV3BT Script.

The fun stuff

So, I could possibly have a family and I could indeed possible like to enjoy time with them.  I play with Lego in the interest of my family.  I am a good dad…  unless explosives are involved.

Don’t judge.

So the project was to determine if we could use a Raspberry PI with open CV and a camera and drive a Lego robot around the floor using the EV3 trying to do cool things.

There are several communication options but I didn’t want to use any sort of wired or wireless Ethernet nor is USB an option from what I can tell.  I also didn’t want to change the EV3’s operating system.

I decided to play with bluetooth.  They are probably other and perhaps better ways to do this but this is what I chose.

Enough disclaimers about the effectiveness of my decision making skills especially about the explosives and related minors.

There are many sites that explain how to connect the EV3 and even program it.  This guy’s is pretty good.

If you are unfamiliar with pairing with Raspberry PI3 and the EV3, google it.  It is a bit cryptic but once pair, you can connect to the EV3 and it appears as a serial device (i.e. /dev/rfcomm0).

The trick and the purpose of the

Sending to the EV3

The program above simply waits for a Bluetooth message and in this case, a text message, prints it on the LCD screen and beeps.  The python below shows the sending of a message to the EV3.  The trick of the EV3BT class is to simply encode and decode the bits.  The serial module takes care of the transmission.

#! /usr/bin/env python3
import serial
import time
import EV3BT

EV3 = serial.Serial('/dev/rfcomm0')
s = EV3BT.encodeMessage(EV3BT.MessageType.Text, 'abc', 'Eat responsibly')
print(EV3BT.printMessage(s))
EV3.write(s)
time.sleep(1)
EV3.close()

You have options for what sort of messages you can send.  These are Text, Numeric, and Logic.  In programmer speak, strings, floating point values (IEEE 754), and Boolean (literally a 1 and a 0).  See below.

The other key is the mailbox.  The ‘abc’ is the mail box and is shown on the block (highlighted in red).  You must pass the mailbox in a form that matches the block so that the block receives the message.  In case it isn’t obvious, you can send messages to multiple mailboxes in your script and control several EV3 loops just but using different mailboxes.

Reading from the EV3

Reading is just a little more complicated in that you probably need to have some sort of loop with blocking logic.  As I say that, every experienced developer reading this is rolling their eyes (back in old school Linux days, should we use select or poll?).

In this example, the EV3 will wait for a touch sensor to be activated and send a message.  To be precise, the message ‘Raspberry PI’ will be sent to the mailbox ‘abc’  in the Raspberry PI.

The key is the decodeMessage.  You tell the method, the string to parse, and the message type expected (as this effects the length of the transfer and there is no identifying mark in the message about the type).  It will return you the mail box, the value, and any remnant bytes left over.  The buffering is not stellar in this example but it gets the point across.

#! /usr/bin/env python3
import serial
import time

import EV3BT

EV3 = serial.Serial('/dev/rfcomm0')
print("Listening for EV3 Bluetooth messages, press CTRL C to quit.")
try:
 while 1:
 n = EV3.inWaiting()
 if n != 0:
  s = EV3.read(n)
  mail,value,s = EV3BT.decodeMessage(s, EV3BT.MessageType.Logic)
  print(mail,value) 
 else:
  # No data is ready to be processed
  time.sleep(0.1)
except KeyboardInterrupt:
 pass
EV3.close()

Moving a robot

So to put it together, I could make a robot move under python control in the Raspberry PI with this script and program.

The EV3 was made as a tank with two treads.  A left and right.  Essentially, the script is sending a numeric to each tank tread.  A positive number moves forward, a negative number moves back.   The larger the number, the faster the rotation.

#! /usr/bin/env python3
import serial
import time
import EV3BT

EV3 = serial.Serial('/dev/rfcomm0')
left = 10
right = 10
s = EV3BT.encodeMessage(EV3BT.MessageType.Numeric, 'left', left)
EV3.write(s)
s = EV3BT.encodeMessage(EV3BT.MessageType.Numeric, 'right', right)
EV3.write(s)
EV3.close()

Areas of improvement

When reading, there is no identifying mark in the package concerning the type.  You also can not assume that number of bytes on the wire will work.  A 3 byte with null looks like a float.

Deriving application specific code to handle the case where you want the EV3 to send a float and a Boolean should be simple to add.  A string?  Not sure the worth of that really from the EV3 to the Raspberry PI.