How to remote control an EV3 Brick with SPIKE Prime over Bluetooth

| |

Both MINDSTORMS EV3 and SPIKE Prime have an onboard BlueTooth chip. It turns out that it isn’t too hard to make them talk to each other. In this article, you’ll learn how you can do it with a little MicroPython script. After following this tutorial you will be able to design your own remote control devices with a SPIKE Hub. You can make any design that fits the EV3 robot you want to control.

The fun thing about the setup I’m describing here is that you only need a script on the EV3 brick. A script on the SPIKE Prime hub is entirely optional. You can use the matrix or run a script that auto-centres motors and it will not interfere with the BlueTooth stream!

For those of you who don’t like to read, I have explained it all in a YouTube video. The SPIKE Prime hub connection is near the end of the video. While you watch, you can like and subscribe to be notified of cool new ideas!

How to remote control MINDSTORMS EV3 devices

How to connect a SPIKE Prime hub to EV3 for remote control

Time Needed : 5 minutes

How to connect a SPIKE Prime hub to a MINDSTORMS EV3 brick over Bluetooth

  1. Boot your EV3 brick into a recent ev3dev

    You can use either the official Python release from LEGO or use the latest ev3dev image. Burn either of those to a MicroSD card, insert it in the MINDSTORMS brick and boot it. Wait until the boot completes and you see a menu.
    Booted into ev3dev

  2. Start scanning for Bluetooth devices

    Go to Wireless and Networks > Bluetooth. In that screen enable Bluetooth and set Visible to enabled. Select the 'Start Scan' option.
    ev3dev bluetooth scan

  3. Enable BlueTooth on the SPIKE Prime hub

    Turn on your SPIKE Prime hub and press the little BlueTooth button until the led ring around it starts blinking blue.

  4. Select the SPIKE Prime hub in the Devices list on your EV3 brick

    Scroll down until the SPIKE Prime hub appears. It could take a few seconds. I named my hub “Antons Second Hub” because I have two SPIKE Prime hubs.
    SPIKE Prime Hub on ev3dev

  5. Write down the MAC address you see

    The address is made up of 6 hexadecimal numbers. In my case, it was 40:BD:32:42:EB:54. I press the Pair button here just to be sure. But I'm not 100% sure this is necessary. I haven't tested the script without pairing. Maybe let me know in the comments?
    LEGO SPIKE Prime Bluetooth MAC Address

  6. Run a MicroPython script on your EV3 brick that listens to the SPIKE Prime hub

    Now you can run any script on your EV3 and start remote controlling. The SPIKE Prime hub is spewing telemetry data over BlueTooth all the time, so no need to run any scripts there!
    Further down in this article I have an example script for a LEGO MINDSTORMS Rubber Band Cannon omnibot. You can tweak that code to fit your robot design. Remember to replace the MAC Address in the script with the MAC Address of your specific hub!
    I have a separate VS Code tutorial where I explain more in-depth how you can run scripts on the EV3 brick.

Tools
  • A PC or Mac with MS Visual Studio Code
Materials
  • MicroSD Card
  • SPIKE Prime hub
  • MINDSTORMS EV3 brick

Here’s a video of the result. Remember to like and subscribe if you haven’t done so yet.

The MicroPython script for a SPIKE Prime remote control

Below you will find the script I used in my video. It is based on a Pybricks project. Credits to them for reverse-engineering the telemetry stream and writing a class around that. The easiest way to use it is with the LEGO MINDSTORMS VS Code extension. In VS Code, click the MINDSTORMS icon in the very left toolbar. Create a new project. Add a file called ‘connection.py’ and copy the respective script in there. Finally, replace the contents of the main.py file with the other script.

