24、基于行为的机器人技术:Alfie 机器人汽车实现

基于行为的机器人技术:Alfie 机器人汽车实现

1. 基于行为的机器人控制原理

在基于行为的机器人技术中, Controller 类起着核心作用。它需要一个由 Behavior 对象组成的列表或数组,这些对象共同构成了机器人的整体行为。 Controller 实例会从 Behavior 数组的最高索引开始,检查每个行为对象的 takeControl() 方法的返回值。如果返回 true ,则调用该行为的 action() 方法;如果返回 false ,则继续检查下一个行为对象的 takeControl() 方法返回值。行为的优先级通过数组索引来分配, Controller 类会不断重新扫描所有行为对象。当高优先级行为的 takeControl() 方法返回 true 时,会抑制低优先级行为的 action() 方法。以下是该过程的 mermaid 流程图:

graph TD;
    A[开始] --> B[从最高索引检查行为];
    B --> C{takeControl()返回true?};
    C -- 是 --> D[调用action()方法];
    C -- 否 --> E[检查下一个行为];
    E --> C;
    D --> F[继续扫描行为];
    F --> G{高优先级行为takeControl()为true?};
    G -- 是 --> H[抑制低优先级行为];
    G -- 否 --> F;
    H --> F;

2. Alfie 机器人汽车示例

