Robot Car steuern mit BlueDot

In the English magazine The Magpi, issue 114 Have I read something new for me again and interesting things about robot cars (Robot Car). The focus of the article was the relatively new accessories Raspberry Pi Build, an interface to the Lego engines. So, if you have a Lego fleet, you can now program and control your models with a Raspberry Pi.

One aspect of the control is also interesting for all other lovers of robot cars with the much used yellow electric motors: that of Martin O'Hanlon - employee of the Raspberry Pi Foundation - developed smartphone app Bluedot, a Bluetooth control that on the Raspberry Pi can be adjusted for your own purposes. This means that the appearance and functionality are programmed with Python. Obviously this app is only available for Android. Here is a screenshot from the app on my smartphone with the eponymous blue dot:

Hardware used:


Raspberry Pi with Bluetooth, e.g. 3b+


Smart Robot Car Kit

You can find a detailed contribution to the Smart Robot Car Kit here.

As I said, appearance, i.e. number of buttons, shapes and colors of the points as well as the functions, can be designed according to your own wishes. More on that later.

On my Android smartphone I entered Blue Dot in the Play Store in the search window. The thick blue dot and the underline Martin O’Hanlon *tools led me to the right app from the large number of options displayed. So that the open app later finds the Raspberry Pi, it must first be linked to the smartphone under Settings/Bluetooth. Self-murmuring must be activated on both devices and selected on the Raspberry Pi with the left mouse click on the Bluetooth symbol "Make Discoverable".

The next two pictures show the basic coupling of the smartphone and Raspberry Pi, as well as the app before the actual connecting the app to the Raspi. With several coupled devices, several options can also be offered here. Simply click on the two lines with Raspberrypi and address, then the connection is established, provided that the program has also started on the Raspberry Pi.

The associated Python library must be installed on the Raspberry Pi. This is best done with the terminal command:

 sudo PIP3 Install Bluedot

In the next step we are looking for "Github Bluedot" with Google in the browser and are on the side of Martin O’Hanlon guided. Here we find important information, such as the links to "Online documentation“As well as many Program examples (recipes). I quickly download everything as a zip file, unpack the file and postpone the examples to the Raspberry Pi to try everything out.

Here I recommend copying, because this way you get to know the diverse functionality of the program library the fastest. Because here, too, I repeat myself, the appearance of the app on the smartphone and the functionality are programmed on the Raspberry Pi.