# This code was originally written by Pybricks
# Paste all of it into a file named 'connection.py' and place it next to your 'main.py' file
# Nothing below is written by Anton's Mindstorms
# I found it here. https://github.com/pybricks/pybricks-projects
from uctypes import addressof, sizeof, struct
from usocket import socket, SOCK_STREAM
from _thread import start_new_thread
from pybricks.bluetooth import (
str2ba,
sockaddr_rc,
AF_BLUETOOTH,
BTPROTO_RFCOMM
)
from pybricks.tools import wait, StopWatch
def get_bluetooth_rfcomm_socket(address, channel):
addr_data = bytearray(sizeof(sockaddr_rc))
addr = struct(addressof(addr_data), sockaddr_rc)
addr.rc_family = AF_BLUETOOTH
str2ba(address, addr.rc_bdaddr)
addr.rc_channel = channel
sock = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)
sock.connect(addr_data)
return sock
class SpikePrimeStreamReader():
def __init__(self, address):
try:
self.sock = get_bluetooth_rfcomm_socket(address, 1)
except OSError as e:
print("Turn on Bluetooth on the EV3 and on SPIKE.")
raise e
self._values = None
start_new_thread(self.reader, ())
watch = StopWatch()
while watch.time() < 2000:
if self.values() is not None:
return
wait(100)
raise IOError("No data received")
def disconnect(self):
self.sock.close()
def reader(self):
while True:
try:
raw = self.sock.recv(1024)
except OSError:
break
try:
data = eval(raw)
if data['m'] == 0:
self._values = data['p']
except (SyntaxError, KeyError):
pass
def values(self):
return self._values
def device(self, port):
if 'A' <= port <= 'F':
return self.values()[ord(port)ord('A')][1]
else:
raise ValueError
def acceleration(self):
return self.values()[6]
def gyro(self):
return self.values()[7]
def orientation(self):
return self.values()[8]
view raw connection.py hosted with ❤ by GitHub
#!/usr/bin/env pybricks-micropython
# Replace the contents of your 'main.py' file with this script.
# Author: Anton's Mindstorms
# Full tutorial on https://antonsmindstorms.com
# Connection class by https://pybricks.com
from pybricks.hubs import EV3Brick
from pybricks.tools import wait
from pybricks.ev3devices import (Motor, TouchSensor, ColorSensor,
InfraredSensor, UltrasonicSensor, GyroSensor)
from pybricks.parameters import Port, Stop, Direction, Button, Color
from math import sin, radians, pi, atan2, degrees
from connection import SpikePrimeStreamReader
# Create the connection. Replace this with the MAC address for your SPIKE hub !!
spike = SpikePrimeStreamReader('38:0B:3C:A3:45:0D')
MAX_SPEED = 800
DEADZONE = MAX_SPEED * 0.1
three_o_clock = Motor(Port.A)
seven_o_clock = Motor(Port.C)
eleven_o_clock = Motor(Port.B)
gun = Motor(Port.D)
def deadzone(value):
if abs(value) < DEADZONE:
return 0
else:
return value
def drive(speed, direction, turn):
three_o_clock.run( sin(radians(90 direction)) * speed + turn)
seven_o_clock.run( sin(radians(210 direction)) * speed + turn)
eleven_o_clock.run( sin(radians(330 direction)) * speed + turn)
direction = 0
speed = 0
turn = 0
# Now you can simply read values!
while True:
down, backward, left = spike.acceleration()
if spike.device("E")[0] >= 5:
# Touch sensor is pressed
gun.run_angle(400, 90)
turn = spike.device("C")[0] * 20
forward = backward * 1
right = left * 1
direction = degrees( atan2(right, forward) )
speed = (right ** 2 + forward ** 2) ** 0.5
drive(speed, direction, turn)
view raw main.py hosted with ❤ by GitHub

The Omnibot as shown in the video demo

You can download full code and building instructions from the digital downloads section.

With some tweaks the could also control a regular drift car.

Previous

Building and Coding Voice-controlled EV3 race cars with optional FPV

LEGO MINDSTORMS Robot Inventor Set 51515 part list and Studio part files

Next

13 thoughts on “How to remote control an EV3 Brick with SPIKE Prime over Bluetooth”

  1. When i start program sometimes i get message like this:

    Unhandled exception in thread started by <bound_method b5e67ab0 .>
    Traceback (most recent call last):
    File “/home/robot/sterowanie_zdalne/connection.py”, line 61, in reader
    File “/home/robot/sterowanie_zdalne/connection.py”, line 57, in reader
    File “”, line 1, in
    NameError: name ‘null’ isn’t defined
    Traceback (most recent call last):
    File “/home/robot/sterowanie_zdalne/main.py”, line 14, in
    File “/home/robot/sterowanie_zdalne/connection.py”, line 45, in __init__
    NameError: name ‘IOError’ isn’t defined

    But when i wait for 30 minutes and turn on Spike again everything works fine. Any ideas what could go wrong? I made no changes to connection.py

    Reply
    • Interesting. Just turning the SPIKE on and off should do the trick. And maybe turn Bluetooth on and off on the ev3.

      Reply
          • Ya maybe because i know a little bit of ev3dev python from when i made a lego tank and controlled it with a ps3 controller.

          • So recently i made a swirlbot with lego spike and i made a joystick remote controll with lego mindstorms the only thing is i don’t know how to connect them with bluetooth. when i go to connect it i select the spike hub from the ev3dev bluetooth devices but it says operation currently unavailable. what should i do?

  2. Hi, I was wondering if it is also possible to control Technic Hubs, like the ones found in 42100 Technic Liebherr Excavator R 9800 with an EV3? I would like to control the motors of the Techinc Hub with the help of python scripts run on the EV3. Thank you!

    Reply

Leave a Reply

%d bloggers like this: