如何使用树莓派制作避障机器人

  • 内容
  • ....
  • 相关

学习Arduino或者树莓派的过程中,如果仅仅看代码或者做简单实验,那么常常会虎头蛇尾,所以我们建议还是尝试一些简单的机器人项目,这样既有趣也能不断学习提高。本文将向大家展示如何使用树莓派制作简单的避障机器人。

避障机器人

树莓派避障机器人各功能组件

众所周知,树莓派可以通过GPIO 接口、USB接口、以太网接口、HDMI接口、LCD和摄像头接口与诸多的外设进行通信。这个项目中我们使用的是Raspberry Pi 3B,3B有一个64位的ARMv7四核处理器,内存为1GB,还内置了Wi-Fi和蓝牙。详情可阅读: 树莓派3的外围I/O数据接口

树莓派3B主板

项目中采用HC-SR04超声波测距模块作为避障探头,HC-SR04超声波测距模块具有2cm-400cm非接触式测量范围,测距精度可达3mm。模块包含了超声波发射器、接收器和控制电路。HC-SR04的介绍以前做过一些,可查阅: HC-SR04超声波测距模块的测试树莓派3 超声波测距代码这两篇文章。

hc-sr04超声波测距模块

同时,项目中还用到了GP2Y0A21红外传感器,它通过发射和检测红外辐射来感知周围环境的某些特征。红外传感器能够测量物体发出的热量并探测运动。它的距离测量范围是10cm~80cm。关于红外线传感器模块,可查阅: 夏普GP2Y0A21红外测距传感器接口定义

Sharp IR Sensor - GP2Y0A21YK0F。Sharp GP2Y0A21 红外测距传感器(10~80cm)

避障机器人的动力驱动,我们采用了L298N电机驱动模块,L298N驱动模块可以控制直流电机正转和反转,一块L298N驱动模块可以同时控制两个直流电机。L298N电机驱动模块接收来自树莓派的控制信号,并将信号传送给电动机,以此来控制电机的运动。关于L298N的接口定义,可阅读: 电机驱动板L298N的接口定义

L298N针脚定义

其次,项目中还会用到电压调节器IC LM7805 ,它的作用是保持输出电压在一个恒定值。78xx系列IC中的xx表示它可以提供的稳定输出电压。如7805 IC可提供+5伏的稳定电压。下图是LM7805稳压IC的针脚定义图

LM7805的引脚定义

项目中,避障机器人采用两个200 rpm的12v直流减速电机作为动力源。

避障机器人的电路图

树莓派避障机器人电路原理图

在电路图中,实线表示电源线Vcc,长虚线表示接地线GND,短虚线表示控制信号线。

避障机器人的Python代码

手动控制代码

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规范修改代码缩进。