Hi, I want to use an additional servo for a project I am working on. How do I read input and code it?
If you want to add extra servos to picar-x, you can refer to our picarx.py code to expand on the original code, which requires you to modify the code yourself.
You need to modify the code by yourself. So you need to have some basic programming skills to expand the code.
Thank you, that works
I modified the code on picar-x.py to add the additional servo, see below. When I try to run it, it gives me the following message: Attribute Error: ‘Picarx’ object has no attribute ‘set_nerf_gun_angle’.
The code I use to modify the angle of the additional servo is px.set_nerf_gun_angle(30)
The modified picar-x.py code below:
from robot_hat import Pin, ADC, PWM, Servo, fileDB
from robot_hat import Grayscale_Module, Ultrasonic
from robot_hat import Pin, ADC, PWM, Servo, fileDB
from robot_hat import Grayscale_Module, Ultrasonic, reset_mcu
Remove this line: from robot_hat.utils import reset_mcu, run_comman2
import time
import os
import time
import os
reset robot_hat
reset_mcu()
time.sleep(0.2)
def constrain(x, min_val, max_val):
‘’’
Constrains value to be within a range.
‘’’
return max(min_val, min(max_val, x))
class Picarx(object):
CONFIG = ‘/opt/picar-x/picar-x.conf’
DEFAULT_LINE_REF = [1000, 1000, 1000]
DEFAULT_CLIFF_REF = [500, 500, 500]
DIR_MIN = -35
DIR_MAX = 35
CAM_PAN_MIN = -90
CAM_PAN_MAX = 90
CAM_TILT_MIN = -35
CAM_TILT_MAX = 65
NERF_GUN_MIN = -90
NERF_GUN_MAX = 90
PERIOD = 4095
PRESCALER = 10
TIMEOUT = 0.02
# servo_pins: camera_pan_servo, camera_tilt_servo, direction_servo
# motor_pins: left_swicth, right_swicth, left_pwm, right_pwm
# grayscale_pins: 3 adc channels
# ultrasonic_pins: tring, echo
# config: path of config file
def __init__(self,
servo_pins:list=['P0', 'P1', 'P2', 'P3'],
motor_pins:list=['D4', 'D5', 'P12', 'P13'],
grayscale_pins:list=['A0', 'A1', 'A2'],
ultrasonic_pins:list=['D2','D3'],
config:str=CONFIG,
):
# --------- config_flie ---------
self.config_flie = fileDB(config, 774, os.getlogin())
# --------- servos init ---------
self.cam_pan = Servo(servo_pins[0])
self.cam_tilt = Servo(servo_pins[1])
self.dir_servo_pin = Servo(servo_pins[2])
self.nerf_gun = Servo(servo_pins[3])
# get calibration values
self.dir_cali_val = float(self.config_flie.get("picarx_dir_servo", default_value=0))
self.cam_pan_cali_val = float(self.config_flie.get("picarx_cam_pan_servo", default_value=0))
self.cam_tilt_cali_val = float(self.config_flie.get("picarx_cam_tilt_servo", default_value=0))
self.nerf_gun_cali_val = float(self.config_flie.get("picarx_nerf_gun_servo", default_value=0))
# set servos to init angle
self.dir_servo_pin.angle(self.dir_cali_val)
self.cam_pan.angle(self.cam_pan_cali_val)
self.cam_tilt.angle(self.cam_tilt_cali_val)
self.nerf_gun.angle(self.nerf_gun_cali_val)
# --------- motors init ---------
self.left_rear_dir_pin = Pin(motor_pins[0])
self.right_rear_dir_pin = Pin(motor_pins[1])
self.left_rear_pwm_pin = PWM(motor_pins[2])
self.right_rear_pwm_pin = PWM(motor_pins[3])
self.motor_direction_pins = [self.left_rear_dir_pin, self.right_rear_dir_pin]
self.motor_speed_pins = [self.left_rear_pwm_pin, self.right_rear_pwm_pin]
# get calibration values
self.cali_dir_value = self.config_flie.get("picarx_dir_motor", default_value="[1, 1]")
self.cali_dir_value = [int(i.strip()) for i in self.cali_dir_value.strip().strip("[]").split(",")]
self.cali_speed_value = [0, 0]
self.dir_current_angle = 0
# init pwm
for pin in self.motor_speed_pins:
pin.period(self.PERIOD)
pin.prescaler(self.PRESCALER)
# --------- grayscale module init ---------
adc0, adc1, adc2 = [ADC(pin) for pin in grayscale_pins]
self.grayscale = Grayscale_Module(adc0, adc1, adc2, reference=None)
# get reference
self.line_reference = self.config_flie.get("line_reference", default_value=str(self.DEFAULT_LINE_REF))
self.line_reference = [float(i) for i in self.line_reference.strip().strip('[]').split(',')]
self.cliff_reference = self.config_flie.get("cliff_reference", default_value=str(self.DEFAULT_CLIFF_REF))
self.cliff_reference = [float(i) for i in self.cliff_reference.strip().strip('[]').split(',')]
# transfer reference
self.grayscale.reference(self.line_reference)
# --------- ultrasonic init ---------
tring, echo= ultrasonic_pins
self.ultrasonic = Ultrasonic(Pin(tring), Pin(echo))
def set_motor_speed(self, motor, speed):
''' set motor speed
param motor: motor index, 1 means left motor, 2 means right motor
type motor: int
param speed: speed
type speed: int
'''
motor -= 1
if speed >= 0:
direction = 1 * self.cali_dir_value[motor]
elif speed < 0:
direction = -1 * self.cali_dir_value[motor]
speed = abs(speed)
if speed != 0:
speed = int(speed /2 ) + 50
speed = speed - self.cali_speed_value[motor]
if direction < 0:
self.motor_direction_pins[motor].high()
self.motor_speed_pins[motor].pulse_width_percent(speed)
else:
self.motor_direction_pins[motor].low()
self.motor_speed_pins[motor].pulse_width_percent(speed)
def motor_speed_calibration(self, value):
self.cali_speed_value = value
if value < 0:
self.cali_speed_value[0] = 0
self.cali_speed_value[1] = abs(self.cali_speed_value)
else:
self.cali_speed_value[0] = abs(self.cali_speed_value)
self.cali_speed_value[1] = 0
def motor_direction_calibrate(self, motor, value):
''' set motor direction calibration value
param motor: motor index, 1 means left motor, 2 means right motor
type motor: int
param value: speed
type value: int
'''
motor -= 1
if value == 1:
self.cali_dir_value[motor] = 1
elif value == -1:
self.cali_dir_value[motor] = -1
self.config_flie.set("picarx_dir_motor", self.cali_dir_value)
def dir_servo_calibrate(self, value):
self.dir_cali_val = value
self.config_flie.set("picarx_dir_servo", "%s"%value)
self.dir_servo_pin.angle(value)
def set_dir_servo_angle(self, value):
self.dir_current_angle = constrain(value, self.DIR_MIN, self.DIR_MAX)
angle_value = value + self.dir_cali_val
self.dir_servo_pin.angle(angle_value)
def nerf_gun_servo_calibrate(self, value):
self.nerf_gun_cali_val = value
self.config_flie.set("picarx_nerf_gun_servo", "%s"%value)
self.nerf_gun.angle(value)
def cam_pan_servo_calibrate(self, value):
self.cam_pan_cali_val = value
self.config_flie.set("picarx_cam_pan_servo", "%s"%value)
self.cam_pan.angle(value)
def cam_tilt_servo_calibrate(self, value):
self.cam_tilt_cali_val = value
self.config_flie.set("picarx_cam_tilt_servo", "%s"%value)
self.cam_tilt.angle(value)
def set_cam_pan_angle(self, value):
value = constrain(value, self.CAM_PAN_MIN, self.CAM_PAN_MAX)
self.cam_pan.angle(-1*(value + -1*self.cam_pan_cali_val))
def set_camera_tilt_angle(self, value):
value = constrain(value, self.CAM_TILT_MIN, self.CAM_TILT_MAX)
self.cam_tilt.angle(-1*(value + -1*self.cam_tilt_cali_val))
def set_nerf_gun_angle(self, value):
self.nerf_gun_servo_calibrate(value)
value = constrain(value, self.NERF_GUN_MIN, self.NERF_GUN_MAX)
self.nerf_gun.angle(value)
#self.nerf_gun.angle(-1*(value ))
def set_power(self, speed):
self.set_motor_speed(1, speed)
self.set_motor_speed(2, speed)
def backward(self, speed):
current_angle = self.dir_current_angle
if current_angle != 0:
abs_current_angle = abs(current_angle)
if abs_current_angle > 40:
abs_current_angle = 40
power_scale = (100 - abs_current_angle) / 100.0
if (current_angle / abs_current_angle) > 0:
self.set_motor_speed(1, -1*speed)
self.set_motor_speed(2, speed * power_scale)
else:
self.set_motor_speed(1, -1*speed * power_scale)
self.set_motor_speed(2, speed )
else:
self.set_motor_speed(1, -1*speed)
self.set_motor_speed(2, speed)
def forward(self, speed):
current_angle = self.dir_current_angle
if current_angle != 0:
abs_current_angle = abs(current_angle)
if abs_current_angle > 40:
abs_current_angle = 40
power_scale = (100 - abs_current_angle) / 100.0
if (current_angle / abs_current_angle) > 0:
self.set_motor_speed(1, 1*speed * power_scale)
self.set_motor_speed(2, -speed)
else:
self.set_motor_speed(1, speed)
self.set_motor_speed(2, -1*speed * power_scale)
else:
self.set_motor_speed(1, speed)
self.set_motor_speed(2, -1*speed)
def stop(self):
self.set_motor_speed(1, 0)
self.set_motor_speed(2, 0)
def get_distance(self):
return self.ultrasonic.read()
def set_grayscale_reference(self, value):
if isinstance(value, list) and len(value) == 3:
self.line_reference = value
self.grayscale.reference(self.line_reference)
self.config_flie.set("line_reference", self.line_reference)
else:
raise ValueError("grayscale reference must be a 1*3 list")
def get_grayscale_data(self):
return list.copy(self.grayscale.read())
def get_line_status(self,gm_val_list):
return self.grayscale.read_status(gm_val_list)
def set_line_reference(self, value):
self.set_grayscale_reference(value)
def set_cliff_reference(self, value):
if isinstance(value, list) and len(value) == 3:
self.cliff_reference = value
self.config_flie.set("cliff_reference", self.cliff_reference)
else:
raise ValueError("grayscale reference must be a 1*3 list")
if name == “main”:
px = Picarx()
px.forward(50)
time.sleep(1)
px.stop()
After modifying the picarx.py file, do you do a reinstallation, which is required for it to take effect:
cd ~/picar-x
sudo python3 setup.py install
This may be required for bookworm systems:
sudo python3 setup.py install --break-system-packages
I have tried with the reinstallation sudo python3 setup.py install but it still not working
What do you mean by break system packages? Thank you
“sudo python3 setup.py install --break-system-packages”
This is a one-line install command.
If you are currently using a bookworm system, running sudo python3 setup.py install install command needs to be followed by --break-system-packages, so you need to run:
sudo python3 setup.py instal --break-system-packages
Once the installation is successful, you can run the code script again to see if it solves the problem. If you still get an error, please provide us a screenshot of the error.