The next picture of the smartphone with the JOOPAD can be obtained with the following Python code (sample program

 from bluedot import Bluedot
 from signal import Break
 def up():
 def down():
 def leaf():
 def right():
 def Button_a():
 def button_b():
 BD = Bluedot(cols=5, rows=3)
 # dpad buttons
 BD.color = "Gray"
 BD.Square = True
 BD[0,0].visible = False
 BD[2,0].visible = False
 BD[0,2].visible = False
 BD[2,2].visible = False
 BD[1,1].visible = False
 BD[1,0].When_Pressed = up
 BD[1,2].When_Pressed = down
 BD[0,1].When_Pressed = leaf
 BD[2,1].When_Pressed = right
 # Buttons
 BD[3,0].visible = False
 BD[4,0].visible = False
 BD[3,2].visible = False
 BD[4,2].visible = False
 BD[3,1].color = "Blue"
 BD[3,1].Square = False
 BD[3,1].When_Pressed = Button_a
 BD[4,1].color = "Red"
 BD[4,1].When_Pressed = button_b

With bd = bluedot (cols = 5, rows = 3)  the Bluedot object is instantiated with 5 columns and 3 rows. Then the unwanted fields BD [0.0] .Visible = false  made invisible. Color and shape of the buttons are e.g. Bd.Color = "Gray" and Vol.square = True  Are defined. With commands like BD [1.0] .When_pressed = up  are called up defined functions.

With regard to my Robot Car project, my attention is drawn to the programs and In both programs, only the large blue dot is displayed on the smartphone as in the first picture, but the functionality is different.

 from bluedot import Bluedot
 from Gpiocero import Robot
 from signal import Break
 BD = Bluedot()
 robot = Robot(leaf=(10, 9), right=(8, 7))
 def move(POS):
     IF POS.Top:
     elif POS.bottom:
     elif POS.leaf:
     elif POS.right:
 def stop():
 BD.When_Pressed = move
 BD.When_Moved = move
 BD.When_Released = stop

For my Robot Car with Raspberry Pi and the Motor Controller Phat Motozero from ThePihut, I only have to change the line with the GPIO pins of the Robot object. I use the outputs for Motor 3 LEFT = (23.16) and Motor 4 Right = (13.18). The Raspberry Pi previously coupled in the settings is displayed in the app after starting the program. After tapping, the blue dot appears. When typing onto the four "cardinal points", the wheels move at full throttle, but my left wheel turns in the wrong direction. The remedy would be exchanged of the GPIO numbers when instantiation of the Robot and restart of the program, or quickly overflow the engine on the motor controller.

But only full throttle before or back, or high speed spinning on the spot, are unsatisfactory. So next I try the demo program

 from Gpiocero import Robot
 from bluedot import Bluedot
 from signal import Break
 def POS_TO_VALUES(X, y):
     leaf = y IF X > 0 Else y + X
     right = y IF X < 0 Else y - X
     return (clamped(leaf), clamped(right))
 def clamped(V):
     return Max(-1, min(1, V))
 def drive():
     while True:
         IF BD.Is_pressed:
             X, y = BD.position.X, BD.position.y
             yield POS_TO_VALUES(X, y)
             yield (0, 0)
 IF __Surname__ == '__Main__':
     robot = Robot(leaf=(10, 9), right=(8, 7))
     BD = Bluedot()
     robot.source = drive()

This means that the Robot Car can also drive slower because a coordinate system is stored for the blue dot. The values ​​for X and Y are between -1.0 and +1.0. Alternatively, you can also determine angles and distance. Result: much better, but the cornering is still unsatisfactory, because the program only knows: one wheel turns forward, the other backwards, unfortunately not: one bike turns faster than the other for a quiet movement.

At this point I remembered that in spring 2021 we had a blog series on the subject of Robot Car, where we also developed code for cornering. This makes this blog post a continuation of the blog, so to speak Robot Car with Raspberry Pi of April 24, 2021

At that time we developed a code, each with 5 speed levels per direction. Code 505 stood for standstill, the initial number 6 to 10 for forward trip, 4 to 0 for reverse ride, the rear number group for left or right curve. We were able to use this code both for keyboard input and radio transmission with HC-12 or NRF24L01. The advantages of the driving levels lies in the adapted pulse width modulation for the engines. For the lowest driving level, the motors already need 20% to 40% of the voltage. They just hum, but don't turn yet. And if necessary, the maximum voltage, e.g. two lithium batteries, is too much for the continuous operation of the engines, in my case only 60% to 70% of the maximum value.

In the next step, I would like to develop a (sub) program that captures the X, Y coordinates of the blue point and converted into the indices for my driving level list. As a starting point, I choose the sample program All essential methods (functions) (hereinafter referred to bold) used as examples:

 from bluedot import Bluedot
 from time import sleep, time
 dot = Bluedot(auto_start_server = False)
 def pressed(POS):
     print("Pressed: x = {} y = {} angle = {} distance = {} middle = {} top = {} bottom = {} left = {} right = {} time = {}".format(POS.X, POS.y, POS.angle, POS.spacer, POS.middle, POS.Top, POS.bottom, POS.leaf, POS.right, time()))
 def released():
     print("Released: x = {} y = {}".format(dot.position.X, dot.position.y))
 def moved(POS):
     print("Moved: X = {} Y = {}".format(POS.X, POS.y))
 def swiped(swipe):
     print("Swiped: up = {} down = {} left = {} right = {} speed = {}".format(swipe.up, swipe.down, swipe.leaf, swipe.right, swipe.speed))
 def Double_Presed(POS):
     print("Double pressed: x = {} y = {}".format(POS.X, POS.y))
 def client_connected():
     print("Connected Callback")
 def client_disconnected():
     print("Disconnected Callback")
 dot.when_client_connects = client_connected
 dot.when_client_disconnects = client_disconnected
 dot.When_Pressed = pressed
 dot.When_Released = released
 dot.When_Moved = moved
 dot.When_swiped = swiped
 dot.when_double_pressed = Double_Presed
 print("Wait for Press")
 print("Wait for Move")
 print("Wait for Release")
 print("Wait for Double Press")
 print("Wait for Swipe")
     while True:

As usual with object -oriented programming, self -defined functions are called up by methods. Be recognized dot.when_client_connects and dot.When_client_disconnects For the connection Raspberry Pi and smartphone, as well as dot.when_pressed, dot.when_released, dot.When_moved, dot.When_swiped and dot.When_double_pressed for interaction with the blue point.

In the self-defined functions, only the type of interaction and the respective data are issued with the print command. Here I started to calculate my driving levels from the X and Y coordinates. So: The decimal values ​​between -1.0 and +1.0 are to be converted between 0 and 10 in integer numbers. To do this, I multiply the values ​​with 5, round without decimal places and add 5. These values ​​are then the indices of my list of driving levels.

After a lot of trying out, I decided to only use the When_Pressed method. The Robot Car drives approximately in the direction that is typed on the blue dot. When tapping the middle or when the Bluetooth connection is interrupted by the back button (triangular icon) on the smartphone, the Robot Car stops.

Next I have to do these program sets with the program from the blog Robot Car with Raspberry Pi of April 24, 2021 associate. Last year I took keyboard commands for the control. This part can now be omitted, but I would like to take over the implementation of the Y and X values ​​in driving stages. (download)

 #! /usr/bin/python3
 # Code for Driving A Robot Car With Motozero
 # Motors Attached to M3 and M4
 # For Motor Control, Use Android App Bluedot by Martin O'hanlon
 # Install Python Library (modules) with: Sudo PIP3 Install Bluedot
 # By Bernd54albrecht for AZ-Delivery
 from bluedot import Bluedot
 from time import sleep
 from Gpiocero import Robot, engine, Outputdevice
 import _thread  
 dot = Bluedot(auto_start_server = False)
 robot = Robot(leaf=(23,16), right=(13,18))
 Motor1_enable = Outputdevice(12, Initial_value=1)
 Motor2_enable = Outputdevice(25, Initial_value=1)
 y = 5    # Index for Rate of Speed ​​0
 X = 5    # Index for Straight Ahead
 def pressed(POS):
     y = intimately(round(5*POS.y +5,0))
     X = intimately(round(5*POS.X +5,0))
     print("Pressed, Y, X =",y,X)
 def client_connected():
     print("Connected Callback")
 def client_disconnected():
     print("Disconnected Callback")
 def gutcode():
     dot.When_Pressed = pressed
     print("Wait for Press")
 def engine(y,X):
     print("Y =",y, "X =", X)
     Speed ​​level = [-600,-500,-400,-320,-250,0,250,320,400,500,600]
     speed = Speed ​​level[y]
         IF X==10:
         leaf = min(speed+250,600)
         right = Max(speed-250,-600)
     elif X==9:
         leaf = min(speed+200,600)
         right = Max(speed-200,-600)
     elif X==8:
         leaf = min(speed+150,600)
         right = Max(speed-150,-600)    
     elif X==7:
         leaf = min(speed+100,600)
         right = Max(speed-100,-600)
     elif X==6:
         leaf = min(speed+50,600)
         right = Max(speed-50,-600)
     elif X==4:
         right = min(speed+50,600)
         leaf = Max(speed-50,-600)
     elif X==3:
         right = min(speed+100,600)
         leaf = Max(speed-100,-600)
     elif X==2:
         right = min(speed+150,600)
         leaf = Max(speed-150,-600)          
     elif X==1:
         right = min(speed+200,600)
         leaf = Max(speed-200,-600)
     elif X==0:
         right = min(speed+250,600)
         leaf = Max(speed-250,-600)
         leaf = speed
         right = speed
     robot.value = (leaf/1000, right/1000)
     dot.when_client_connects = client_connected
     dot.when_client_disconnects = client_disconnected  
     while True:

Perfect, the driving levels and the corrections for the cornering fit for the few free square meters in our living room. This does not necessarily have to be the case with another voltage supply. Then please adjust the values ​​for the driving levels and the corrections for the cornering. It is only important that the mean value of the eleven driving levels (index 5, because the count begins at 0!) Is always 0. For the autostart of the program and automatic shutdown of the Raspi at the end, I refer to the Blog Robot Car with Raspberry Pi of April 24, 2021.

Finally, I show a small video of my first driving attempts. Driving is not difficult. If you have typed incorrectly, just press again. It was difficult for me to drive and film at the same time and keep it as a smartphone and robot car in the picture. It is worth imitating, it's really fun. Thanks to Martin O’Hanlon for this easy -to -use Bluetooth app.


Projekte für anfängerRaspberry pi


Andreas Wolter

Andreas Wolter

@Sven: dieser Beitrag zeigt die Verwendung des Raspberry Pi auf dem Robot Car.

Andreas Wolter



Wie bekomme ich das Programm auf den esp32

Leave a comment

All comments are moderated before being published