02 Python Chassis Motion Control

From Waveshare Wiki
Revision as of 07:17, 21 March 2024 by Eng52 (talk | contribs) (Created page with "<div class="wiki-pages jet-green-color"> ='''Python Chassis Motion Control'''= In this chapter, we'll craft a Python routine for controlling the motion of a robot's chassis....")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Python Chassis Motion Control

In this chapter, we'll craft a Python routine for controlling the motion of a robot's chassis. This approach can be adapted to other programming languages for similar motion control tasks.

Control Mechanism Overview

We utilize code blocks within JupyterLab to compose JSON commands. These commands are then dispatched to the microcontroller via the GPIO serial port on a Raspberry Pi (the default baud rate for communication with the microcontroller is 115200). Upon receiving these commands, the microcontroller executes the specified actions.

Further sections will delve into the variety of commands that can be sent to the microcontroller. Alternatively, you might choose to implement these functionalities in a different programming language or develop a dedicated application for the controlling system.

Design Advantages

Adopting a master-slave architecture significantly liberates the resources of the master device. In this setup, the master device (such as a Raspberry Pi or Jetson SBC) acts as the brain, while the ESP32 microcontroller serves as a cerebellum-like entity handling the lower-level motion controls. This division of labor allows the master device to focus on high-level tasks like vision processing and decision-making, while the microcontroller efficiently manages precise movement control and other low-level tasks. Such an arrangement ensures that the microcontroller can maintain accurate wheel rotation speeds through high-frequency PID control, without overburdening the master device with computationally intensive tasks.

Main Program (app.py)

The main program of the product, app.py, automatically executes upon booting due to the configuration set by autorun.sh (which is pre-configured in the product). Running app.py occupies the GPIO serial port and the camera, which might lead to conflicts or errors if other tutorials or programs require these resources. Ensure to disable the auto-start of app.py before proceeding with development or learning.

As app.py employs multithreading and uses crontab for autostart, typical commands like sudo killall python won't suffice to terminate it. You would need to comment out the relevant line in crontab and reboot the device.

crontab -e

Upon your first use of this command, you will be prompted to select an editor to open the crontab file. It is recommended to choose 'nano' by entering the corresponding number for nano, followed by pressing the Enter key to confirm.
Use the '#' symbol to comment out the line containing "...... app.py".

# @reboot ~/ugv_pt_rpi/ugv-env/bin/python ~/ugv_pt_rpi/app.py >> ~/ugv.log 2>&1
@reboot /bin/bash ~/ugv_pt_rpi/start_jupyter.sh >> ~/jupyter_log.log 2>&1

Note: Make sure not to comment out the line containing "start_jupyter.sh", as doing so will prevent JupyterLab from launching on startup, disabling your access to interactive tutorials.

To exit and save the changes, after editing the content of crontab, press Ctrl + X to exit nano. Since you have made edits to the crontab file, it will ask if you want to save the changes (Save modified buffer?). Enter the letter 'Y' and then press Enter to exit and save the modifications.

After restarting the device, the main program will no longer run automatically upon boot-up, allowing you to freely use the tutorials within JupyterLab. If you wish to re-enable the automatic execution of the main program at startup in the future, you can reopen the crontab file using the method described above. Simply remove the '#' symbol in front of the '@' symbol, then exit and save the changes. This will restore the automatic startup functionality of the main program.

Chassis Control Demo

In the following routine, we use the is_raspberry_pi5() function to determine the model of the Raspberry Pi since the device names for the GPIO serial port differ between Raspberry Pi 4B and Raspberry Pi 5. It's crucial to use the correct device name and baud rate (default 115200) that matches the microcontroller.
Before executing the code block below, ensure the robot is elevated so that the drive wheels are off the ground. Activating the code will cause the robot to move; take precautions to prevent it from falling off the table.

from base_ctrl import BaseController
import time

# Function for Detecting Raspberry Pi
def is_raspberry_pi5():
    with open('/proc/cpuinfo', 'r') as file:
        for line in file:
            if 'Model' in line:
                if 'Raspberry Pi 5' in line:
                    return True
                else:
                    return False

# Determine the GPIO Serial Device Name Based on the Raspberry Pi Model
if is_raspberry_pi5():
    base = BaseController('/dev/ttyAMA0', 115200)
else:
    base = BaseController('/dev/serial0', 115200)

# The wheel rotates at a speed of 0.2 meters per second and stops after 2 seconds.
base.send_command({"T":1,"L":0.2,"R":0.2})
time.sleep(2)
base.send_command({"T":1,"L":0,"R":0})

By invoking the code block mentioned above, the Raspberry Pi will initially send the command {"T":1,"L":0.2,"R":0.2} (the structure of commands will be discussed in more detail in later chapters). This command starts the wheels turning. After a two-second interval, the Raspberry Pi will send another command {"T":1,"L":0,"R":0}, causing the wheels to stop. It's important to note that even if the command to stop the wheels isn't sent, the wheels will still cease turning if no new commands are issued. This is due to a heartbeat function built into the subordinate machine. The purpose of this heartbeat function is to halt the current motion command automatically if the master control hasn't sent any new commands to the subordinate machine for an extended period. This function is designed to prevent continuous motion of the subordinate machine in case the master control encounters a problem that leads to a freeze or crash.

If you want the robot to continue moving indefinitely, the master control unit needs to cyclically send motion control commands every 2 to 4 seconds.

Chassis Steering Principle

The earlier routine allows you to make the robot move forward for two seconds before stopping. Further adjustments to the parameters can control the direction of the chassis, based on the differential steering principle.

When turning, the inner wheels (on the side towards which the turn is made) travel a shorter distance and thus should rotate slower to maintain stability. The differential gear system achieves this by allowing the drive wheels to rotate at different speeds. Usually, the outer wheels (on the opposite side of the turn) rotate faster than the inner wheels. This variation in speed results in the turning motion of the vehicle, allowing it to steer in the intended direction.

You can control the vehicle's steering by assigning different target linear velocities to each wheel, thus achieving maneuverability and easily adjustable turning radii.