Teleoperation Robot
Below is an example Python script for teleoperating a differential drive robot:
from pynput import keyboard
import time
from smd.red import *
from serial.tools.list_ports import comports
from platform import system
class PIDController:
def __init__(self, kp, ki, kd):
self.kp = kp
self.ki = ki
self.kd = kd
self.previous_error = 0
self.integral = 0
def calculate(self, error, delta_time):
self.integral += error * delta_time
derivative = (error - self.previous_error) / delta_time if delta_time > 0 else 0
output = (self.kp * error) + (self.ki * self.integral) + (self.kd * derivative)
self.previous_error = error
return max(min(output, 100), -100)
def USB_Port():
ports = list(comports())
usb_names = {
"Windows": ["USB Serial Port"],
"Linux": ["/dev/ttyUSB"],
"Darwin": [
"/dev/tty.usbserial",
"/dev/tty.usbmodem",
"/dev/tty.SLAB_USBtoUART",
"/dev/tty.wchusbserial",
"/dev/cu.usbserial",
]
}
os_name = system()
if ports:
for port, desc, hwid in sorted(ports):
if any(name in port or name in desc for name in usb_names.get(os_name, [])):
print("Connected!")
return port
print("Available ports:")
for port, desc, hwid in ports:
print(f"Port: {port}, Description: {desc}, HWID: {hwid}")
else:
print("No ports detected!")
return None
def teleoperate_smd():
print("Use W/A/S/D to control the robot. Press Q to quit.")
port = USB_Port()
if not port:
print("No suitable port found. Exiting...")
return
try:
smd = Master(port)
smd.attach(Red(0)) # Left motor (ID 0)
smd.attach(Red(1)) # Right motor (ID 1)
smd.enable_torque(0, 1)
smd.enable_torque(1, 1)
left_pid = PIDController(kp=24.96, ki=0.00, kd=19.10)
right_pid = PIDController(kp=46.97, ki=0.00, kd=18.96)
base_speed = 100
turning_speed = 100 # Speed for turning
last_time = time.time()
def on_press(key):
nonlocal last_time
try:
# Calculate time difference
current_time = time.time()
delta_time = current_time - last_time
last_time = current_time
if hasattr(key, 'char'):
if key.char == 'w': # Move forward
print("Move Forward")
error = base_speed
left_speed = left_pid.calculate(error, delta_time)
right_speed = right_pid.calculate(error, delta_time)
# Send commands to both motors simultaneously
smd.set_duty_cycle(0, -left_speed) # Left motor forward
smd.set_duty_cycle(1, right_speed) # Right motor forward
elif key.char == 's': # Move backward
print("Move Backward")
error = -base_speed
left_speed = left_pid.calculate(error, delta_time)
right_speed = right_pid.calculate(error, delta_time)
# Send commands to both motors simultaneously
smd.set_duty_cycle(0, -left_speed) # Left motor backward
smd.set_duty_cycle(1, right_speed) # Right motor backward
elif key.char == 'a': # Turn left
print("Turn Left")
# Send commands to both motors simultaneously
smd.set_duty_cycle(0, 0) # Left motor stopped
smd.set_duty_cycle(1, turning_speed) # Right motor forward
elif key.char == 'd': # Turn right
print("Turn Right")
# Send commands to both motors simultaneously
smd.set_duty_cycle(0, -turning_speed) # Left motor forward
smd.set_duty_cycle(1, 0) # Right motor stopped
elif key.char == 'q': # Quit
print("Exiting...")
return False
except AttributeError:
pass
def on_release(key):
# Stop both motors simultaneously
smd.set_duty_cycle(0, 0)
smd.set_duty_cycle(1, 0)
# Start keyboard listener
with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
except Exception as e:
print(f"Error: {e}")
finally:
# Stop both motors simultaneously during cleanup
smd.set_duty_cycle(0, 0)
smd.set_duty_cycle(1, 0)
smd.enable_torque(0, 0)
smd.enable_torque(1, 0)
smd.close()
print("SMD connection closed.")
teleoperate_smd()
Last updated