Python3 parallel programing/output - Grove Display and Motor

Hello,

I have a python(3) program where i control some motors and sensors. Now I added a display.

I want to do the “motor-output” parallel to the “diplay-output”. Not one after the other.
Do i need multiprocessing or concurrency here? And how would i do it in my program?
Or is there an easier way?

The program:

#!/usr/bin/python

-- coding: latin-1 --

import grovepi
import time
import smbus2 as smbus
from raspberry_i2c_tb6612fng import MotorDriverTB6612FNG, TB6612FNGMotors
driver = MotorDriverTB6612FNG()
_COMMAND_MODE = 0x80
_DATA_MODE = 0x40
_NORMAL_DISPLAY = 0xA6

_DISPLAY_OFF = 0xAE
_DISPLAY_ON = 0xAF
_INVERSE_DISPLAY = 0xA7
_SET_BRIGHTNESS = 0x81

BasicFont = [[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
[0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00],
[0x00, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00],
[0x00, 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00, 0x00],
[0x00, 0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00, 0x00],
[0x00, 0x23, 0x13, 0x08, 0x64, 0x62, 0x00, 0x00],
[0x00, 0x36, 0x49, 0x55, 0x22, 0x50, 0x00, 0x00],
[0x00, 0x00, 0x05, 0x03, 0x00, 0x00, 0x00, 0x00],
[0x00, 0x1C, 0x22, 0x41, 0x00, 0x00, 0x00, 0x00],
[0x00, 0x41, 0x22, 0x1C, 0x00, 0x00, 0x00, 0x00],
[0x00, 0x08, 0x2A, 0x1C, 0x2A, 0x08, 0x00, 0x00],
[0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00],
[0x00, 0xA0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00],
[0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00],
[0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00],
[0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00],
[0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, 0x00],
[0x00, 0x00, 0x42, 0x7F, 0x40, 0x00, 0x00, 0x00],
[0x00, 0x62, 0x51, 0x49, 0x49, 0x46, 0x00, 0x00],
[0x00, 0x22, 0x41, 0x49, 0x49, 0x36, 0x00, 0x00],
[0x00, 0x18, 0x14, 0x12, 0x7F, 0x10, 0x00, 0x00],
[0x00, 0x27, 0x45, 0x45, 0x45, 0x39, 0x00, 0x00],
[0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30, 0x00, 0x00],
[0x00, 0x01, 0x71, 0x09, 0x05, 0x03, 0x00, 0x00],
[0x00, 0x36, 0x49, 0x49, 0x49, 0x36, 0x00, 0x00],
[0x00, 0x06, 0x49, 0x49, 0x29, 0x1E, 0x00, 0x00],
[0x00, 0x00, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00],
[0x00, 0x00, 0xAC, 0x6C, 0x00, 0x00, 0x00, 0x00],
[0x00, 0x08, 0x14, 0x22, 0x41, 0x00, 0x00, 0x00],
[0x00, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x00],
[0x00, 0x41, 0x22, 0x14, 0x08, 0x00, 0x00, 0x00],
[0x00, 0x02, 0x01, 0x51, 0x09, 0x06, 0x00, 0x00],
[0x00, 0x32, 0x49, 0x79, 0x41, 0x3E, 0x00, 0x00],
[0x00, 0x7E, 0x09, 0x09, 0x09, 0x7E, 0x00, 0x00],
[0x00, 0x7F, 0x49, 0x49, 0x49, 0x36, 0x00, 0x00],
[0x00, 0x3E, 0x41, 0x41, 0x41, 0x22, 0x00, 0x00],
[0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C, 0x00, 0x00],
[0x00, 0x7F, 0x49, 0x49, 0x49, 0x41, 0x00, 0x00],
[0x00, 0x7F, 0x09, 0x09, 0x09, 0x01, 0x00, 0x00],
[0x00, 0x3E, 0x41, 0x41, 0x51, 0x72, 0x00, 0x00],
[0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, 0x00],
[0x00, 0x41, 0x7F, 0x41, 0x00, 0x00, 0x00, 0x00],
[0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, 0x00, 0x00],
[0x00, 0x7F, 0x08, 0x14, 0x22, 0x41, 0x00, 0x00],
[0x00, 0x7F, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00],
[0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F, 0x00, 0x00],
[0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00, 0x00],
[0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00, 0x00],
[0x00, 0x7F, 0x09, 0x09, 0x09, 0x06, 0x00, 0x00],
[0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00, 0x00],
[0x00, 0x7F, 0x09, 0x19, 0x29, 0x46, 0x00, 0x00],
[0x00, 0x26, 0x49, 0x49, 0x49, 0x32, 0x00, 0x00],
[0x00, 0x01, 0x01, 0x7F, 0x01, 0x01, 0x00, 0x00],
[0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00, 0x00],
[0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00, 0x00],
[0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00, 0x00],
[0x00, 0x63, 0x14, 0x08, 0x14, 0x63, 0x00, 0x00],
[0x00, 0x03, 0x04, 0x78, 0x04, 0x03, 0x00, 0x00],
[0x00, 0x61, 0x51, 0x49, 0x45, 0x43, 0x00, 0x00],
[0x00, 0x7F, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00],
[0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00],
[0x00, 0x41, 0x41, 0x7F, 0x00, 0x00, 0x00, 0x00],
[0x00, 0x04, 0x02, 0x01, 0x02, 0x04, 0x00, 0x00],
[0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
[0x00, 0x01, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00],
[0x00, 0x20, 0x54, 0x54, 0x54, 0x78, 0x00, 0x00],
[0x00, 0x7F, 0x48, 0x44, 0x44, 0x38, 0x00, 0x00],
[0x00, 0x38, 0x44, 0x44, 0x28, 0x00, 0x00, 0x00],
[0x00, 0x38, 0x44, 0x44, 0x48, 0x7F, 0x00, 0x00],
[0x00, 0x38, 0x54, 0x54, 0x54, 0x18, 0x00, 0x00],
[0x00, 0x08, 0x7E, 0x09, 0x02, 0x00, 0x00, 0x00],
[0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C, 0x00, 0x00],
[0x00, 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00, 0x00],
[0x00, 0x00, 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00],
[0x00, 0x80, 0x84, 0x7D, 0x00, 0x00, 0x00, 0x00],
[0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00],
[0x00, 0x41, 0x7F, 0x40, 0x00, 0x00, 0x00, 0x00],
[0x00, 0x7C, 0x04, 0x18, 0x04, 0x78, 0x00, 0x00],
[0x00, 0x7C, 0x08, 0x04, 0x7C, 0x00, 0x00, 0x00],
[0x00, 0x38, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00],
[0x00, 0xFC, 0x24, 0x24, 0x18, 0x00, 0x00, 0x00],
[0x00, 0x18, 0x24, 0x24, 0xFC, 0x00, 0x00, 0x00],
[0x00, 0x00, 0x7C, 0x08, 0x04, 0x00, 0x00, 0x00],
[0x00, 0x48, 0x54, 0x54, 0x24, 0x00, 0x00, 0x00],
[0x00, 0x04, 0x7F, 0x44, 0x00, 0x00, 0x00, 0x00],
[0x00, 0x3C, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00],
[0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00, 0x00],
[0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00, 0x00],
[0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x00],
[0x00, 0x1C, 0xA0, 0xA0, 0x7C, 0x00, 0x00, 0x00],
[0x00, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x00, 0x00],
[0x00, 0x08, 0x36, 0x41, 0x00, 0x00, 0x00, 0x00],
[0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00],
[0x00, 0x41, 0x36, 0x08, 0x00, 0x00, 0x00, 0x00],
[0x00, 0x02, 0x01, 0x01, 0x02, 0x01, 0x00, 0x00],
[0x00, 0x02, 0x05, 0x05, 0x02, 0x00, 0x00, 0x00]]

class GroveOledDisplay128x64(object):
HORIZONTAL = 0x00
VERTICAL = 0x01
PAGE = 0x02

def init(self, bus=2, address=0x3C):
self.bus = smbus.SMBus(bus)
self.address = address

self.off()
self.inverse = False
self.mode = self.HORIZONTAL

self.clear()
self.on()

def on(self):
self.send_command(_DISPLAY_ON)

def off(self):
self.send_command(_DISPLAY_OFF)

def send_command(self, command):
self.bus.write_byte_data(self.address, _COMMAND_MODE, command)

def send_data(self, data):
self.bus.write_byte_data(self.address, _DATA_MODE, data)

def send_commands(self, commands):
for c in commands:
self.send_command©

def clear(self):
self.off()
for i in range(8):
self.set_cursor(i, 0)
self.puts(’ ’ * 16)

self.on()
self.set_cursor(0, 0)

@property
def inverse(self):
return self._inverse

@inverse.setter
def inverse(self, enable):
self.send_command(_INVERSE_DISPLAY if enable else _NORMAL_DISPLAY)
self._inverse = enable

@property
def mode(self):
return self._mode

@mode.setter
def mode(self, mode):
self.send_command(0x20)
self.send_command(mode)
self._mode = mode

def set_cursor(self, row, column):
self.send_command(0xB0 + row)
self.send_command(0x00 + (8column & 0x0F))
self.send_command(0x10 + ((8
column>>4)&0x0F))

def putc(self, c):
C_add = ord©
if C_add < 32 or C_add > 127: # Ignore non-printable ASCII characters
c = ’ ’
C_add = ord©

for i in range(0, 8):
    self.send_data(BasicFont[C_add-32][i])

def puts(self, text):
for c in text:
self.putc©

def show_image(self, image):
from PIL import Image
import numpy as np

im = Image.open(image)

bw = im.convert('1')
pixels = np.array(bw.getdata())
page_size = 128 * 8

self.set_cursor(0, 0)
for page in range(8):
    start = page_size * page
    end = start + page_size

    for i in range(start, start + 128):
        data = np.packbits(pixels[i:end:128][::-1])[0]
        self.send_data(data)

#############################################
test1 = 1
test2 = 1
ur3 = 3 #links ur = mb CHA
ur4 = 4 #rechts ur = mb CHB
#“ultrasonic_ranger” könnte auch anders heißen; hier wird nur dem Platzhalter die Zahl zugewiesen
Abstandswert = 3 #Abstand ur3 nd ur4
Rückwärtswert = 0.5
Drehwert = 1
while True:
if (grovepi.ultrasonicRead(ur3)) <= (Abstandswert):
driver.dc_motor_run(TB6612FNGMotors.MOTOR_CHA, -100) #Motor läuft “rückwärts” → fährt bei 100 langsam; muss noch höher
time.sleep(0.001)
driver.dc_motor_run(TB6612FNGMotors.MOTOR_CHB, -100) #Motor läuft “rückwärts”
print (grovepi.ultrasonicRead(ur3))
time.sleep(Rückwärtswert) #fährt 2sec Rückwärts
driver.dc_motor_run(TB6612FNGMotors.MOTOR_CHA, 100)
time.sleep(0.001)
driver.dc_motor_run(TB6612FNGMotors.MOTOR_CHB, -100)
time.sleep(Drehwert) #dreht 1sec auf der Stelle
if (grovepi.ultrasonicRead(ur3)) > (Abstandswert):
print (“Vorwärts!”)
print (grovepi.ultrasonicRead(ur3))
driver.dc_motor_run(TB6612FNGMotors.MOTOR_CHA, 100)
time.sleep(0.001)
driver.dc_motor_run(TB6612FNGMotors.MOTOR_CHB, 100)
if (grovepi.ultrasonicRead(ur4)) <= (Abstandswert):
print (“Ultraschallsensor4”)
driver.dc_motor_run(TB6612FNGMotors.MOTOR_CHB, -100) #Motor läuft “rückwärts”
time.sleep(0.001)
driver.dc_motor_run(TB6612FNGMotors.MOTOR_CHA, -100) #Motor läuft “rückwärts”
print (grovepi.ultrasonicRead(ur4))
time.sleep(Rückwärtswert) #fährt 2sec Rückwärts
driver.dc_motor_run(TB6612FNGMotors.MOTOR_CHB, 100)
time.sleep(0.001)
driver.dc_motor_run(TB6612FNGMotors.MOTOR_CHA, -100)
time.sleep(Drehwert) #dreht 1sec auf der Stelle
if (grovepi.ultrasonicRead(ur4)) > (Abstandswert):
print (“Vorwärts!”)
print (grovepi.ultrasonicRead(ur4))
driver.dc_motor_run(TB6612FNGMotors.MOTOR_CHA, 100)
time.sleep(0.001)
driver.dc_motor_run(TB6612FNGMotors.MOTOR_CHB, 100)
if test1 == test2:
display = GroveOledDisplay128x64(bus=1) # —AB HIER DISPLAY NEU— test/example Display
display.set_cursor(1, 1)
display.puts(‘UR3 und UR4:’)
display.set_cursor(3, 1)
display.puts(‘Kein Hindernis!’)
display.set_cursor(5, 1)
display.puts(’---------------’)
print (“Ultraschallsensor3”)
time.sleep(10) # —BIS HIER DISPLAY NEU—
time.sleep(0.001) # —BIS HIER DISPLAY NEU—

I tried to put the Display output-“block” after the “if’s” of the sensors/ after (or before) the motor output.
But either I have the problem that the time sleep0.001 makes the display blinking and not readable. Or if i make it longer “time.sleep1.000”… the breaks between the sensor-requests are way too long.

Because of this my idea was to run the display output and the motor output (+sensor request?) parallel.

Thanks for your help!!

1 Like

I know there are ways to make certain of the GoPiGo functions blocking and non-blocking - you may want to take a look at the underlying libraries and see what you can find.

Let us know what you come up with.