电频车自动跟随系统的基本原理是通过无线通信模块和超声波模块实现小车对移动目标的定位和跟随。你需要准备以下硬件模块:
控制器模块:可以使用STM32单片机作为主控制器,负责接收无线信号和超声波信号,计算移动目标的位置,控制电机的转速和方向。
无线收发模块:可以使用NRF24L01无线模块作为无线通信的方式,实现小车和移动目标之间的数据传输。
超声波接收模块:可以使用HC-SR04超声波模块作为超声波信号的接收器,实现小车对移动目标的距离和角度的测量。
电机及电机驱动模块:可以使用直流减速电机作为小车的驱动器,通过PWM信号控制其转速和方向。可以使用L298N电机驱动芯片作为电机的驱动器,实现PWM信号和电机之间的转换。
报警模块:可以使用蜂鸣器或LED灯作为报警器,实现小车在遇到异常情况时发出提示。
电源模块:可以使用锂电池作为小车的电源,提供稳定的供电。
下面是一个可能的Python代码框架:
# 导入相关库
import serial # 串口通信库
import time # 时间库
import RPi.GPIO as GPIO # 树莓派GPIO库
# 定义相关引脚
NRF_CE = 22 # NRF24L01 CE引脚
NRF_CSN = 8 # NRF24L01 CSN引脚
TRIG1 = 16 # 超声波1 TRIG引脚
ECHO1 = 18 # 超声波1 ECHO引脚
TRIG2 = 36 # 超声波2 TRIG引脚
ECHO2 = 38 # 超声波2 ECHO引脚
TRIG3 = 40 # 超声波3 TRIG引脚
ECHO3 = 37 # 超声波3 ECHO引脚
AIN1 = 11 # L298N AIN1引脚
AIN2 = 13 # L298N AIN2引脚
BIN1 = 15 # L298N BIN1引脚
BIN2 = 29 # L298N BIN2引脚
PWMA = 12 # L298N PWMA引脚
PWMB = 32 # L298N PWMB引脚
BUZZER = 31 # 蜂鸣器引脚
# 定义相关参数
SERIAL_PORT = "/dev/ttyAMA0" # 串口端口号
SERIAL_BAUDRATE = 9600 # 串口波特率
FIND_SIGNAL = b'F' # 寻找信号字节
DISTANCE_THRESHOLD = 100 # 距离阈值(cm)
ANGLE_THRESHOLD = 10 # 角度阈值(度)
SPEED_MAX = 100 # 最大速度(%)
SPEED_MIN = 20 # 最小速度(%)
SPEED_STEP = 10 # 速度步进(%)
PWM_FREQUENCY = 50 # PWM频率(Hz)
# 初始化GPIO模式
GPIO.setmode(GPIO.BOARD) # 使用物理引脚编号
# 初始化NRF24L01模块
GPIO.setup(NRF_CE, GPIO.OUT) # 设置CE引脚为输出模式
GPIO.setup(NRF_CSN, GPIO.OUT) # 设置CSN引脚为输出模式
GPIO.output(NRF_CE, GPIO.LOW) # 设置CE引脚为低电平
GPIO.output(NRF_CSN, GPIO.HIGH) # 设置CSN引脚为高电平
# 初始化超声波模块
GPIO.setup(TRIG1, GPIO.OUT) # 设置TRIG1引脚为输出模式
GPIO.setup(ECHO1, GPIO.IN) # 设置ECHO1引脚为输入模式
GPIO.setup(TRIG2, GPIO.OUT) # 设置TRIG2引脚为输出模式
GPIO.setup(ECHO2, GPIO.IN) # 设置ECHO2引脚为输入模式
GPIO.setup(TRIG3, GPIO.OUT) # 设置TRIG3引脚为输出模式
GPIO.setup(ECHO3, GPIO.IN) # 设置ECHO3引脚为输入模式
# 初始化电机及电机驱动模块
GPIO.setup(AIN1, GPIO.OUT) # 设置AIN1引脚为输出模式
GPIO.setup(AIN2, GPIO.OUT) # 设置AIN2引脚为输出模式
GPIO.setup(BIN1, GPIO.OUT) # 设置BIN1引脚为输出模式
GPIO.setup(BIN2, GPIO.OUT) # 设置BIN2引脚为输出模式
GPIO.setup(PWMA, GPIO.OUT) # 设置PWMA引脚为输出模式
GPIO.setup(PWMB, GPIO.OUT) # 设置PWMB引脚为输出模式
# 初始化报警模块
GPIO.setup(BUZZER, GPIO.OUT) # 设置BUZZER引脚为输出模式
# 初始化串口通信对象
ser = serial.Serial(SERIAL_PORT, SERIAL_BAUDRATE)
# 初始化PWM对象
pwm_a = GPIO.PWM(PWMA, PWM_FREQUENCY) # 创建PWMA的PWM对象,设置频率为50Hz
pwm_b = GPIO.PWM(PWMB, PWM_FREQUENCY) # 创建PWMB的PWM对象,设置频率为50Hz
pwm_a.start(0) # 启动PWMA的PWM输出,初始占空比为0%
pwm_b.start(0) # 启动PWMB的PWM输出,初始占空比为0%
# 定义发送寻找信号函数
def send_find_signal():
global ser, FIND_SIGNAL
ser.write(FIND_SIGNAL) # 向串口写入寻找信号字节
# 定义测量超声波距离函数(单位:cm)
def measure_distance(trig_pin, echo_pin):
global GPIO
GPIO.output(trig_pin, GPIO.HIGH) # 发送10us的高电平触发超声波发射
time.sleep(0.00001)
GPIO.output(trig_pin, GPIO.LOW)
while not GPIO.input(echo_pin):
pass
start_time = time.time()
while GPIO.input(echo_pin):
pass
end_time = time.time()
distance = (end_time - start_time) * 340 / 2 * 100
return distance
# 定义计算移动目标位置函数(单位:cm,度)
def calculate_position():
global DISTANCE_THRESHOLD
d1 = measure_distance(TRIG1, ECHO1)
d2 = measure_distance(TRIG2, ECHO2)
d3 = measure_distance(TRIG3, ECHO3)
if d1 > DISTANCE_THRESHOLD or d2 > DISTANCE_THRESHOLD or d3 > DISTANCE_THRESHOLD:
return None
else:
x = (d1**2 + d3**2 - d2**2) / (4 * d3)
y = (d1**2 - x**2)**0.5
angle = math.atan(y / x) * 180 / math.pi
return x, y, angle
# 定义控制电机转速函数(参数:左轮速度,右轮速度,单位:%)
def control_motor_speed(left_speed, right_speed):
global SPEED_MAX, SPEED_MIN, SPEED_STEP
left_speed = max(min(left_speed, SPEED_MAX), -SPEED_MAX) # 限制左轮速度在最大值和最小值之间
right_speed = max(min(right_speed, SPEED_MAX), -SPEED_MAX) # 限制右轮速度在最大值和最小值之间
if left_speed > 0: # 如果左轮速度为正
GPIO.output(AIN1, GPIO.HIGH) # 设置AIN1为高电平,使左轮向前转
GPIO.output(AIN2, GPIO.LOW) # 设置AIN2为低电平
elif left_speed < 0: # 如果左轮速度为负>
GPIO.output(AIN1, GPIO.LOW) # 设置AIN1为低电平,使左轮向后转
GPIO.output(AIN2, GPIO.HIGH) # 设置AIN2为高电平
else: # 如果左轮速度为零
GPIO.output(AIN1, GPIO.LOW) # 设置AIN1为低电平,使左轮停止
GPIO.output(AIN2, GPIO.LOW) # 设置AIN2为低电平
if right_speed > 0: # 如果右轮速度为正
GPIO.output(BIN1, GPIO.HIGH) # 设置BIN1为高电平,使右轮向前转
GPIO.output(BIN2, GPIO.LOW) # 设置BIN2为低电平
elif right_speed < 0: # 如果右轮速度为负>
GPIO.output(BIN1, GPIO.LOW) # 设置BIN1为低电平,使右轮向后转
GPIO.output(BIN2, GPIO.HIGH) # 设置BIN2为高电平
else: # 如果右轮速度为零
GPIO.output(BIN1, GPIO.LOW) # 设置BIN1为低电平,使右轮停止
GPIO.output(BIN2, GPIO.LOW) # 设置BIN2为低电平
pwm_a.ChangeDutyCycle(abs(left_speed)) # 改变PWMA的占空比,控制左轮的转速
pwm_b.ChangeDutyCycle(abs(right_speed)) # 改变PWMB的占空比,控制右轮的转速
# 定义控制小车跟随函数(参数:移动目标的位置)
def control_car_follow(position):
global DISTANCE_THRESHOLD, ANGLE_THRESHOLD
if position is None: # 如果没有检测到移动目标的位置
control_motor_speed(0, 0) # 停止小车运动
beep(3) # 发出三声报警音
else:
x, y, angle = position # 解析移动目标的位置信息
if x > DISTANCE_THRESHOLD: # 如果移动目标距离小车太远
if angle > ANGLE_THRESHOLD: # 如果移动目标偏离小车中心太多(向左)
control_motor_speed(SPEED_MIN + SPEED_STEP * angle / ANGLE_THRESHOLD, SPEED_MAX) # 调整小车的转速,使其向左前进
elif angle < -angle_threshold: # 如果移动目标偏离小车中心太多(向右)>
control_motor_speed(SPEED_MAX, SPEED_MIN + SPEED_STEP * abs(angle) / ANGLE_THRESHOLD) # 调整小车的转速,使其向右前进
else: # 如果移动目标在小车中心附近
control_motor_speed(SPEED_MAX, SPEED_MAX) # 使小车直线前进
elif x < -distance_threshold: # 如果移动目标距离小车太近>
if angle > ANGLE_THRESHOLD: # 如果移动目标偏离小车中心太多(向左)
control_motor_speed(-SPEED_MIN - SPEED_STEP * angle / ANGLE_THRESHOLD, -SPEED_MAX) # 调整小车的转速,使其向左后退
elif angle < -angle_threshold: # 如果移动目标偏离小车中心太多(向右)>
control_motor_speed(-SPEED_MAX, -SPEED_MIN - SPEED_STEP * abs(angle) / ANGLE_THRESHOLD) # 调整小车的转速,使其向右后退
else: # 如果移动目标在小车中心附近
control_motor_speed(-SPEED_MAX, -SPEED_MAX) # 使小车直线后退
else: # 如果移动目标距离小车适中
control_motor_speed(0, 0) # 停止小车运动
# 定义发出报警音函数(参数:次数)
def beep(times):
global BUZZER
for i in range(times):
GPIO.output(BUZZER, GPIO.HIGH)
time.sleep(0.5)
GPIO.output(BUZZER, GPIO.LOW)
time.sleep(0.5)
# 主循环函数
def main():
while True:
send_find_signal()
position = calculate_position()
control_car_follow(position)
# 程序入口函数
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
pwm_a.stop()
pwm_b.stop()
ser.close()
GPIO.cleanup()
领取专属 10元无门槛券
私享最新 技术干货