本章目录
第七章 智能机器人系统
7.1 引言:智能机器人系统概览
想象一个能够用步态和动作表达性格的双足机器人角色。2024年,迪士尼研究院公开了相关原型及其设计与控制方法,为研究“机械设计、运动控制与角色动画如何协同”提供了一个案例。
开篇案例:迪士尼研究院的双足机器人
该项目重点展示了双足机构、强化学习控制、动画动作和操作员交互界面的结合。它说明机器人角色的效果来自机械、控制与内容设计的协同,并不意味着原型已经具备通用的自然语言理解或完全自主服务能力。这个案例也引出了本章的核心主题:机器人如何把感知数据转化为受约束、可验证的行动。
资料来源:Disney Research, “Design and Control of a Bipedal Robotic Character”。
智能机器人系统的核心组件
智能机器人系统,无论是迪士尼的双足机器人还是我们日常生活中的扫地机器人,都由以下核心组件构成:
- 感知系统:机器人的"眼睛"和"耳朵" * 传感器(如摄像头、麦克风、距离传感器等) * 数据处理和特征提取
- 决策系统:机器人的"大脑" * 环境理解和建模 * 任务规划 * 行为决策
- 控制系统:机器人的"肌肉" * 运动规划 * 执行器控制(如电机控制)
- 学习系统:机器人的"经验积累" * 数据收集和分析 * 模型更新和优化 * 适应性调整
这些组件紧密协作,使机器人能够感知环境、做出决策、执行动作,并从经验中学习和改进。
本章项目目标:验证从感知到决策的基本链路
在本章中,我们将通过硬件单项测试和网格仿真,理解智能机器人从感知、规划到决策的基本链路。课程不把尚未标定和验收的模块直接组合成“功能完整”的自主机器人。
我们的目标是验证系统是否能够:
- 感知周围环境
- 规划简单路径
- 在仿真中规划路径并处理障碍
- 用测试验证安全优先的基本决策
的小型移动机器人。
学习目标
通过学习本章内容,你将能够:
知识目标
- 理解智能机器人系统的基本架构和工作原理
- 掌握机器人感知、决策、控制和学习的基本概念
- 了解机器人编程的基础知识
- 认识机器人技术在现实世界中的应用和影响
技能目标
- 能够搭建一个基础的机器人硬件平台
- 学会使用基本的传感器采集环境数据
- 编写简单的程序控制机器人运动
- 在网格仿真中实现并验证基本导航算法
- 设计和实现简单的机器人行为决策系统
无论你是对机器人充满好奇的初学者,还是希望深入了解智能系统的学生,本章都将为你提供一次激动人心的学习之旅。让我们一起踏上这个从数据到行动的智能机器人探索之路吧!
在下一节中,我们将开始我们的第一个实践项目:搭建机器人的硬件平台。准备好你的工具和热情,我们即将动手创造属于自己的智能机器人!
7.2 搭建机器人硬件平台
欢迎来到我们动手实践的第一步!在这一节中,我们将一起搭建一个简单但功能强大的机器人硬件平台。别担心,即使你从未接触过电路或编程,只要跟着我们的指导,你也能成功组装出自己的小机器人。
机器人硬件基础知识
在开始动手之前,让我们先了解一下构成机器人的基本硬件组件:
- 控制器:机器人的"大脑",我们将使用Raspberry Pi 4B。
- 机器人底盘:机器人的"身体",提供结构支撑和移动能力。
- 电机和轮子:让机器人能够移动。
- 电机驱动板:控制电机的转速和方向。
- 电池:为整个系统提供电力。
- 传感器:机器人的"感官",我们将在后续章节添加。
实践项目:组装基础机器人平台
硬件清单和采购建议
以下是我们需要的核心组件:
- Raspberry Pi 4B(4GB RAM)
- 两轮差速驱动机器人底盘套件
- L298N 电机驱动模块
- 与电机额定电压匹配的电池组,以及稳定的5V降压模块(为Raspberry Pi供电)
- 杜邦线若干
- 螺丝刀套装
采购建议:
- 可以在电子商城如淘宝、亚马逊等购买这些组件。
- 选择有好评的卖家,确保配件质量。
- 部分组件可能有套装销售,可以节省成本。
详细组装步骤指南
- 准备底盘 * 按照底盘套件说明书组装底盘框架。 * 确保两个驱动轮安装牢固,能够自由转动。
- 安装电机 * 将两个直流电机固定到底盘指定位置。 * 检查电机轴与轮子是否对齐。
- 安装Raspberry Pi * 在底盘上找一个合适的位置安装Raspberry Pi。 * 使用螺丝或双面胶固定,确保稳固。
- 连接电机驱动板 * 将L298N电机驱动模块安装在Raspberry Pi旁边。 * 确保有足够的空间连接线缆。
- 安装电池 * 将电池安装在底盘的合适位置,保持重心平衡。 * 确保电池的输出端口易于接触。
基础电路连接
现在,让我们将各个部分连接起来:
- 电机连接 * 将左右电机分别连接到L298N的输出端A和B。
- L298N与Raspberry Pi连接 * 将L298N的IN1、IN2、IN3、IN4引脚分别连接到Raspberry Pi的GPIO引脚(例如GPIO 17, 18, 22, 23)。 * 将L298N的GND连接到Raspberry Pi的GND。
- 电源连接 * 按电机和驱动板的额定电压连接电池,不能仅因驱动板端子标有“12V”就使用12V电池。 * 通过额定电流足够的5V降压模块为Raspberry Pi供电;电机电源与控制器必须共地。 * 电池输出端应串联保险丝和总电源开关;调试运动程序时应准备可立即触发的急停方式。
- 检查连接 * 仔细检查所有连接,确保没有短路或接错。
安全注意事项
- 在连接电路时,始终断开电源。
- 注意电池的正负极,接反可能会损坏组件。
- 避免金属物品接触电路板,防止短路。
- 如果闻到异味或看到冒烟,立即断开电源并检查。
- 保持工作区域干净整洁,避免小零件丢失。
测试你的机器人平台
完成组装后,让我们进行一个简单的测试:
- 给系统通电。
- 观察Raspberry Pi的指示灯,确认其正常启动。
- 如果一切正常,恭喜你!你已经成功搭建了机器人的基础平台。
在下一节中,我们将学习如何为这个平台添加基本的传感器,使我们的机器人能够"感知"周围的世界。
记住,Rome wasn't built in a day(罗马不是一天建成的)。如果在组装过程中遇到困难,不要灰心。仔细检查每一步,如果需要,可以寻求同学或老师的帮助。每一个成功的工程师都是从这样的小项目开始的!
7.3 机器人的感知系统
想象一下,如果你突然失去了所有的感官,你将如何与世界互动?这正是没有传感器的机器人所面临的困境。在这一节中,我们将为我们的机器人添加"感官",使它能够感知周围的世界。
传感器类型和原理介绍
传感器是机器人的"感官",它们将物理世界的信息转换为电信号,供机器人的"大脑"(处理器)分析。以下是我们将使用的几种基本传感器:
- 摄像头:机器人的"眼睛" * 原理:捕捉光线并将其转换为数字图像 * 应用:物体识别、颜色检测、动作追踪
- 超声波传感器:机器人的"回声定位"能力 * 原理:发射高频声波并测量回波时间来计算距离 * 应用:障碍物检测、距离测量
- IMU (惯性测量单元):机器人的"平衡感" * 原理:测量加速度和角速度 * 应用:姿态估计、运动检测
实践项目:安装和测试基本传感器
硬件清单
- Raspberry Pi Camera Module V2
- HC-SR04 超声波传感器
- MPU-6050 IMU模块
- 面包板和杜邦线
硬件连接指南
- 安装摄像头 * 将摄像头模块连接到Raspberry Pi的摄像头接口 * 注意:小心操作柔性排线,避免损坏
- 连接超声波传感器 * VCC连接到Raspberry Pi的5V * GND连接到Raspberry Pi的GND * TRIG连接到GPIO25(本章统一使用BCM编号,避免与右电机GPIO23冲突) * ECHO输出为5V,不可直接连接Raspberry Pi的3.3V GPIO。使用电阻分压(例如ECHO—1 kΩ—GPIO24—2 kΩ—GND)或双向电平转换模块后再接GPIO24
- 连接IMU模块 * VCC连接到3.3V * GND连接到GND * SDA连接到GPIO2 * SCL连接到GPIO3
软件环境配置
-
更新Raspberry Pi系统:
sudo apt update sudo apt upgrade2. 安装必要的库:sudo apt install python3-picamera2 sudo apt install python3-pip pip3 install RPi.GPIO pip3 install mpu6050-raspberrypi3. 启用I2C接口(用于IMU):sudo raspi-config在Interface Options中启用I2C
传感器数据读取和可视化
让我们编写一个简单的Python程序来读取和显示传感器数据:
import RPi.GPIO as GPIO
import time
from picamera2 import Picamera2
from mpu6050 import mpu6050
# 设置GPIO模式
GPIO.setmode(GPIO.BCM)
# 超声波传感器设置
TRIG = 25
ECHO = 24
GPIO.setup(TRIG, GPIO.OUT)
GPIO.setup(ECHO, GPIO.IN)
# 初始化摄像头
camera = Picamera2()
camera.configure(camera.create_still_configuration())
camera.start()
# 初始化IMU
imu = mpu6050(0x68)
def get_distance(timeout=0.03):
"""返回厘米数;未在超时时间内收到回波时返回None。"""
GPIO.output(TRIG, False)
time.sleep(0.000002)
GPIO.output(TRIG, True)
time.sleep(0.00001)
GPIO.output(TRIG, False)
deadline = time.monotonic() + timeout
while GPIO.input(ECHO) == 0:
if time.monotonic() >= deadline:
return None
start_time = time.monotonic()
deadline = time.monotonic() + timeout
while GPIO.input(ECHO) == 1:
if time.monotonic() >= deadline:
return None
stop_time = time.monotonic()
time_elapsed = stop_time - start_time
distance = (time_elapsed * 34300) / 2
return distance
try:
while True:
# 读取超声波传感器数据
dist = get_distance()
if dist is None:
print("Distance: timeout")
else:
print(f"Distance: {dist:.2f} cm")
# 读取IMU数据
accel_data = imu.get_accel_data()
gyro_data = imu.get_gyro_data()
print(f"Accelerometer data: {accel_data}")
print(f"Gyroscope data: {gyro_data}")
# 捕获图像
camera.capture_file('image.jpg')
print("Image captured")
time.sleep(1)
except KeyboardInterrupt:
print("Measurement stopped by user")
finally:
GPIO.cleanup()
camera.stop()
运行这个程序,你将看到来自各个传感器的数据流。恭喜你,你的机器人现在已经能"看"、"听"和"感觉"了!
挑战与思考
- 尝试调整超声波传感器的位置,看看它如何影响距离测量。
- 用IMU数据检测机器人是否在移动或倾斜。
- 利用摄像头拍摄的图像,想想我们如何让机器人识别特定物体?
在下一节中,我们将学习如何利用这些感知数据来控制机器人的运动。记住,优秀的工程师不仅要会使用工具,还要理解工具的工作原理。继续探索,继续提问!
多传感器数据的边界
不同传感器只有在描述同一状态量、单位和坐标系已经统一,并且时间戳对齐后,才能进行有意义的融合。HC-SR04测得的是传感器到前方反射面的距离,IMU测得的是机体加速度和角速度,二者不能直接加权平均为“位移”。本章只分别记录这些数据,并把严格的标定、姿态估计和卡尔曼滤波作为拓展内容。
思考:如果要估计机器人的位姿,还需要哪些信息(例如轮编码器、传感器外参和时间戳)?
7.4 基础运动控制
现在我们的机器人已经能够采集感知数据了。本节学习在受控条件下完成前进、后退和转向测试。首次运行时应架空驱动轮,并由一人随时断开总电源。
电机控制原理
在开始编程之前,让我们先了解一下电机控制的基本原理:
- 直流电机:我们的机器人使用的是直流电机,通过改变施加在电机上的电压,我们可以控制电机的转速和方向。
- H桥:这是控制直流电机的关键电路。想象一个字母"H",电机连接在横杠上,通过控制四个开关(实际上是晶体管),我们可以改变电流方向,从而改变电机旋转方向。
- PWM(脉冲宽度调制):通过快速开关电源(每秒数千次),我们可以控制施加到电机的平均电压,从而控制速度。占空比越高,电机转速越快。
实践项目:实现简单的遥控功能
步骤1:基本电机控制
首先,让我们编写一个基本的Python脚本来控制电机:
import RPi.GPIO as GPIO
import time
# 设置GPIO模式
GPIO.setmode(GPIO.BCM)
# 定义电机控制引脚
LEFT_FORWARD = 17
LEFT_BACKWARD = 18
RIGHT_FORWARD = 22
RIGHT_BACKWARD = 23
# 设置引脚为输出
GPIO.setup(LEFT_FORWARD, GPIO.OUT)
GPIO.setup(LEFT_BACKWARD, GPIO.OUT)
GPIO.setup(RIGHT_FORWARD, GPIO.OUT)
GPIO.setup(RIGHT_BACKWARD, GPIO.OUT)
# 创建PWM对象
LEFT_PWM_F = GPIO.PWM(LEFT_FORWARD, 100)
LEFT_PWM_B = GPIO.PWM(LEFT_BACKWARD, 100)
RIGHT_PWM_F = GPIO.PWM(RIGHT_FORWARD, 100)
RIGHT_PWM_B = GPIO.PWM(RIGHT_BACKWARD, 100)
# 启动PWM
LEFT_PWM_F.start(0)
LEFT_PWM_B.start(0)
RIGHT_PWM_F.start(0)
RIGHT_PWM_B.start(0)
def set_motor_speed(left_speed, right_speed):
left_speed = max(-100, min(100, left_speed))
right_speed = max(-100, min(100, right_speed))
if left_speed >= 0:
LEFT_PWM_F.ChangeDutyCycle(left_speed)
LEFT_PWM_B.ChangeDutyCycle(0)
else:
LEFT_PWM_F.ChangeDutyCycle(0)
LEFT_PWM_B.ChangeDutyCycle(-left_speed)
if right_speed >= 0:
RIGHT_PWM_F.ChangeDutyCycle(right_speed)
RIGHT_PWM_B.ChangeDutyCycle(0)
else:
RIGHT_PWM_F.ChangeDutyCycle(0)
RIGHT_PWM_B.ChangeDutyCycle(-right_speed)
# 测试电机控制
try:
print("前进")
set_motor_speed(30, 30)
time.sleep(0.5)
set_motor_speed(0, 0)
time.sleep(0.3)
print("后退")
set_motor_speed(-30, -30)
time.sleep(0.5)
set_motor_speed(0, 0)
time.sleep(0.3)
print("左转")
set_motor_speed(-25, 25)
time.sleep(0.4)
set_motor_speed(0, 0)
time.sleep(0.3)
print("右转")
set_motor_speed(25, -25)
time.sleep(0.4)
print("停止")
set_motor_speed(0, 0)
except KeyboardInterrupt:
print("程序被用户中断")
finally:
set_motor_speed(0, 0)
GPIO.cleanup()
步骤2:键盘控制
现在,让我们添加键盘控制。将下面的循环替换步骤1中的“测试电机控制”部分,并保留前面的GPIO和PWM初始化代码;不要在已经执行GPIO.cleanup()后单独运行此片段。
import curses
# 初始化curses
screen = curses.initscr()
curses.noecho()
curses.cbreak()
screen.keypad(True)
screen.timeout(200) # 200毫秒未收到按键就停车
try:
while True:
char = screen.getch()
if char == -1:
set_motor_speed(0, 0)
elif char == ord('q'):
break
elif char == curses.KEY_UP:
print("前进")
set_motor_speed(50, 50)
elif char == curses.KEY_DOWN:
print("后退")
set_motor_speed(-50, -50)
elif char == curses.KEY_LEFT:
print("左转")
set_motor_speed(-30, 30)
elif char == curses.KEY_RIGHT:
print("右转")
set_motor_speed(30, -30)
elif char == ord(' '):
print("停止")
set_motor_speed(0, 0)
finally:
set_motor_speed(0, 0)
# 恢复终端设置
curses.nocbreak()
screen.keypad(False)
curses.echo()
curses.endwin()
# 清理GPIO设置
GPIO.cleanup()
安全注意事项
- 始终确保电机连接正确,错误的连接可能导致短路。
- 在进行任何硬件更改时,请断开电源。
- 在测试时,将机器人放在一个安全的位置,防止它意外跑出。
- 如果电机或电路变得异常热,立即关闭电源并检查。
挑战与思考
- 尝试实现速度控制:如何让机器人缓慢加速或减速?
- 思考如何实现更平滑的转弯。
- 挑战:能否让机器人按照预设的路径移动,例如画一个正方形?
- 考虑如何结合上一节学到的传感器数据来实现简单的避障功能。
扩展阅读
- PID控制:一种更精确的速度和位置控制方法
- 运动学模型:理解和计算机器人的运动轨迹
- 电机编码器:如何更精确地测量和控制电机转速
在下一节中,我们将学习如何使用摄像头进行视觉识别,这将为我们的机器人添加更高级的感知能力。记住,优秀的工程师总是不断尝试和学习。继续探索,继续创新!
7.5 视觉识别与处理
想象一下,如果你的机器人能够"看到"并理解它所看到的东西,会有多么神奇!在这一节中,我们将探索计算机视觉的世界,让我们的机器人能够识别物体、检测颜色,甚至读取简单的标志。
计算机视觉基础概念
在我们开始编程之前,让我们先了解一些基本概念:
- 图像表示:计算机中的图像是由像素组成的二维数组。每个像素包含颜色信息,通常是RGB(红、绿、蓝)值。
- 图像处理:这包括对图像进行各种操作,如调整亮度、对比度,应用滤镜等。
- 特征提取:从图像中提取有用的信息,如边缘、角点、颜色分布等。
- 物体检测:在图像中定位并识别特定的物体。
- 机器学习在视觉中的应用:使用训练好的模型来识别复杂的物体或场景。
实践项目:实现基本的物体检测
我们将使用OpenCV库来实现一个简单的颜色检测和物体跟踪系统。
步骤1:环境设置
首先,我们需要安装OpenCV库:
pip install opencv-python numpy
步骤2:基本的颜色检测
让我们编写一个程序来检测特定颜色的物体:
import cv2
import numpy as np
# 初始化摄像头
cap = cv2.VideoCapture(0)
while True:
# 读取一帧图像
ret, frame = cap.read()
if not ret:
break
# 转换到HSV颜色空间
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# 定义蓝色的HSV范围
lower_blue = np.array([100, 50, 50])
upper_blue = np.array([130, 255, 255])
# 创建掩码
mask = cv2.inRange(hsv, lower_blue, upper_blue)
# 对原图像进行按位与操作
res = cv2.bitwise_and(frame, frame, mask=mask)
# 显示结果
cv2.imshow('Original', frame)
cv2.imshow('Mask', mask)
cv2.imshow('Result', res)
# 按'q'键退出
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放摄像头并关闭所有窗口
cap.release()
cv2.destroyAllWindows()
这个程序会检测蓝色物体。你可以通过调整lower_blue和upper_blue的值来检测其他颜色。
步骤3:物体跟踪
现在,让我们扩展程序来跟踪检测到的物体:
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if not ret:
break
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
lower_blue = np.array([100, 50, 50])
upper_blue = np.array([130, 255, 255])
mask = cv2.inRange(hsv, lower_blue, upper_blue)
# 对掩码进行形态学操作,去除噪点
kernel = np.ones((5, 5), np.uint8)
mask = cv2.erode(mask, kernel, iterations=2)
mask = cv2.dilate(mask, kernel, iterations=2)
# 寻找轮廓
contours, _ = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 如果找到了轮廓
if contours:
# 找到最大的轮廓
c = max(contours, key=cv2.contourArea)
# 计算轮廓的重心
M = cv2.moments(c)
if M["m00"] != 0:
cx = int(M["m10"] / M["m00"])
cy = int(M["m01"] / M["m00"])
# 在图像上画出重心
cv2.circle(frame, (cx, cy), 5, (0, 0, 255), -1)
# 打印物体的位置
print(f"Object at ({cx}, {cy})")
cv2.imshow('Frame', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
这个程序能在当前图像中定位满足颜色阈值的最大连通区域。它并不具备通用的“物体理解”能力,光照变化和相似颜色都会影响结果。
挑战与思考
- 尝试检测不同的颜色。你需要如何修改代码?
- 如何让程序同时检测多种颜色?
- 思考:我们如何利用物体的位置信息来控制机器人的运动?
- 挑战:能否实现一个简单的"跟随物体"功能,让机器人跟随特定颜色的物体移动?
扩展阅读
- 图像分割:如何将图像分割成多个有意义的区域
- 特征匹配:如何在图像中查找特定的模式或物体
- 深度学习在计算机视觉中的应用:如卷积神经网络(CNN)
下一节将把视觉实验与路径规划仿真区分开来:先离线验证感知结果,再讨论它进入真实控制回路所需的安全条件。
拓展:从视觉模型到机器人动作
若使用预训练检测器或交通标志分类器,教材必须同时给出模型来源、许可证、文件校验值、类别表和与训练一致的预处理流程。仅把整幅摄像头画面缩放后分类,不能可靠地定位交通标志;超声波测得的“最近反射面”也不一定是视觉框中的目标。因此,本章不把这两类结果直接接入电机控制。可将保存的视频作为离线输入,比较颜色阈值、检测置信度和误报率;任何真实运动实验都要另行完成标定、失效保护和独立急停验收。
7.6 导航与路径规划
想象一下,如果你的机器人能够自主地在复杂环境中穿行,避开障碍物,并找到最佳路径到达目标位置,那将是多么令人兴奋!在这一节中,我们将探索导航与路径规划的基础知识,并实现一个简单但功能强大的自主导航系统。
路径规划算法简介
在开始编程之前,让我们先了解一些基本的路径规划概念和算法:
- 图搜索算法:将环境表示为一个图,然后使用搜索算法找到最佳路径。 * 深度优先搜索(DFS) * 广度优先搜索(BFS) * A*算法(结合了最佳优先搜索和启发式搜索)
- 基于采样的算法:在连续空间中随机采样点,构建路径。 * 快速随机探索树(RRT) * 概率路线图(PRM)
- 势场法:将目标点视为吸引力源,障碍物视为斥力源。
在本节中,我们将重点关注A*算法,因为它在效率和最优性之间取得了很好的平衡。
实践项目:实现简单的自主导航
我们将创建一个简化的 2D 网格世界,在其中实现 A* 路径规划和基本的避障功能。
步骤1:创建环境表示
首先,我们需要创建一个表示我们环境的类:
class GridWorld:
def __init__(self, width, height):
self.width = width
self.height = height
self.obstacles = set()
def add_obstacle(self, x, y):
self.obstacles.add((x, y))
def is_valid_position(self, x, y):
return 0 <= x < self.width and 0 <= y < self.height and (x, y) not in self.obstacles
def get_neighbors(self, x, y):
neighbors = [(x+1, y), (x-1, y), (x, y+1), (x, y-1)]
return [(nx, ny) for nx, ny in neighbors if self.is_valid_position(nx, ny)]
步骤2:实现A*算法
现在,让我们实现A*算法:
import heapq
def heuristic(a, b):
return abs(b[0] - a[0]) + abs(b[1] - a[1])
def a_star(grid, start, goal):
if not grid.is_valid_position(*start) or not grid.is_valid_position(*goal):
return None
closed = set()
came_from = {}
g_score = {start: 0}
open_set = [(heuristic(start, goal), 0, start)]
while open_set:
_, current_g, current = heapq.heappop(open_set)
if current in closed:
continue
if current == goal:
path = []
while current in came_from:
path.append(current)
current = came_from[current]
path.append(start)
path.reverse()
return path
closed.add(current)
for neighbor in grid.get_neighbors(*current):
if neighbor in closed:
continue
tentative_g = current_g + 1
if tentative_g < g_score.get(neighbor, float("inf")):
came_from[neighbor] = current
g_score[neighbor] = tentative_g
f_score = tentative_g + heuristic(neighbor, goal)
heapq.heappush(open_set, (f_score, tentative_g, neighbor))
return None
步骤3:在网格仿真中验证路径
下面的代码只在终端中显示规划结果,不控制真实机器人:
def render_grid(grid, path, start, goal):
path_cells = set(path or [])
for y in range(grid.height):
row = []
for x in range(grid.width):
pos = (x, y)
if pos == start:
row.append("S")
elif pos == goal:
row.append("G")
elif pos in grid.obstacles:
row.append("#")
elif pos in path_cells:
row.append("*")
else:
row.append(".")
print(" ".join(row))
grid = GridWorld(10, 10)
for obstacle in [(2, 2), (3, 3), (4, 4)]:
grid.add_obstacle(*obstacle)
start, goal = (0, 0), (9, 9)
path = a_star(grid, start, goal)
assert path is not None
assert path[0] == start and path[-1] == goal
assert not (set(path) & grid.obstacles)
render_grid(grid, path, start, goal)
这条实验链可在普通Python环境中复现:构造网格、运行A*、用断言检查路径,再观察文本地图。把网格路径变成真实底盘动作还需要朝向、轮编码器或定位系统以及闭环控制,不能用固定时长的电机动作代替位姿更新。
挑战与思考
- 如何改进当前的导航系统以处理动态障碍物?
- 思考:A*算法在大规模环境中的性能如何?有什么可能的优化方法?
- 挑战:能否实现一个简单的SLAM(同时定位与地图构建)系统,让机器人在未知环境中导航?
- 考虑如何将不确定性纳入到路径规划中,以处理传感器噪声和环境变化。
扩展阅读
- 动态路径规划:如何在环境变化时实时调整路径
- 概率路线图(PRM):一种用于高维空间路径规划的采样方法
- 强化学习在路径规划中的应用:如何让机器人通过试错学习最优导航策略
本节完成了一个可复现的网格路径规划实验。它验证的是规划算法,不代表实体机器人已经获得定位、避障或自主运动能力。
记住,真正的挑战往往在于如何处理现实世界的不确定性和复杂性。继续探索和实验,你可能会发现解决这些挑战的创新方法!
从规划仿真到实体系统
本节的A*示例假设地图、起点和终点都已知,且每次移动成本相同。动态障碍、实时建图与视觉语义导航属于拓展任务。它们需要定位误差模型、重规划频率、碰撞检测、看门狗和急停测试;本章不提供可直接驱动实体机器人的伪实现。
7.7 决策与行为控制
决策层把任务目标和感知状态转化为行为。常见方法包括有限状态机和行为树。行为树由条件、动作、顺序节点和选择节点组成;节点每次“滴答”返回成功(SUCCESS)、失败(FAILURE)或运行中(RUNNING)。
纯仿真实验:用决策规则选择行为
下面的示例不导入GPIO,也不会驱动电机。它用字典模拟机器人状态,便于先验证“安全优先”的决策顺序:
from enum import Enum, auto
class Status(Enum):
SUCCESS = auto()
FAILURE = auto()
RUNNING = auto()
def choose_action(state):
if state["emergency_stop"]:
return "STOP"
if state["distance_cm"] is None or state["distance_cm"] < 30:
return "STOP"
if state["battery_percent"] < 20:
return "RETURN_TO_CHARGE"
if state["target_visible"]:
return "APPROACH_TARGET"
return "EXPLORE"
tests = [
({"emergency_stop": True, "distance_cm": 100, "battery_percent": 80, "target_visible": True}, "STOP"),
({"emergency_stop": False, "distance_cm": 20, "battery_percent": 80, "target_visible": False}, "STOP"),
({"emergency_stop": False, "distance_cm": 100, "battery_percent": 10, "target_visible": True}, "RETURN_TO_CHARGE"),
({"emergency_stop": False, "distance_cm": 100, "battery_percent": 80, "target_visible": True}, "APPROACH_TARGET"),
]
for state, expected in tests:
assert choose_action(state) == expected
print("all decision tests passed")
真实系统还必须规定每个动作的持续条件、超时、抢占和停止语义。例如,“前进”通常应返回RUNNING,并在条件失效时立即由更高优先级的安全分支抢占;程序退出时必须显式停止电机并释放资源。上述代码只验证决策逻辑,不是实体机器人控制程序。
挑战与思考
- 为传感器超时、通信中断和定位失效分别添加测试。
- 如果“电量低”和“前方有障碍”同时发生,为什么应该先停车?
- 画出等价的行为树,并标注每个节点可能返回的状态。
7.8 学习与适应
强化学习通过环境反馈学习策略。本节只在离散网格中演示Q-learning,不把训练中的随机探索用于真实电机控制。
纯仿真实验:固定迷宫中的Q-learning
import numpy as np
ACTIONS = [(0, -1), (0, 1), (-1, 0), (1, 0)] # 上、下、左、右
WIDTH = HEIGHT = 6
START, GOAL = (0, 0), (5, 5)
OBSTACLES = {(1, 0), (1, 1), (1, 2), (3, 3), (4, 3)}
def step(state, action):
dx, dy = ACTIONS[action]
candidate = (state[0] + dx, state[1] + dy)
valid = (
0 <= candidate[0] < WIDTH
and 0 <= candidate[1] < HEIGHT
and candidate not in OBSTACLES
)
if not valid:
return state, -5.0, False
if candidate == GOAL:
return candidate, 20.0, True
return candidate, -1.0, False
rng = np.random.default_rng(42)
q = np.zeros((WIDTH, HEIGHT, len(ACTIONS)))
alpha, gamma, epsilon = 0.1, 0.95, 1.0
for _ in range(3000):
state = START
for _ in range(200): # 防止无界循环
if rng.random() < epsilon:
action = int(rng.integers(len(ACTIONS)))
else:
action = int(np.argmax(q[state]))
next_state, reward, done = step(state, action)
target = reward if done else reward + gamma * np.max(q[next_state])
q[state][action] += alpha * (target - q[state][action])
state = next_state
if done:
break
epsilon = max(0.05, epsilon * 0.995)
# 评估时关闭探索,并限制步数
state, path = START, [START]
for _ in range(100):
action = int(np.argmax(q[state]))
state, _, done = step(state, action)
path.append(state)
if done:
break
assert path[-1] == GOAL, "策略未到达终点;请检查环境或训练参数"
print(path)
固定随机种子、固定地图、每回合最大步数和关闭探索的评估,使结果可以复查。障碍碰撞会得到惩罚并保持原位,目标奖励在到达时可达。
从仿真到真实机器人
持续学习和DQN需要经验回放、目标网络、稳定性评估和安全约束。真实机器人上的在线随机探索可能造成碰撞或设备损坏,因此本章删除不完整的实体部署伪代码。若继续拓展,应先在独立仿真器中训练和回归测试,再以冻结策略、低速沙箱和人工急停方式验证;不能把“仿真中得分提高”等同于真实系统安全。
挑战与思考
- 将Q-learning路径与A*路径长度比较,并解释两者所需先验信息的差异。
- 改变奖励后,记录成功率和平均步数,而不是只展示一次轨迹。
- 构造一个无解地图,验证最大步数能否让训练和评估正常结束。
7.9 项目整合与展示
必做项目:可复现的网格导航实验
学生提交一个不连接实体电机的导航程序,完成以下闭环:
- 使用固定网格、起点、终点和障碍物;
- 运行A*并用断言验证路径合法性;
- 运行安全优先的决策规则测试;
- 任选Q-learning作为对照,报告成功率、平均步数和随机种子;
- 提交环境版本、运行命令、预期输出和失败案例。
评价以正确性与可复现性(40%)、测试与异常处理(30%)、实验分析(20%)、表达与协作(10%)为准。
选做项目:低速实体避障
只有在教师审核接线和风险清单后才可进行。验收门槛包括:HC-SR04 ECHO电平转换、统一引脚表、保险丝/总开关、独立急停、测距超时即停车、程序异常退出即停车,以及架空轮测试通过。选做项目不要求视觉识别、SLAM、持续学习或DQN,避免把多个尚未验证的模块一次性接入执行器。
展示时应区分“已运行并测量的结果”“仿真结果”和“设计设想”,不得用含pass、未定义接口或随机数占位的框架冒充完成系统。
7.10 未来展望与伦理考虑
随着我们深入探索智能机器人系统的各个方面,我们不仅要思考技术本身,还要考虑这些技术将如何塑造我们的未来,以及我们作为技术开发者和使用者应该承担的责任。在本节中,我们将探讨智能机器人技术的前沿发展,并深入讨论相关的伦理和社会问题。
智能机器人的前沿发展
1. 人工通用智能(AGI)
目前的机器人系统大多是针对特定任务设计的。未来的发展方向之一是创造具有通用智能的机器人,能够像人类一样灵活地应对各种任务和环境。
- 挑战:实现真正的通用智能需要解决诸如常识推理、迁移学习、元学习等一系列复杂问题。
- 潜在影响:AGI 可能彻底改变劳动力市场,并对社会结构产生深远影响。
2. 群体机器人和分布式智能
未来的机器人系统可能不再是独立的个体,而是相互协作的群体。
- 技术趋势:分布式算法、群体智能、多智能体系统。
- 应用前景:大规模环境监测、灾难救援、微型医疗机器人。
3. 软体机器人和仿生技术
模仿生物结构和行为的机器人设计正在兴起。
- 创新点:柔性材料、仿生驱动、自修复能力。
- 潜在应用:医疗手术、深海探索、空间任务。
4. 脑机接口与人机融合
直接连接人脑和机器的技术正在快速发展。
- 研究方向:非侵入式脑信号采集、神经编码解析、意图识别。
- 伦理考量:人类增强、隐私保护、身份认同。
5. 自主性和道德决策
赋予机器人更高水平的自主性和道德决策能力。
- 技术挑战:形式化伦理规则、情境理解、价值对齐。
- 社会影响:责任归属、法律框架调整、人机互动范式的改变。
伦理与社会问题讨论
1. 就业和经济影响
- 问题:智能机器人可能取代大量人类工作,如何应对可能的大规模失业?
- 讨论点:
- 新技术创造的新就业机会
- 教育系统的调整和再培训计划
- 普遍基本收入等社会政策的可行性
2. 隐私和数据安全
- 问题:智能机器人系统收集和处理大量个人数据,如何保护隐私和防止滥用?
- 讨论点:
- 数据收集和使用的透明度
- 个人数据所有权和控制权
- 加密技术和去中心化数据存储
3. 安全性和责任归属
- 问题:当自主机器人系统造成伤害时,谁应该负责?
- 讨论点:
- 机器人行为的可预测性和可解释性
- 设计者、制造商、所有者和使用者的责任划分
- 机器人保险和赔偿机制
4. 人机关系和社会影响
- 问题:随着机器人变得更加智能和拟人化,人类社会将如何适应?
- 讨论点:
- 机器人的法律地位
- 人机交互的心理影响
- 社会规范和价值观的潜在变化
5. 军事应用和武器自主性
- 问题:自主武器系统的发展引发了严重的伦理担忧。
- 讨论点:
- 人类控制和有意义的人类参与的必要性
- 国际管控和军备竞赛
- 战争法则的适用性和调整
6. 公平性和偏见
- 问题:机器人系统可能继承或放大人类社会中的偏见。
- 讨论点:
- 训练数据的代表性和多样性
- 算法公平性的评估和保障
- 少数群体权益的保护
案例研究:自动驾驶汽车的伦理困境
自动驾驶技术是智能机器人系统在现实世界中的一个重要应用,它集中体现了许多技术和伦理挑战。
场景:一辆自动驾驶汽车面临不可避免的碰撞,它必须在撞向一群行人或牺牲车内乘客之间做出选择。
讨论问题:
- 汽车应该如何"决定"?是否应该有预设的伦理准则?
- 这种决策应该由谁来制定—— 政府、汽车制造商、还是消费者?
- 如果自动驾驶汽车总体上比人类驾驶更安全,但偶尔会做出有争议的决定,社会应该如何看待?
- 这种情况下的责任归属问题应该如何解决?
小组讨论:智能机器人对未来社会的影响
为了深入思考这些问题,我们将进行一个小组讨论活动。
活动安排:
- 将班级分成 4-5 人的小组。
- 每组选择一个主题(如就业影响、隐私问题、人机关系等)。
- 小组内部讨论 20 分钟,准备一个简短的陈述。
- 每组派代表进行 5 分钟的陈述。
- 全班开放讨论 15 分钟。
评估标准:
- 对问题的深入理解
- 论证的逻辑性和创新性
- 多角度思考的能力
- 表达和沟通的清晰度
结语
智能机器人技术正在以前所未有的速度发展,它带来了巨大的机遇,同时也伴随着重大的挑战和伦理问题。作为未来的工程师和科学家,你们不仅需要掌握先进的技术,还要培养对社会责任的认识和伦理思考的能力。
技术并非脱离价值而独立存在:需求定义、数据选择、性能指标和部署制度都会影响不同群体。希望通过本章的学习,你们不仅掌握构建智能机器人系统的基础知识,也能识别设计选择中的责任与权衡。