# 第七章　智能机器人系统

## 7.1 引言：智能机器人系统概览

想象一个能够用步态和动作表达性格的双足机器人角色。2024年，迪士尼研究院公开了相关原型及其设计与控制方法，为研究“机械设计、运动控制与角色动画如何协同”提供了一个案例。

### 开篇案例：迪士尼研究院的双足机器人

该项目重点展示了双足机构、强化学习控制、动画动作和操作员交互界面的结合。它说明机器人角色的效果来自机械、控制与内容设计的协同，并不意味着原型已经具备通用的自然语言理解或完全自主服务能力。这个案例也引出了本章的核心主题：机器人如何把感知数据转化为受约束、可验证的行动。

资料来源：[Disney Research, “Design and Control of a Bipedal Robotic Character”](https://la.disneyresearch.com/publication/design-and-control-of-a-bipedal-robotic-character/)。

### 智能机器人系统的核心组件

智能机器人系统，无论是迪士尼的双足机器人还是我们日常生活中的扫地机器人，都由以下核心组件构成：

1. 感知系统：机器人的"眼睛"和"耳朵"
   * 传感器（如摄像头、麦克风、距离传感器等）
   * 数据处理和特征提取
2. 决策系统：机器人的"大脑"
   * 环境理解和建模
   * 任务规划
   * 行为决策
3. 控制系统：机器人的"肌肉"
   * 运动规划
   * 执行器控制（如电机控制）
4. 学习系统：机器人的"经验积累"
   * 数据收集和分析
   * 模型更新和优化
   * 适应性调整

这些组件紧密协作，使机器人能够感知环境、做出决策、执行动作，并从经验中学习和改进。

### 本章项目目标：验证从感知到决策的基本链路

在本章中，我们将通过硬件单项测试和网格仿真，理解智能机器人从感知、规划到决策的基本链路。课程不把尚未标定和验收的模块直接组合成“功能完整”的自主机器人。

我们的目标是验证系统是否能够：

* 感知周围环境
* 规划简单路径
* 在仿真中规划路径并处理障碍
* 用测试验证安全优先的基本决策

的小型移动机器人。

### 学习目标

通过学习本章内容，你将能够：

#### 知识目标

* 理解智能机器人系统的基本架构和工作原理
* 掌握机器人感知、决策、控制和学习的基本概念
* 了解机器人编程的基础知识
* 认识机器人技术在现实世界中的应用和影响

#### 技能目标

* 能够搭建一个基础的机器人硬件平台
* 学会使用基本的传感器采集环境数据
* 编写简单的程序控制机器人运动
* 在网格仿真中实现并验证基本导航算法
* 设计和实现简单的机器人行为决策系统

无论你是对机器人充满好奇的初学者，还是希望深入了解智能系统的学生，本章都将为你提供一次激动人心的学习之旅。让我们一起踏上这个从数据到行动的智能机器人探索之路吧！

在下一节中，我们将开始我们的第一个实践项目：搭建机器人的硬件平台。准备好你的工具和热情，我们即将动手创造属于自己的智能机器人！

## 7.2 搭建机器人硬件平台

欢迎来到我们动手实践的第一步！在这一节中，我们将一起搭建一个简单但功能强大的机器人硬件平台。别担心，即使你从未接触过电路或编程，只要跟着我们的指导，你也能成功组装出自己的小机器人。

### 机器人硬件基础知识

在开始动手之前，让我们先了解一下构成机器人的基本硬件组件：

1. **控制器**：机器人的"大脑"，我们将使用Raspberry Pi 4B。
2. **机器人底盘**：机器人的"身体"，提供结构支撑和移动能力。
3. **电机和轮子**：让机器人能够移动。
4. **电机驱动板**：控制电机的转速和方向。
5. **电池**：为整个系统提供电力。
6. **传感器**：机器人的"感官"，我们将在后续章节添加。

### 实践项目：组装基础机器人平台

#### 硬件清单和采购建议

以下是我们需要的核心组件：

1. Raspberry Pi 4B（4GB RAM）
2. 两轮差速驱动机器人底盘套件
3. L298N 电机驱动模块
4. 与电机额定电压匹配的电池组，以及稳定的5V降压模块（为Raspberry Pi供电）
5. 杜邦线若干
6. 螺丝刀套装

采购建议：

* 可以在电子商城如淘宝、亚马逊等购买这些组件。
* 选择有好评的卖家，确保配件质量。
* 部分组件可能有套装销售，可以节省成本。

#### 详细组装步骤指南

1. **准备底盘**
   * 按照底盘套件说明书组装底盘框架。
   * 确保两个驱动轮安装牢固，能够自由转动。
2. **安装电机**
   * 将两个直流电机固定到底盘指定位置。
   * 检查电机轴与轮子是否对齐。
3. **安装Raspberry Pi**
   * 在底盘上找一个合适的位置安装Raspberry Pi。
   * 使用螺丝或双面胶固定，确保稳固。
4. **连接电机驱动板**
   * 将L298N电机驱动模块安装在Raspberry Pi旁边。
   * 确保有足够的空间连接线缆。
5. **安装电池**
   * 将电池安装在底盘的合适位置，保持重心平衡。
   * 确保电池的输出端口易于接触。

#### 基础电路连接

现在，让我们将各个部分连接起来：

1. **电机连接**
   * 将左右电机分别连接到L298N的输出端A和B。
2. **L298N与Raspberry Pi连接**
   * 将L298N的IN1、IN2、IN3、IN4引脚分别连接到Raspberry Pi的GPIO引脚（例如GPIO 17, 18, 22, 23）。
   * 将L298N的GND连接到Raspberry Pi的GND。
3. **电源连接**
   * 按电机和驱动板的额定电压连接电池，不能仅因驱动板端子标有“12V”就使用12V电池。
   * 通过额定电流足够的5V降压模块为Raspberry Pi供电；电机电源与控制器必须共地。
   * 电池输出端应串联保险丝和总电源开关；调试运动程序时应准备可立即触发的急停方式。
4. **检查连接**
   * 仔细检查所有连接，确保没有短路或接错。

#### 安全注意事项

1. 在连接电路时，始终断开电源。
2. 注意电池的正负极，接反可能会损坏组件。
3. 避免金属物品接触电路板，防止短路。
4. 如果闻到异味或看到冒烟，立即断开电源并检查。
5. 保持工作区域干净整洁，避免小零件丢失。

### 测试你的机器人平台

完成组装后，让我们进行一个简单的测试：

1. 给系统通电。
2. 观察Raspberry Pi的指示灯，确认其正常启动。
3. 如果一切正常，恭喜你！你已经成功搭建了机器人的基础平台。

在下一节中，我们将学习如何为这个平台添加基本的传感器，使我们的机器人能够"感知"周围的世界。

记住，Rome wasn't built in a day（罗马不是一天建成的）。如果在组装过程中遇到困难，不要灰心。仔细检查每一步，如果需要，可以寻求同学或老师的帮助。每一个成功的工程师都是从这样的小项目开始的！

## 7.3 机器人的感知系统

想象一下，如果你突然失去了所有的感官，你将如何与世界互动？这正是没有传感器的机器人所面临的困境。在这一节中，我们将为我们的机器人添加"感官"，使它能够感知周围的世界。

### 传感器类型和原理介绍

传感器是机器人的"感官"，它们将物理世界的信息转换为电信号，供机器人的"大脑"（处理器）分析。以下是我们将使用的几种基本传感器：

1. **摄像头**：机器人的"眼睛"
   * 原理：捕捉光线并将其转换为数字图像
   * 应用：物体识别、颜色检测、动作追踪
2. **超声波传感器**：机器人的"回声定位"能力
   * 原理：发射高频声波并测量回波时间来计算距离
   * 应用：障碍物检测、距离测量
3. **IMU (惯性测量单元)**：机器人的"平衡感"
   * 原理：测量加速度和角速度
   * 应用：姿态估计、运动检测

### 实践项目：安装和测试基本传感器

#### 硬件清单

1. Raspberry Pi Camera Module V2
2. HC-SR04 超声波传感器
3. MPU-6050 IMU模块
4. 面包板和杜邦线

#### 硬件连接指南

1. **安装摄像头**
   * 将摄像头模块连接到Raspberry Pi的摄像头接口
   * 注意：小心操作柔性排线，避免损坏
2. **连接超声波传感器**
   * 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
3. **连接IMU模块**
   * VCC连接到3.3V
   * GND连接到GND
   * SDA连接到GPIO2
   * SCL连接到GPIO3

#### 软件环境配置

1.  更新Raspberry Pi系统：

    ```
    sudo apt update
    sudo apt upgrade
    ```
2.  安装必要的库：

    ```
    sudo apt install python3-picamera2
    sudo apt install python3-pip
    pip3 install RPi.GPIO
    pip3 install mpu6050-raspberrypi
    ```
3.  启用I2C接口（用于IMU）：

    ```
    sudo raspi-config
    ```

    在Interface Options中启用I2C

#### 传感器数据读取和可视化

让我们编写一个简单的Python程序来读取和显示传感器数据：

```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()
```

运行这个程序，你将看到来自各个传感器的数据流。恭喜你，你的机器人现在已经能"看"、"听"和"感觉"了！

### 挑战与思考

1. 尝试调整超声波传感器的位置，看看它如何影响距离测量。
2. 用IMU数据检测机器人是否在移动或倾斜。
3. 利用摄像头拍摄的图像，想想我们如何让机器人识别特定物体？

在下一节中，我们将学习如何利用这些感知数据来控制机器人的运动。记住，优秀的工程师不仅要会使用工具，还要理解工具的工作原理。继续探索，继续提问！

### 多传感器数据的边界

不同传感器只有在描述同一状态量、单位和坐标系已经统一，并且时间戳对齐后，才能进行有意义的融合。HC-SR04测得的是传感器到前方反射面的距离，IMU测得的是机体加速度和角速度，二者不能直接加权平均为“位移”。本章只分别记录这些数据，并把严格的标定、姿态估计和卡尔曼滤波作为拓展内容。

思考：如果要估计机器人的位姿，还需要哪些信息（例如轮编码器、传感器外参和时间戳）？

## 7.4 基础运动控制

现在我们的机器人已经能够采集感知数据了。本节学习在受控条件下完成前进、后退和转向测试。首次运行时应架空驱动轮，并由一人随时断开总电源。

### 电机控制原理

在开始编程之前，让我们先了解一下电机控制的基本原理：

1. **直流电机**：我们的机器人使用的是直流电机，通过改变施加在电机上的电压，我们可以控制电机的转速和方向。
2. **H桥**：这是控制直流电机的关键电路。想象一个字母"H"，电机连接在横杠上，通过控制四个开关（实际上是晶体管），我们可以改变电流方向，从而改变电机旋转方向。
3. **PWM（脉冲宽度调制）**：通过快速开关电源（每秒数千次），我们可以控制施加到电机的平均电压，从而控制速度。占空比越高，电机转速越快。

### 实践项目：实现简单的遥控功能

#### 步骤1：基本电机控制

首先，让我们编写一个基本的Python脚本来控制电机：

```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()`后单独运行此片段。

```python
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()
```

### 安全注意事项

1. 始终确保电机连接正确，错误的连接可能导致短路。
2. 在进行任何硬件更改时，请断开电源。
3. 在测试时，将机器人放在一个安全的位置，防止它意外跑出。
4. 如果电机或电路变得异常热，立即关闭电源并检查。

### 挑战与思考

1. 尝试实现速度控制：如何让机器人缓慢加速或减速？
2. 思考如何实现更平滑的转弯。
3. 挑战：能否让机器人按照预设的路径移动，例如画一个正方形？
4. 考虑如何结合上一节学到的传感器数据来实现简单的避障功能。

### 扩展阅读

* PID控制：一种更精确的速度和位置控制方法
* 运动学模型：理解和计算机器人的运动轨迹
* 电机编码器：如何更精确地测量和控制电机转速

在下一节中，我们将学习如何使用摄像头进行视觉识别，这将为我们的机器人添加更高级的感知能力。记住，优秀的工程师总是不断尝试和学习。继续探索，继续创新！

## 7.5 视觉识别与处理

想象一下，如果你的机器人能够"看到"并理解它所看到的东西，会有多么神奇！在这一节中，我们将探索计算机视觉的世界，让我们的机器人能够识别物体、检测颜色，甚至读取简单的标志。

### 计算机视觉基础概念

在我们开始编程之前，让我们先了解一些基本概念：

1. **图像表示**：计算机中的图像是由像素组成的二维数组。每个像素包含颜色信息，通常是RGB（红、绿、蓝）值。
2. **图像处理**：这包括对图像进行各种操作，如调整亮度、对比度，应用滤镜等。
3. **特征提取**：从图像中提取有用的信息，如边缘、角点、颜色分布等。
4. **物体检测**：在图像中定位并识别特定的物体。
5. **机器学习在视觉中的应用**：使用训练好的模型来识别复杂的物体或场景。

### 实践项目：实现基本的物体检测

我们将使用OpenCV库来实现一个简单的颜色检测和物体跟踪系统。

#### 步骤1：环境设置

首先，我们需要安装OpenCV库：

```bash
pip install opencv-python numpy
```

#### 步骤2：基本的颜色检测

让我们编写一个程序来检测特定颜色的物体：

```python
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：物体跟踪

现在，让我们扩展程序来跟踪检测到的物体：

```python
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()
```

这个程序能在当前图像中定位满足颜色阈值的最大连通区域。它并不具备通用的“物体理解”能力，光照变化和相似颜色都会影响结果。

### 挑战与思考

1. 尝试检测不同的颜色。你需要如何修改代码？
2. 如何让程序同时检测多种颜色？
3. 思考：我们如何利用物体的位置信息来控制机器人的运动？
4. 挑战：能否实现一个简单的"跟随物体"功能，让机器人跟随特定颜色的物体移动？

### 扩展阅读

* 图像分割：如何将图像分割成多个有意义的区域
* 特征匹配：如何在图像中查找特定的模式或物体
* 深度学习在计算机视觉中的应用：如卷积神经网络（CNN）

下一节将把视觉实验与路径规划仿真区分开来：先离线验证感知结果，再讨论它进入真实控制回路所需的安全条件。

### 拓展：从视觉模型到机器人动作

若使用预训练检测器或交通标志分类器，教材必须同时给出模型来源、许可证、文件校验值、类别表和与训练一致的预处理流程。仅把整幅摄像头画面缩放后分类，不能可靠地定位交通标志；超声波测得的“最近反射面”也不一定是视觉框中的目标。因此，本章不把这两类结果直接接入电机控制。可将保存的视频作为离线输入，比较颜色阈值、检测置信度和误报率；任何真实运动实验都要另行完成标定、失效保护和独立急停验收。
## 7.6 导航与路径规划

想象一下，如果你的机器人能够自主地在复杂环境中穿行，避开障碍物，并找到最佳路径到达目标位置，那将是多么令人兴奋！在这一节中，我们将探索导航与路径规划的基础知识，并实现一个简单但功能强大的自主导航系统。

### 路径规划算法简介

在开始编程之前，让我们先了解一些基本的路径规划概念和算法：

1. **图搜索算法**：将环境表示为一个图，然后使用搜索算法找到最佳路径。
   * 深度优先搜索（DFS）
   * 广度优先搜索（BFS）
   * A\*算法（结合了最佳优先搜索和启发式搜索）
2. **基于采样的算法**：在连续空间中随机采样点，构建路径。
   * 快速随机探索树（RRT）
   * 概率路线图（PRM）
3. **势场法**：将目标点视为吸引力源，障碍物视为斥力源。

在本节中，我们将重点关注A\*算法，因为它在效率和最优性之间取得了很好的平衡。

### 实践项目：实现简单的自主导航

我们将创建一个简化的 2D 网格世界，在其中实现 A\* 路径规划和基本的避障功能。

#### 步骤1：创建环境表示

首先，我们需要创建一个表示我们环境的类：

```python
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\*算法：

```python
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：在网格仿真中验证路径

下面的代码只在终端中显示规划结果，不控制真实机器人：

```python
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\*、用断言检查路径，再观察文本地图。把网格路径变成真实底盘动作还需要朝向、轮编码器或定位系统以及闭环控制，不能用固定时长的电机动作代替位姿更新。
### 挑战与思考

1. 如何改进当前的导航系统以处理动态障碍物？
2. 思考：A\*算法在大规模环境中的性能如何？有什么可能的优化方法？
3. 挑战：能否实现一个简单的SLAM（同时定位与地图构建）系统，让机器人在未知环境中导航？
4. 考虑如何将不确定性纳入到路径规划中，以处理传感器噪声和环境变化。

### 扩展阅读

* 动态路径规划：如何在环境变化时实时调整路径
* 概率路线图（PRM）：一种用于高维空间路径规划的采样方法
* 强化学习在路径规划中的应用：如何让机器人通过试错学习最优导航策略

本节完成了一个可复现的网格路径规划实验。它验证的是规划算法，不代表实体机器人已经获得定位、避障或自主运动能力。

记住，真正的挑战往往在于如何处理现实世界的不确定性和复杂性。继续探索和实验，你可能会发现解决这些挑战的创新方法！
### 从规划仿真到实体系统

本节的A\*示例假设地图、起点和终点都已知，且每次移动成本相同。动态障碍、实时建图与视觉语义导航属于拓展任务。它们需要定位误差模型、重规划频率、碰撞检测、看门狗和急停测试；本章不提供可直接驱动实体机器人的伪实现。
## 7.7 决策与行为控制

决策层把任务目标和感知状态转化为行为。常见方法包括有限状态机和行为树。行为树由条件、动作、顺序节点和选择节点组成；节点每次“滴答”返回成功（SUCCESS）、失败（FAILURE）或运行中（RUNNING）。

### 纯仿真实验：用决策规则选择行为

下面的示例不导入GPIO，也不会驱动电机。它用字典模拟机器人状态，便于先验证“安全优先”的决策顺序：

```python
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，并在条件失效时立即由更高优先级的安全分支抢占；程序退出时必须显式停止电机并释放资源。上述代码只验证决策逻辑，不是实体机器人控制程序。

### 挑战与思考

1. 为传感器超时、通信中断和定位失效分别添加测试。
2. 如果“电量低”和“前方有障碍”同时发生，为什么应该先停车？
3. 画出等价的行为树，并标注每个节点可能返回的状态。
## 7.8 学习与适应

强化学习通过环境反馈学习策略。本节只在离散网格中演示Q-learning，不把训练中的随机探索用于真实电机控制。

### 纯仿真实验：固定迷宫中的Q-learning

```python
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需要经验回放、目标网络、稳定性评估和安全约束。真实机器人上的在线随机探索可能造成碰撞或设备损坏，因此本章删除不完整的实体部署伪代码。若继续拓展，应先在独立仿真器中训练和回归测试，再以冻结策略、低速沙箱和人工急停方式验证；不能把“仿真中得分提高”等同于真实系统安全。

### 挑战与思考

1. 将Q-learning路径与A\*路径长度比较，并解释两者所需先验信息的差异。
2. 改变奖励后，记录成功率和平均步数，而不是只展示一次轨迹。
3. 构造一个无解地图，验证最大步数能否让训练和评估正常结束。
## 7.9 项目整合与展示

### 必做项目：可复现的网格导航实验

学生提交一个不连接实体电机的导航程序，完成以下闭环：

1. 使用固定网格、起点、终点和障碍物；
2. 运行A\*并用断言验证路径合法性；
3. 运行安全优先的决策规则测试；
4. 任选Q-learning作为对照，报告成功率、平均步数和随机种子；
5. 提交环境版本、运行命令、预期输出和失败案例。

评价以正确性与可复现性（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. 公平性和偏见

* **问题**：机器人系统可能继承或放大人类社会中的偏见。
* **讨论点**：
  * 训练数据的代表性和多样性
  * 算法公平性的评估和保障
  * 少数群体权益的保护

### 案例研究：自动驾驶汽车的伦理困境

自动驾驶技术是智能机器人系统在现实世界中的一个重要应用，它集中体现了许多技术和伦理挑战。

**场景**：一辆自动驾驶汽车面临不可避免的碰撞，它必须在撞向一群行人或牺牲车内乘客之间做出选择。

**讨论问题**：

1. 汽车应该如何"决定"？是否应该有预设的伦理准则？
2. 这种决策应该由谁来制定—— 政府、汽车制造商、还是消费者？
3. 如果自动驾驶汽车总体上比人类驾驶更安全，但偶尔会做出有争议的决定，社会应该如何看待？
4. 这种情况下的责任归属问题应该如何解决？

### 小组讨论：智能机器人对未来社会的影响

为了深入思考这些问题，我们将进行一个小组讨论活动。

**活动安排**：

1. 将班级分成 4-5 人的小组。
2. 每组选择一个主题（如就业影响、隐私问题、人机关系等）。
3. 小组内部讨论 20 分钟，准备一个简短的陈述。
4. 每组派代表进行 5 分钟的陈述。
5. 全班开放讨论 15 分钟。

**评估标准**：

* 对问题的深入理解
* 论证的逻辑性和创新性
* 多角度思考的能力
* 表达和沟通的清晰度

### 结语

智能机器人技术正在以前所未有的速度发展，它带来了巨大的机遇，同时也伴随着重大的挑战和伦理问题。作为未来的工程师和科学家，你们不仅需要掌握先进的技术，还要培养对社会责任的认识和伦理思考的能力。

技术并非脱离价值而独立存在：需求定义、数据选择、性能指标和部署制度都会影响不同群体。希望通过本章的学习，你们不仅掌握构建智能机器人系统的基础知识，也能识别设计选择中的责任与权衡。

