In the previous blogs about the Robot Car we have used the robust Uno and Nano compatible microcontrollers. Now let the Raspians come to their rightful place. For the Raspberry Pi there were already motor controllers based on the ICs L293D and kits for robot cars shortly after its appearance in the year 2012. With the annual Pi Wars there is even competition for the most versatile models; the tasks have always been very demanding.
In this blog I would like to use one of the advantages of Raspi and connect a wireless keyboard to the USB port. Furthermore, I use one of the rare Raspberry Pi 3A+, best suited for our purposes. In principle, however, the code listed below works for each Raspi model. As an motor controller I use the MotoZero from ThePiHut. As the name suggests, it is a HAT (Hardware Attached on Top) in Pi Zero format. But the J6 header (better known as GPIO-pins) has been unchanged for years for all models.
A DC-DC converter is indispensable for our construction; I use the LM2596S Step-down DC-DC Buck Converter with 3-digit digital display where the voltages are displayed directly. The switch between input and output voltage is made via the small button on the right next to the three-digit display. Since the voltage is supplied via the 5V pin (Pin 2 or 4), the input voltage for the Raspi must be very precise 5,0 to 5,1 V. Voltage spikes can destroy the Raspberry Pi. That's never happened to me before. But even an unplanned restart is annoying enough, because the boot process takes about a minute.
|1||Raspberry Pi 3A+|
|or Raspberry Pi 3B / 3B+
or Raspberry Pi Zero / WH
Note: In the end we also want to use WLAN
|1||Engine Controller Moto Zero|
|1||LM2596S Step-down DC-DC Buck Converter with 3-digit digital display|
|1||Robot Car kit with two engines/wheels|
|Battery compartment, Jumper cable, small material|
I have screwed the DC-DC converter in the front area below the chassis, as before I have attached casings for the Raspi and the battery compartment with velvet tape or two-sided (carpet) adhesive tape.
Image: Robot Car from above with Raspberry Pi 3A+ and Battery Pack (2 LiPo batteries)
Picture from below: 2 motors and DC-DC-Converter
A few words on the Raspberry Pi 3A+ and MotoZero: The 3A+ model is the cut-off version of the 3B+ with a four-core processor, 512MB memory and WLAN/Bluetooth and one USB-A socket. I can do without a LAN connection and other USB sockets and have the lower power consumption. With the Pi Zero with the simple processor I was particularly annoyed that I always need adapters for HDMI cables and USB.
The MotoZero is a simple motor controller with two L293D ICs. Up to four engines can be controlled. The advantage of a HAT is that you can save a lot of cable connections by sticking it on the J6 header. The MotoZero comes as a kit and must be soldered. In addition, there are these instructions, Tip: Instead of the supplied 40-pole GPIO header, use a so-called Stacking Header, where the pins stand out clearly upwards. The motor controllers do not use all GPIOs, so you can use some pins for sensors or other extensions. For construction reasons, I used the connections Engine 3 and 4. And as I've learned in experiments, the reference voltage for pulse width modulation (PWM), i.e. engine control, is at the Enable Pin of the L293D.
|Positive (+) Terminal||24||6||23||13|
|Negative (-) Terminal||27||22||16||18|
As in previous blog posts on the Raspberry Pi and Python I also this time enthuse about the program module gpiozero by Ben Nuttall and others, for me a prime example for object-oriented programming. Of course, all functions for the control of motors, but also the measurement of sensor data, are implemented.
Since we use the same engines as before, I have decided again for the system with the five driving stages per direction. As a reminder, if the voltage is too low, the motors only grumble, but do not run. And as a function of the voltage supply, the voltage may also be limited. Therefore, the speedLevel list with the 11 elements can look different for your setup. For gpiozero, the values must be between -1 and + 1; therefore, the division is made by 1000 when the value is allocated. In addition, I am therefore able to use the self-developed remote control systems with HC-12 and nRF24L01 again.
# Code for driving a robot car with MotoZero
# Motors attached to M3 and M4
# For motor control, use keybord w, a, s, y or arrow keys
# By Bernd54Albrecht for AZ-Delivery
from gpiozero import Robot, Motor, OutputDevice, LED
from signal import pause
robot = Robot (left = (16, 23), right = (13, 18))
motor1_enable = OutputDevice (12, initial_value= 1)
motor2_enable = OutputDevice (25, initial_value= 1)
led = LED (4)
code = 505
inkey_buffer = 1
def inkey ():
tty.setraw (sys.stdin.fileno ())
termios.tcsetattr (fd, termios.TCSADRAIN, remember_attributes)
def readkey ():
k1 = inkey ()
if ord (k1)! = 0x1b:
k2 = inkey ()
if ord (k2)! = 0x5b:
k3 = inkey ()
return chr (0x10 + ord (k3)-65) # 16 = Up, 17 = Down, 18 = Right, 19 = Left arrows
def getCode ():
key = readkey ()
print ("key =", key, "ord (key)", ord (key))
if (key == 'w' or ord (key) == 16) and code <1000:
code = code + 100
elif (key == 'y' or ord (key) == 17) and code> 100:
code = code-100
elif (key == 's' or ord (key) == 18) and code%100 <10:
code = code + 1
elif (key == 'a' or ord (key) == 19) and code%100 > 0:
code = code-1
elif key == ' ':
code = 505
elif ord (key) == 3:
def motor (y, x):
print ("y =", y, " x = ", x)
speedLevel = [-600, -500, -400, -320, -250,0, 250, 320, 400,500, 600]
speed = speedLevel [y]
if x == 10:
left = min (speed + 250, 600)
right = max (speed-250, -600)
elif x == 9:
left = min (speed + 200, 600)
right = max (speed-200, -600)
elif x == 8:
left = min (speed + 150, 600)
right = max (speed-150, -600)
elif x == 7:
left = min (speed + 100, 600)
right = max (speed-100, -600)
elif x == 6:
left = min (speed + 50, 600)
right = max (speed-50, -600)
elif x == 4:
right = min (speed + 50, 600)
left = max (speed-50, -600)
elif x == 3:
right = min (speed + 100, 600)
left = max (speed-100, -600)
elif x == 2:
right = min (speed + 150, 600)
left = max (speed-150, -600)
elif x == 1:
right = min (speed + 200, 600)
left = max (speed-200, -600)
elif x == 0:
right = min (speed + 250, 600)
left = max (speed-250, -600)
left = speed
right = speed
robot.value = (left/1000, right/1000)
y = int (code/100)
x = code-100 *y
_thread.start_new_thread (motor, (y, x))
In the program I use a program module, with which I can query a single key press even without a return key. However, this module requires that it is started in the terminal. Otherwise you get the following error message:
Image: Error message if the program is not started in the terminal
Those who do not want to do this can do without the module and work with the input command. However, every input must be completed with the Return key.
In my setup, the Python program will start in the terminal anyway, as I have written the program start to the autostart file. So I can also start the Raspi without a monitor and have my Robot Car ready after booting. For Autostart there are various methods that have changed in recent years, too. I use the possibility, which is officially called "System method". To do this, open the above file with:
sudo nano /etc/xdg/lxsession/LXDE-pi/autostart
From the following lines, you will already find the first three in the autostart file:
@lxpanel -- profile LXDE-pi
@pcmanfm --desktop -- profile LXDE-pi
@lxterminal -e python3 /path/my_script.py
With the fourth line, I start the terminal and carry out our Python3 program. What is important is that the program is specified with the full path, in my case
@lxterminal -e python3 /home/pi/robotCar/robotCar_MotoZero3_4_Code505.py
As an indication that the system and program start is complete, I have connected an LED to pin 4. So whenthis lights up, the little robot car is ready for use and waits for the keyboard commands w, a, s, f, the arrow keys or spacebar for the quick stop. Ctrl + C will terminate the program.
If you do not have a radio keypad, you can, of course, also use the program in a terminal program on the PC, e.g. Putty, start.
Image: Putty Configuration and Start
After logging in, switch to the correct directory, in my case
and start the Python program with
However, a new instance of the Terminal and Python program is started. So if your RobotCar buckles while driving, runs parallel still the program opened with autostart This must first complete and if necessary are removed from autostart.
Picture: Putty Login and program start
The program is terminated with Ctrl + C; and if you want to shut down the Raspi, enter the following:
sudo shutdown-h now
Finally, the opposite to the autostart, the automatic shutdown without a monitor and keyboard. A tool of Adafruit, but incomprehensible without the explanation by Michael Horne (https://www.recantha.co.uk/blog/).
The whole thing works by briefly connecting the last two pins (board #39= Ground and #40= GPIO21), no matter whether you have a short-circuit plug or a paper clip.
The program is required git, which is pre-installed in the Raspberry Pi OS today. Who doesn't have it yet, starts with (after the mandatory update and upgrade)
sudo apt-get install git
With git clone, the Adafruit script will be downloaded:
git clone https://github.com/adafruit/Adafruit-GPIO-Halt
or git clone git://github.com/adafruit/Adafruit-GPIO-Halt
Cloning means that the directory has now been copied to our Raspi. We switch to this directory
There, we enter the following commands one after the other:
sudo make install
This will install the script in the /usr/local/bin/gpio-halt directory
To run this script as a "service", we create the required file with:
sudo nano /lib/systemd/system/gpio-halt.service
Description = Short pins 21 and ground to shutdown the Pi
ExecStart=/usr/local/bin/gpio-halt 21 &
In nano, the script is saved with Ctrl + o and okay, then nano is ended with Ctrl + x.
We are back in the terminal on the Command Line. Here the program is made executable with:
sudo chmod 644 /lib/systemd/system/gpio-halt.service
And systemd is supposed to use the script from now on:
sudo systemctl daemon-reload
sudo systemctl enable gpio-halt.service
At the end, the Raspi will be
rebooted and we can try the script.
Have fun trying out.