学习Arduino或者树莓派的过程中,如果仅仅看代码或者做简单实验,那么常常会虎头蛇尾,所以我们建议还是尝试一些简单的机器人项目,这样既有趣也能不断学习提高。本文将向大家展示如何使用树莓派制作简单的避障机器人。
众所周知,树莓派可以通过GPIO 接口、USB接口、以太网接口、HDMI接口、LCD和摄像头接口与诸多的外设进行通信。这个项目中我们使用的是Raspberry Pi 3B,3B有一个64位的ARMv7四核处理器,内存为1GB,还内置了Wi-Fi和蓝牙。详情可阅读: 树莓派3的外围I/O数据接口
项目中采用HC-SR04超声波测距模块作为避障探头,HC-SR04超声波测距模块具有2cm-400cm非接触式测量范围,测距精度可达3mm。模块包含了超声波发射器、接收器和控制电路。HC-SR04的介绍以前做过一些,可查阅: HC-SR04超声波测距模块的测试和 树莓派3 超声波测距代码这两篇文章。
同时,项目中还用到了GP2Y0A21红外传感器,它通过发射和检测红外辐射来感知周围环境的某些特征。红外传感器能够测量物体发出的热量并探测运动。它的距离测量范围是10cm~80cm。关于红外线传感器模块,可查阅: 夏普GP2Y0A21红外测距传感器接口定义
避障机器人的动力驱动,我们采用了L298N电机驱动模块,L298N驱动模块可以控制直流电机正转和反转,一块L298N驱动模块可以同时控制两个直流电机。L298N电机驱动模块接收来自树莓派的控制信号,并将信号传送给电动机,以此来控制电机的运动。关于L298N的接口定义,可阅读: 电机驱动板L298N的接口定义
其次,项目中还会用到电压调节器IC LM7805 ,它的作用是保持输出电压在一个恒定值。78xx系列IC中的xx表示它可以提供的稳定输出电压。如7805 IC可提供+5伏的稳定电压。下图是LM7805稳压IC的针脚定义图
项目中,避障机器人采用两个200 rpm的12v直流减速电机作为动力源。
在电路图中,实线表示电源线Vcc,长虚线表示接地线GND,短虚线表示控制信号线。
import curses
import RPi.GPIO as GPIO
class MotorControler(object):
def __init__(self, parent=None):
self._data = {'name': 'MOTOR', 'delay': 0.01, 'LD': 3, 'LU': 5, 'RD': 7, 'RU': 8}
self.init_pin()
def init_pin(self):
self.GPIO_LD_PIN = self._data.get('LD', -1)
self.GPIO_LU_PIN = self._data.get('LU', -1)
self.GPIO_RD_PIN = self._data.get('RD', -1)
self.GPIO_RU_PIN = self._data.get('RU', -1)
if self.GPIO_LD_PIN == -1 or self.GPIO_LU_PIN == -1 or self.GPIO_RD_PIN == -1 or self.GPIO_RU_PIN == -1:
print('message', 'FATAL ERROR : INVALID PIN ENCOUNTER # ' + str(self.GPIO_LD_PIN) + ', ' + + str(
self.GPIO_LU_PIN) + ', ' + + str(self.GPIO_RD_PIN) + ', ' + + str(self.GPIO_RU_PIN))
# pin setup
# set GPIO numbering mode and define output pins
GPIO.setup(self.GPIO_LD_PIN, GPIO.OUT)
GPIO.setup(self.GPIO_LU_PIN, GPIO.OUT)
GPIO.setup(self.GPIO_RD_PIN, GPIO.OUT)
GPIO.setup(self.GPIO_RU_PIN, GPIO.OUT)
time.sleep(0.5) # warmup time
self.stop()
def stop(self):
GPIO.output(self.GPIO_LD_PIN, False)
GPIO.output(self.GPIO_LU_PIN, False)
GPIO.output(self.GPIO_RD_PIN, False)
GPIO.output(self.GPIO_RU_PIN, False)
def step_forward(self):
GPIO.output(self.GPIO_LD_PIN, False)
GPIO.output(self.GPIO_LU_PIN, True)
GPIO.output(self.GPIO_RD_PIN, False)
GPIO.output(self.GPIO_RU_PIN, True)
print('Move Forward')
def step_backward(self):
GPIO.output(self.GPIO_LD_PIN, True)
GPIO.output(self.GPIO_LU_PIN, False)
GPIO.output(self.GPIO_RD_PIN, True)
GPIO.output(self.GPIO_RU_PIN, False)
print('Move Backward')
def step_right(self):
GPIO.output(self.GPIO_LD_PIN, True)
GPIO.output(self.GPIO_LU_PIN, False)
GPIO.output(self.GPIO_RD_PIN, False)
GPIO.output(self.GPIO_RU_PIN, True)
print('Move Right')
def step_left(self):
GPIO.output(self.GPIO_LD_PIN, False)
GPIO.output(self.GPIO_LU_PIN, True)
GPIO.output(self.GPIO_RD_PIN, True)
GPIO.output(self.GPIO_RU_PIN, False)
print('Move Left')
def move_forward(self, count=15):
for i in range(count):
self.step_forward()
self.stop()
def move_backward(self, count=15):
for i in range(count):
self.step_backward()
self.stop()
def move_right(self, count=15):
for i in range(count):
self.step_right()
self.stop()
def move_left(self, count=15):
for i in range(count):
self.step_left()
self.stop()
#set GPIO numbering mode and define output pins
GPIO.setmode(GPIO.BOARD)
# Get the curses window, turn off echoing of keyboard to screen, turn on
# instant (no waiting) key response, and use special values for cursor keys
screen = curses.initscr()
curses.noecho()
curses.cbreak()
screen.keypad(True)
motor = MotorControler()
try:
while True:
char = screen.getch()
if char == ord('q'):
break
elif char == curses.KEY_UP:
motor.move_forward(count=15)
elif char == curses.KEY_DOWN:
motor.move_backward(count=15)
elif char == curses.KEY_RIGHT:
motor.move_right(count=15)
elif char == curses.KEY_LEFT:
motor.move_left(count=15)
elif char == 10:
motor.stop()
finally:
#Close down curses properly, inc turn echo back on!
curses.nocbreak(); screen.keypad(0); curses.echo()
curses.endwin()
GPIO.cleanup()
自动控制代码
import RPi.GPIO as GPIO import time import numpy as np
GPIO.setmode(GPIO.BOARD) GPIO.setwarnings(False)
class MotorControler(object):
def __init__(self, parent=None):
self._data = {'name': 'MOTOR', 'delay': 0.01, 'LD': 14 'LU': 15, 'RD': 18, 'RU': 23}
self.init_pin()
def init_pin(self):
self.GPIO_LD_PIN = self._data.get('LD', -1) self.GPIO_LU_PIN = self._data.get('LU', -1)
self.GPIO_RD_PIN = self._data.get('RD', -1) self.GPIO_RU_PIN = self._data.get('RU', -1)
if self.GPIO_LD_PIN == -1 or self.GPIO_LU_PIN == -1 or self.GPIO_RD_PIN == -1 or self.GPIO_RU_PIN == -1:
print('message', 'FATAL ERROR : INVALID PIN ENCOUNTER # ' + str(self.GPIO_LD_PIN) + ', ' + + str(
self.GPIO_LU_PIN) + ', ' + + str(self.GPIO_RD_PIN) + ', ' + + str(self.GPIO_RU_PIN))
# pin setup
# set GPIO numbering mode and define output pins
GPIO.setup(self.GPIO_LD_PIN, GPIO.OUT) GPIO.setup(self.GPIO_LU_PIN, GPIO.OUT) GPIO.setup(self.GPIO_RD_PIN, GPIO.OUT) GPIO.setup(self.GPIO_RU_PIN, GPIO.OUT) time.sleep(0.5) # warmup time self.stop()
def stop(self):
GPIO.output(self.GPIO_LD_PIN, False) GPIO.output(self.GPIO_LU_PIN, False)
GPIO.output(self.GPIO_RD_PIN, False) GPIO.output(self.GPIO_RU_PIN, False)
def step_forward(self):
GPIO.output(self.GPIO_LD_PIN, False) GPIO.output(self.GPIO_LU_PIN, True)
GPIO.output(self.GPIO_RD_PIN, False) GPIO.output(self.GPIO_RU_PIN, True) print('Move Forward')
def step_backward(self):
GPIO.output(self.GPIO_LD_PIN, True) GPIO.output(self.GPIO_LU_PIN, False)
GPIO.output(self.GPIO_RD_PIN, True) GPIO.output(self.GPIO_RU_PIN, False) print('Move Backward')
def step_right(self):
GPIO.output(self.GPIO_LD_PIN, True) GPIO.output(self.GPIO_LU_PIN, False)
GPIO.output(self.GPIO_RD_PIN, False) GPIO.output(self.GPIO_RU_PIN, True) print('Move Right')
def step_left(self):
GPIO.output(self.GPIO_LD_PIN, False) GPIO.output(self.GPIO_LU_PIN, True)
GPIO.output(self.GPIO_RD_PIN, True) GPIO.output(self.GPIO_RU_PIN, False) print('Move Left')
def move_forward(self, count=15):
for i in range(count):
self.step_forward() self.stop()
def move_backward(self, count=15):
for i in range(count):
self.step_backward() self.stop()
def move_right(self, count=15):
for i in range(count):
self.step_right() self.stop()
def move_left(self, count=15): for i in range(count):
self.step_left() self.stop()
def readings():
IR_SENSOR_A = 2 IR_SENSOR_B = 3 IR_SENSOR_C = 6 IR_SENSOR_D = 4
GPIO.setup(IR_SENSOR_A, GPIO.IN) GPIO.setup(IR_SENSOR_B, GPIO.IN) GPIO.setup(IR_SENSOR_C, GPIO.IN) GPIO.setup(IR_SENSOR_D, GPIO.IN)
time.sleep(0.5) # warmup time
ir_measure_a = GPIO.input(IR_SENSOR_A) ir_measure_b = GPIO.input(IR_SENSOR_B) ir_measure_c = GPIO.input(IR_SENSOR_C) ir_measure_d = GPIO.input(IR_SENSOR_D)
print(ir_measure_a, ir_measure_b, ir_measure_c, ir_measure_d)
return [ir_measure_a, ir_measure_b, ir_measure_c, ir_measure_d]
# FOR DEMO def run():
motor = MotorControler()
while True:
sensor = readings()
if sensor[1] == 0 and sensor[2] == 0:
motor.move_forward(count=15) elif sensor[1] == 1 and sensor[2] == 1:
if np.random.ranf() > 0.5 :
motor.move_left(count=15) else:
motor.move_left(count=15) # provide more condotion for better maneuvering
run()
现在大家可以尽情去尝试避障机器人的控制和修改了。由于网页编码问题,如果代码运行出行报错,尝试按Python规范修改代码缩进。