Ep#42: Optimize Raspberry Pi Code for Yolo Object Detection

Written by:

As i explained in the Video, The machine is now working much more stable thanks to the Yolo object Detection Algorithm. The written code on the raspberry pi was not optimized and since Raspberry pi is considered to be server it is very wise to optimize the code otherwise, it will consume the CPU power of the raspberry pi up to 100% and this will lead to complete stop of the program to run. I got a lot of hints and techniques from chat-gpt to optimize this code.

Below is the written the un-optimized code to control the Servo and DC motors and read and write the Push buttons as well as reading temperature sensor and light sensors. We also simultaneously read and write data via OPC-UA protocol in Python:


from opcua import ua, uamethod, Server
from adafruit_motorkit import MotorKit
from adafruit_servokit import ServoKit
import board
import time
import datetime
from gpiozero import Button
import RPi.GPIO as GPIO
import smbus
import sys
import adafruit_dht



server = Server()

url = "opc.tcp://192.168.1.6:4840"
server.set_endpoint(url)
server.secure_channel_timeout = 500000000
server.session_timeout = 500000000
name = "raspberrypi"
addspace = server.register_namespace(name)
node = server.get_objects_node()
Param = node.add_object(addspace, "Parameters")
Move=  Param.add_variable(addspace, "Movement", 0, ua.VariantType.Float)
Leftpos = Param.add_variable(addspace, "Leftpos",True, ua.VariantType.Boolean)
Rightpos = Param.add_variable(addspace, "Rightpos",True, ua.VariantType.Boolean)
Middlepos = Param.add_variable(addspace, "Middlepos",True, ua.VariantType.Boolean)
Inmotion = Param.add_variable(addspace, "Inmotion",False, ua.VariantType.Boolean)
Warmup = Param.add_variable(addspace, "Warmup", 0)
ServoBase = Param.add_variable(addspace, "ServoBase",130)
ServoHead = Param.add_variable(addspace, "ServoHead",65)
Roomtemp = Param.add_variable(addspace, "Roomtemperature",0)
MoveHome = Param.add_variable(addspace, "MoveHome",False, ua.VariantType.Boolean)
MoveL = Param.add_variable(addspace, "MoveL",False, ua.VariantType.Boolean)
MoveM = Param.add_variable(addspace, "MoveM",False, ua.VariantType.Boolean)
MoveR = Param.add_variable(addspace, "MoveR",False, ua.VariantType.Boolean)

DEVICE_BUS = 1
bus = smbus.SMBus(DEVICE_BUS)
sensor = adafruit_dht.DHT11(board.D5)

global_variable = False
Homing = False
Motion = False
Lplace = False
Mplace = False
Rplace = False

Move.set_writable()
Warmup.set_writable()
ServoBase.set_writable()
ServoHead.set_writable()
Leftpos.set_read_only()
Rightpos.set_read_only()
Middlepos.set_read_only()
Inmotion.set_read_only()
MoveHome.set_writable()
Roomtemp.set_read_only()
MoveM.set_writable()
MoveL.set_writable()
MoveR.set_writable()

kit = MotorKit(0x61)
kit1 = ServoKit(channels = 16)
buttonl = Button(17)
buttonr = Button(18)
buttonm = Button(13)
def  buttonl_pressed():
     Leftpos.set_value(False)
     print('Leftpos is pressed')
def  buttonl_released():
     Leftpos.set_value(True)
     print('Leftpos is Released')
def  buttonr_pressed():
     Rightpos.set_value(False)
     print('Rightpos is pressed')
def  buttonr_released():
     Rightpos.set_value(True)
     print('Rightpos is released')
def  buttonm_pressed():
     Middlepos.set_value(False)
     print('Leftpos is pressed')
def  buttonm_released():
     Middlepos.set_value(True)
     print('Leftpos is Released')

buttonl.when_pressed =  buttonl_pressed
buttonl.when_released =  buttonl_released
buttonr.when_pressed = buttonr_pressed
buttonr.when_released = buttonr_released
buttonm.when_pressed = buttonm_pressed
buttonm.when_released = buttonm_released  
GPIOpin = -1

def Home_Reset(Movingright = False, Movingleft = False):
     
     
 while True:
   if Middlepos.get_value()== True and Rightpos.get_value() == True and Movingleft == False:
      kit.motor2.throttle = 0.7
      Movingright = True
   elif Middlepos.get_value() == False and Movingright == True:
      kit.motor2.throttle = 0
      Movingright = False
      print('Heater is in Home position')
      Motion = False
      return Motion
      break
   elif Rightpos.get_value() == False and Middlepos.get_value()== True :
      Movingright = False
      Movingleft = True
      kit.motor2.throttle = -0.7
   elif Middlepos.get_value() == False and Rightpos.get_value() == True:
      Movingleft = False 
      kit.motor2.throttle = 0
      print('Heater is in Home position')
      Motion = False
      return Motion
      break