2.1 基本行为定义

  • 正常行为( NormalBehavior :这是低优先级行为,机器人正常情况下会向前行驶。以下是其代码实现:
class NormalBehavior(Behavior):
    def takeControl():
        return true
    def action():
        # drive forward
        pwmL.ChangeDutyCycle(3.6)
        pwmR.ChangeDutyCycle(2.2)
    def suppress():
        # all stop
        pwmL.ChangeDutyCycle(2.6)
        pwmR.ChangeDutyCycle(2.6)

takeControl() 方法始终返回 true ,表示该行为一直请求控制,但高优先级行为会优先获得控制权。 action() 方法通过设置电机的占空比来驱动电机向前转动, suppress() 方法则停止两个电机。

  • 避障行为( AvoidObstacle :这是高优先级行为,当机器人检测到前方有障碍物时会触发。代码如下:
class AvoidObstacle(Behavior):
    global distance1, distance2
    def takeControl():
        if distance1 <= 25.4 or distance2 <= 25.4:
            return True
        else:
            return False
    def action():
        # drive backward
        pwmL.ChangeDutyCycle(2.2)
        pwmR.ChangeDutyCycle(3.6)
        time.sleep(1.5)
        # turn right
        pwmL.ChangeDutyCycle(3.6)
        pwmR.ChangeDutyCycle(2.6)
        time.sleep(0.3)
        # stop
        pwmL.ChangeDutyCycle(2.6)
        pwmR.ChangeDutyCycle(2.6)
    def suppress():
        # all stop
        pwmL.ChangeDutyCycle(2.6)
        pwmR.ChangeDutyCycle(2.6)

takeControl() 方法只有在超声波传感器与障碍物的距离小于等于 10 英寸(25.4 厘米)时才返回 true action() 方法会让机器人先向后退 1.5 秒,然后右转 0.3 秒,最后停止等待下一个行为激活。 suppress() 方法同样是停止两个电机。

2.2 测试类实现

为了测试上述行为,创建了 testBBR 类,它会实例化所有之前定义的类和 Controller 对象。以下是代码:

import RPi.GPIO as GPIO
import time
import threading
import numpy as np
# next two libraries must be installed IAW appendix 
instructions
import Adafruit_GPIO.SPI as SPI
import Adafruit_MCP3008

class Behavior():
    global pwmL, pwmR, distance1, distance2
    # use the BCM pin numbers
    GPIO.setmode(GPIO.BCM)
    # setup the motor control pins
    GPIO.setup(18, GPIO.OUT)
    GPIO.setup(19, GPIO.OUT)
    pwmL = GPIO.PWM(18,20) # pin 18 is left wheel pwm
    pwmR = GPIO.PWM(19,20) # pin 19 is right wheel pwm
    # must 'start' the motors with 0 rotation speeds
    pwmL.start(2.8)
    pwmR.start(2.8)

class Controller():
    def __init__(self):
        self.behaviors = []
        self.wait_object = threading.Event()
        self.active_behavior_index = None
        self.running = True
        #self.return_when_no_action = return_when_no_action
        #self.callback = lambda x: 0
    def add(self, behavior):
        self.behaviors.append(behavior)
    def remove(self, index):
        old_behavior = self.behaviors[index]
        del self.behaviors[index]
        if self.active_behavior_index == index:  # stop the old 
one if the new one overrides it
            old_behavior.suppress()
            self.active_behavior_index = None
    def update(self, behavior, index):
        old_behavior = self.behaviors[index]
        self.behaviors[index] = behavior
        if self.active_behavior_index == index:  # stop the old 
one if the new one overrides it
            old_behavior.suppress()
    def step(self):
        behavior = self.find_next_active_behavior()
        if behavior is not None:
            self.behaviors[behavior].action()
            return True
        return False
    def find_next_active_behavior(self):
        for priority, behavior in enumerate(self.behaviors):
            active = behavior.takeControl()
            if active == True:
                activeIndex = priority
        return activeIndex
    def find_and_set_new_active_behavior(self):
        new_behavior_priority = self.find_next_active_behavior()
        if self.active_behavior_index is None or self.active_
behavior_index > new_behavior_priority:
            if self.active_behavior_index is not None:
                self.behaviors[self.active_behavior_index].suppress()
            self.active_behavior_index = new_behavior_priority
    def start(self):  # run the action methods
        self.running = True
        self.find_and_set_new_active_behavior()  # force it once
        thread = threading.Thread(name="Continuous behavior checker",
                                  target=self.continuously_
find_new_active_behavior, 
args=())
        thread.daemon = True
        thread.start()
        while self.running:
            if self.active_behavior_index is not None:
                running_behavior = self.active_behavior_index
                self.behaviors[running_behavior].action()
                if running_behavior == self.active_behavior_index:
                    self.active_behavior_index = None
                    self.find_and_set_new_active_behavior()
            self.running = False
    def stop(self):
        self._running = False
        self.behaviors[self.active_behavior_index].suppress()
    def continuously_find_new_active_behavior(self):
        while self.running:
            self.find_and_set_new_active_behavior()
    def __str__(self):
        return str(self.behaviors)

class NormalBehavior(Behavior):
    def takeControl(self):
        return True
    def action(self):
        # drive forward
        pwmL.ChangeDutyCycle(3.6)
        pwmR.ChangeDutyCycle(2.2)
    def suppress(self):
        # all stop
        pwmL.ChangeDutyCycle(2.6)
        pwmR.ChangeDutyCycle(2.6)

class AvoidObstacle(Behavior):
    def takeControl(self):
        #self.distance1 = distance1
        #self.distance2 = distance2
        if self.distance1 <= 25.4 or self.distance2 <= 25.4:
            return True
        else:
            return False
    def action(self):
        # drive backward
        pwmL.ChangeDutyCycle(2.2)
        pwmR.ChangeDutyCycle(3.6)
        time.sleep(1.5)
        # turn right
        pwmL.ChangeDutyCycle(3.6)
        pwmR.ChangeDutyCycle(2.6)
        time.sleep(0.3)
        # stop
        pwmL.ChangeDutyCycle(2.6)
        pwmR.ChangeDutyCycle(2.6)
    def suppress(self):
        # all stop
        pwmL.ChangeDutyCycle(2.6)
        pwmR.ChangeDutyCycle(2.6)
    def setDistances(self, dest1, dest2):
        self.distance1 = dest1
        self.distance2 = dest2

class testBBR():
    def __init__(self):
        # instantiate objects
        self.nb = NormalBehavior()
        self.oa = AvoidObstacle()
        self.control = Controller()
        # setup the behaviors array by priority; last-in = highest
        self.control.add(self.nb)
        self.control.add(self.oa)
        # initialize distances
        distance1 = 50
        distance2 = 50
        self.oa.setDistances(distance1, distance2)
        # activate the behaviors
        self.control.start()
        threshold = 25.4 #10 inches
        # use the BCM pin numbers
        GPIO.setmode(GPIO.BCM)
        # ultrasonic sensor pins
        self.TRIG1 = 23 # an output
        self.ECHO1 = 24 # an input
        self.TRIG2 = 25 # an output
        self.ECHO2 = 27 # an input
        # set the output pins
        GPIO.setup(self.TRIG1, GPIO.OUT)
        GPIO.setup(self.TRIG2, GPIO.OUT)
        # set the input pins
        GPIO.setup(self.ECHO1, GPIO.IN)
        GPIO.setup(self.ECHO2, GPIO.IN)
        # initialize sensors
        GPIO.output(self.TRIG1, GPIO.LOW)
        GPIO.output(self.TRIG2, GPIO.LOW)
        time.sleep(1)
        # Hardware SPI configuration:
        SPI_PORT   =  0
        SPI_DEVICE = 0
        self.mcp = Adafruit_MCP3008.MCP3008(spi=SPI.SpiDev(SPI_
PORT, SPI_DEVICE))

    def run(self):
        # forever loop
        while True:
            # sensor 1 reading
            GPIO.output(self.TRIG1, GPIO.HIGH)
            time.sleep(0.000010)
            GPIO.output(self.TRIG1, GPIO.LOW)
            # detects the time duration for the echo pulse
            while GPIO.input(self.ECHO1) == 0:
                pulse_start = time.time()
            while GPIO.input(self.ECHO1) == 1:
                pulse_end = time.time()
            pulse_duration = pulse_end - pulse_start
            # distance calculation
            distance1 = pulse_duration * 17150
            # round distance to two decimal points
            distance1 = round(distance1, 2)
            time.sleep(0.1) # ensure that sensor 1 is quiet
            # sensor 2 reading
            GPIO.output(self.TRIG2, GPIO.HIGH)
            time.sleep(0.000010)
            GPIO.output(self.TRIG2, GPIO.LOW)
            # detects the time duration for the echo pulse
            while GPIO.input(self.ECHO2) == 0:
                pulse_start = time.time()
            while GPIO.input(self.ECHO2) == 1:
                pulse_end = time.time()
            pulse_duration = pulse_end - pulse_start
            # distance calculation
            distance2 = pulse_duration * 17150
            # round distance to two decimal points
            distance2 = round(distance2, 2)
            time.sleep(0.1) # ensure that sensor 2 is quiet
            self.oa.setDistances(distance1, distance2)

            count0 = self.mcp.read_adc(0)
            # approximation given 1023 = 7.5V
            voltage = count0 / 100
            self.control.find_and_set_new_active_behavior()

# instantiate an instance of testBBR
bbr = testBBR()
# run it
bbr.run()

2.3 测试运行

通过 SSH 会话运行机器人,使用以下命令启动脚本:

python subsumption.py

机器人会立即向前直线行驶,直到遇到障碍物(如纸板箱)。当距离障碍物约 10 英寸时,机器人会快速暂停,右转,然后继续直线行驶。

3. 增加新行为

可以很容易地添加新的行为,例如基于电池电压水平的停止行为。创建了 StopRobot 类,代码如下:

class StopRobot(Behavior):
    critical_voltage = 6.0 # change to any value suitable for robot
    def takeControl(self):
        if self.voltage < critical_voltage:
            return True
        else:
            return False
    def action(self):
        # all stop
        pwmL.ChangeDutyCycle(2.6)
        pwmR.ChangeDutyCycle(2.6)
    def suppress(self):
        # all stop
        pwmL.ChangeDutyCycle(2.6)
        pwmR.ChangeDutyCycle(2.6)
    def setVoltage(self, volts):
        self.voltage = volts

同时,需要对 testBBR 类进行修改,添加以下两行代码:

self.sr = StopRobot()  # Add this to the bottom of the list of instantiated 
Behavior subclasses.
self.sr.setVoltage(voltage)  # Add this right after the voltage 
measurement.

这样,当电池电压低于临界值时,机器人会停止运行。

4. Alfie 机器人汽车的构建

4.1 机械构建

  • 底盘组装 :Alfie 机器人汽车由 Parallax 公司的套件构建而成,名为 Boe - Bot。可以从 Parallax 网站下载组装说明来快速搭建基本的机器人汽车平台。
  • 动力供应 :机器人汽车由两个连续旋转(CR)伺服电机驱动,需要比为树莓派供电的电池消除器更高的电压和电流。Parallax 提供了一个 Li - ion 电池电源,型号为 28989,它内置充电系统,两个 18650 尺寸的 Li - ion 电池串联可提供 7.4 VDC 的电压,能为伺服电机提供充足的动力。
  • CR 伺服电机 PWM 控制 :CR 伺服电机需要通过适当的 PWM 信号驱动,PWM 脉冲持续时间范围为 1.0 到 2.0 毫秒。不同的 ChangeDutyCycle(arg) 值对应不同的电机转速:
    | arg 值 | 电机状态 |
    | ---- | ---- |
    | 2.6 | 无旋转 |
    | 3.6 | 逆时针全速 |
    | 2.2 | 顺时针全速 |

  • 安装板 :机器人汽车有两个安装板,一个用于安装电池消除器电源,另一个用于安装树莓派和无焊面包板。安装板通过尼龙垫片和螺丝进行安装,无焊面包板使用双面胶带固定,方便拆卸。

4.2 电气和布线

电气连接相对简单,主要包括推进驱动电路和超声波传感器的互连。两个 CR 伺服电机由 Li - ion 电池电源供电,树莓派由单独的电池消除器模块供电。以下是电气连接的主要参数:
| 部件 | 电源 | 运行时间 |
| ---- | ---- | ---- |
| CR 伺服电机 | 7.4 VDC,2600 mAh Li - ion 电池 | 超过 6 小时 |
| 树莓派 | 2100 mAh 电池消除器 | 超过 15 小时 |

综上所述,基于行为的机器人技术通过将不同的行为组合在一起,使机器人能够根据环境条件做出相应的反应。通过 Alfie 机器人汽车的示例,我们展示了如何实现基本的行为控制、避障行为以及添加新的行为。同时,详细介绍了机器人汽车的构建过程,包括机械组装和电气布线。这种方法为开发更复杂的机器人行为提供了基础,可以根据实际需求不断调整和优化机器人的行为。

5. 基于行为的机器人技术总结

基于行为的机器人技术核心在于模拟动物和昆虫的行为模式,特别是它们对环境中感官刺激的反应方式。这种技术借鉴了人类大脑的多层行为功能,采用了包容架构,将不同优先级的行为组合在一起,使机器人能够根据环境条件动态调整自身行为。

5.1 行为优先级与控制机制

在基于行为的机器人系统中,行为的优先级起着关键作用。 Controller 类通过不断扫描 Behavior 对象数组,根据 takeControl() 方法的返回值来确定当前激活的行为。高优先级的行为可以抑制低优先级的行为,从而确保机器人在不同情况下做出最合适的反应。例如,在 Alfie 机器人汽车中,避障行为的优先级高于正常行驶行为,当检测到障碍物时,避障行为会立即接管控制权,使机器人避免碰撞。

5.2 行为的实现与扩展

每个 Behavior 对象都需要实现 takeControl() action() suppress() 三个方法。 takeControl() 方法用于判断该行为是否应该被激活, action() 方法定义了行为的具体操作, suppress() 方法用于在行为被抑制时停止相关操作。通过这种方式,可以方便地实现各种不同的行为,并根据需要进行扩展。例如,添加基于电池电压的停止行为,只需要创建一个新的 Behavior 子类,并在 testBBR 类中进行相应的配置。

5.3 机器人的构建与配置

机器人的硬件构建也是基于行为的机器人技术的重要组成部分。以 Alfie 机器人汽车为例,需要选择合适的底盘、动力源和传感器,并进行正确的组装和布线。同时,还需要根据硬件的特性进行相应的软件配置,例如设置 PWM 信号来控制伺服电机的转速。以下是一个简单的流程图,展示了基于行为的机器人系统的整体架构:

graph LR;
    A[环境感知] --> B[行为判断];
    B --> C{选择行为};
    C -- 高优先级行为 --> D[执行行为];
    C -- 低优先级行为 --> E{是否被抑制};
    E -- 是 --> F[等待];
    E -- 否 --> D;
    D --> G[更新状态];
    G --> A;

6. 技术应用与未来展望

6.1 实际应用场景

基于行为的机器人技术在许多领域都有广泛的应用前景。在工业领域,可以用于自动化生产线中的物料搬运和设备维护,机器人可以根据环境中的障碍物和任务需求自动调整行为,提高生产效率和安全性。在服务领域,如家庭清洁机器人、物流配送机器人等,能够根据环境变化自主规划路径,完成相应的任务。在教育领域,基于行为的机器人可以作为教学工具,帮助学生理解机器人的工作原理和编程思想。

6.2 未来发展方向

随着人工智能和传感器技术的不断发展,基于行为的机器人技术也将不断完善和拓展。未来的机器人可能会具备更复杂的行为模式和更高的智能水平,能够更好地适应各种复杂的环境。例如,结合深度学习算法,机器人可以从大量的数据中学习到更准确的行为决策规则,提高行为的灵活性和适应性。同时,机器人之间的协作也将成为一个重要的研究方向,多个机器人可以通过相互协作完成更复杂的任务。

6.3 总结与建议

基于行为的机器人技术为机器人的开发和应用提供了一种有效的方法。通过将不同的行为组合在一起,并根据环境条件动态调整行为,机器人能够更加智能地完成各种任务。在实际应用中,需要根据具体的需求选择合适的行为模式和硬件配置,并不断进行优化和改进。对于想要深入研究基于行为的机器人技术的读者,可以进一步学习相关的理论知识和实践经验,尝试开发自己的机器人系统。

总之,基于行为的机器人技术是一个充满潜力和挑战的领域,它将为未来的机器人发展带来更多的可能性。通过不断的探索和创新,我们有望开发出更加智能、灵活和高效的机器人,为人类的生活和工作带来更多的便利。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值