def Move_Middle(Movingright = False, Movingleft = False):

 while True:
   if Rightpos.get_value() == False:
      Movingleft = True
      kit.motor2.throttle = -0.7
      
   elif Middlepos.get_value() == False and Movingleft == True:
      Movingleft = False 
      kit.motor2.throttle = 0
      print('Heater is in Middle position')
      Motion = False
      return Motion
      break
   elif Leftpos.get_value() == False:
      Movingright = True
      kit.motor2.throttle = 0.7
   elif Middlepos.get_value() == False and Movingright == True:
      Movingright = False 
      kit.motor2.throttle = 0
      print('Heater is in Middle position')
      Motion = False
      return Motion
      break

def Move_Left(Movingleft = False):
 while True:
     if Leftpos.get_value() == True:
        Movingleft = True
        kit.motor2.throttle = -0.7
     elif Leftpos.get_value() == False:
        Movingleft = False
        kit.motor2.throttle = 0
        print('Heater is in Left position')
        Motion = False
        return Motion
        break
        
def Move_Right(Movingright = False):
 while True:
    if Rightpos.get_value() == True:
        Movingright = True
        kit.motor2.throttle = 0.7
    elif Rightpos.get_value() == False:
        Movingright = False
        kit.motor2.throttle = 0
        print('Heater is in Right position')
        Motion = False
        return Motion
        break
    
server.start()
print("server has started at {}".format(url))

while True:
    
 #Motion = Inmotion.get_value()
 Linear_Motor = Move.get_value()
 kit.motor2.throttle = Linear_Motor
 #print("Middle sensor =",Middlepos.get_value())
 #print("Left sensor =",Leftpos.get_value())
 #print("Right sensor =",Rightpos.get_value()) 
 #print('warmup',Warmup.get_value())
 i = Warmup.get_value()
 if i==1:
     bus.write_byte_data(0x11, 0x01, 0xFF)
     #print('Warmer is On')
 else:
     bus.write_byte_data(0x11, 0x01, 0x00)
     #print('Warmer is Off')    
 ServoBasePos = ServoBase.get_value()
 kit1.servo[0].angle = ServoBasePos
 #print('servobase-position',ServoBasePos)
 ServoHeadPos = ServoHead.get_value()
 kit1.servo[4].angle = ServoHeadPos
 #print('servohead-psoition',ServoHeadPos)
 
 H = MoveHome.get_value()
 if H==True:
    Motion = True
    Home_Reset()
    
 else:
     Motion = False
 
 R = MoveR.get_value()
 if R==True:
    Motion = True
    Move_Right()
    
 else:
     Motion = False
 L = MoveL.get_value()
 if L==True:
    Motion = True
    Move_Left()
    
 else:
     Motion = False
 M = MoveM.get_value()
 if M==True:
    Motion = True
    Move_Middle()
    
 else:
     Motion = False
 time.sleep(2)
  
 try:
        # Print the values to the serial port
        temperature_c = sensor.temperature
        Roomtemp.set_value(temperature_c)
        #print("Temp={0:0.1f}ΒΊC", Roomtemp.get_value())
        time.sleep(2)
 except RuntimeError as error:
        # Errors happen fairly often, DHT's are hard to read, just keep going
        #print(error.args[0])
        
        continue
 except Exception as error:
        sensor.exit()
        raise error

 
 
 

 


 

Although the unoptimized Code works but as i said it was too slow and takes alot of resources from the CPU.

Below is the Optimized Version of the code that use functions instead of Conditional statements. This is very optimal version to use your logic in well defined Function and later Call these functions at the required moment instead of using a lot of If-condition statements in a while loop to provide the necessary condition to do a specific job. please take a look at the optimized Version below:

from opcua import ua, Server
from adafruit_motorkit import MotorKit
from adafruit_servokit import ServoKit
import board
import time
from gpiozero import Button
import smbus
import adafruit_dht

# OPC UA Server setup
server = Server()
url = "opc.tcp://192.168.1.6:4840"
server.set_endpoint(url)
server.secure_channel_timeout = 500000000
server.session_timeout = 500000000
name = "raspberrypi"
addspace = server.register_namespace(name)
node = server.get_objects_node()

# Parameters
Param = node.add_object(addspace, "Parameters")
Move = Param.add_variable(addspace, "Movement", 0, ua.VariantType.Float)
Leftpos = Param.add_variable(addspace, "Leftpos", True, ua.VariantType.Boolean)
Rightpos = Param.add_variable(addspace, "Rightpos", True, ua.VariantType.Boolean)
Middlepos = Param.add_variable(addspace, "Middlepos", True, ua.VariantType.Boolean)
Inmotion = Param.add_variable(addspace, "Inmotion", False, ua.VariantType.Boolean)
Warmup = Param.add_variable(addspace, "Warmup", 0)
ServoBase = Param.add_variable(addspace, "ServoBase", 130)
ServoHead = Param.add_variable(addspace, "ServoHead", 65)
Roomtemp = Param.add_variable(addspace, "Roomtemperature", 0)
MoveHome = Param.add_variable(addspace, "MoveHome", False, ua.VariantType.Boolean)
MoveL = Param.add_variable(addspace, "MoveL", False, ua.VariantType.Boolean)
MoveM = Param.add_variable(addspace, "MoveM", False, ua.VariantType.Boolean)
MoveR = Param.add_variable(addspace, "MoveR", False, ua.VariantType.Boolean)

# Set writable/read-only access
Move.set_writable()
Warmup.set_writable()
ServoBase.set_writable()
ServoHead.set_writable()
MoveHome.set_writable()
MoveM.set_writable()
MoveL.set_writable()
MoveR.set_writable()
Leftpos.set_read_only()
Rightpos.set_read_only()
Middlepos.set_read_only()
Inmotion.set_read_only()
Roomtemp.set_read_only()

# Hardware setup
kit = MotorKit(0x61)
kit1 = ServoKit(channels=16)
buttonl = Button(17)
buttonr = Button(18)
buttonm = Button(13)
sensor = adafruit_dht.DHT11(board.D5)
bus = smbus.SMBus(1)

# Button Handlers
def button_handler(button, position_var):
    def pressed():
        position_var.set_value(False)
        print(f"{button} pressed")
    def released():
        position_var.set_value(True)
        print(f"{button} released")
    return pressed, released

buttonl.when_pressed, buttonl.when_released = button_handler("Leftpos", Leftpos)
buttonr.when_pressed, buttonr.when_released = button_handler("Rightpos", Rightpos)
buttonm.when_pressed, buttonm.when_released = button_handler("Middlepos", Middlepos)

# Motion functions
def move_motor_to_position(target_pos, motor, speed):
    while not target_pos.get_value():
        motor.throttle = speed
        time.sleep(0.05)  # Short delay to reduce CPU usage
    motor.throttle = 0
    print(f"Reached {target_pos}")

def reset_home():
    print("Resetting to Home position...")
    if Middlepos.get_value():
        move_motor_to_position(Middlepos, kit.motor2, 0.7)

def move_to_position(position_var, speed):
    print(f"Moving to {position_var}")
    move_motor_to_position(position_var, kit.motor2, speed)

# Main loop
try:
    server.start()
    print(f"Server started at {url}")

    while True:
        # Control movement
        if MoveHome.get_value():
            reset_home()
            MoveHome.set_value(False)

        if MoveR.get_value():
            move_to_position(Rightpos, 0.7)
            MoveR.set_value(False)

        if MoveL.get_value():
            move_to_position(Leftpos, -0.7)
            MoveL.set_value(False)

        if MoveM.get_value():
            move_to_position(Middlepos, 0.7)
            MoveM.set_value(False)

        # Update servo positions
        kit1.servo[0].angle = ServoBase.get_value()
        kit1.servo[4].angle = ServoHead.get_value()

        # Update room temperature
        try:
            temperature_c = sensor.temperature
            Roomtemp.set_value(temperature_c)
        except RuntimeError:
            pass  # Ignore DHT sensor errors

        # Control the warmer
        bus.write_byte_data(0x11, 0x01, 0xFF if Warmup.get_value() else 0x00)

        # Throttle movement
        kit.motor2.throttle = Move.get_value()

        time.sleep(0.2)  # Reduce CPU usage by adding a delay in the loop

finally:
    server.stop()
    print("Server stopped")

When you compare the Optimized Code you realize that it is shorter and the quality of the code is higher and every thing is packed in Functions that can be called anytime that is needed. This helped my Project a lot. I hope you enjoyed this Episode. πŸ™‚

Like and leave a comment.

money-3

Support Donation.

Please help me to write useful articles for this podcast. Thank you πŸ™‚

€1.00

Leave a comment