教程 13:E-puck 机器人学习 - 从简到难 (90分钟)


目标与简介

本教程将带你系统地学习 E-puck 机器人的编程,采用循序渐进的方法,从最基础的概念开始,逐步深入到复杂的应用。E-puck 是一个教育型移动机器人,非常适合学习机器人学的基础知识。你将学习如何控制机器人的运动、读取传感器数据、实现避障、路径规划等技能。本教程基于官方 E-puck 文档

目录

1. E-puck 机器人简介

E-puck 是一个教育型移动机器人,由瑞士洛桑联邦理工学院(EPFL)开发。它是一个直径约7厘米的圆形机器人,配备了两个轮子进行差动转向,以及8个红外距离传感器用于环境感知。E-puck 非常适合学习机器人学的基础概念。

E-puck 硬件特点

  • 尺寸:直径 70mm,高度 50mm
  • 驱动:两个步进电机,差动转向
  • 传感器:8个红外距离传感器,1个摄像头
  • 通信:蓝牙、红外、WiFi(可选)
  • 处理器:dsPIC30F6014A 微控制器

2. 基础运动控制

让我们从最基础的运动控制开始。E-puck 使用差动转向,这意味着通过控制左右两个轮子的速度来实现转向。我们先创建一个简单的直线运动控制器:

📝 动手实践 #1: 创建基础运动控制器:
from controller import Robot

# 创建机器人实例
robot = Robot()

# 获取时间步长
time_step = int(robot.getBasicTimeStep())

# 获取左右电机
left_motor = robot.getDevice("left_wheel_motor")
right_motor = robot.getDevice("right_wheel_motor")

# 设置电机为速度控制模式
left_motor.setPosition(float('inf'))
right_motor.setPosition(float('inf'))

# 设置基础速度(弧度/秒)
base_speed = 2.0

# 主控制循环
while robot.step(time_step) != -1:
    # 设置左右轮速度相等,实现直线运动
    left_motor.setVelocity(base_speed)
    right_motor.setVelocity(base_speed)

这段代码让 E-puck 以恒定速度直线前进。通过设置左右轮速度相等,机器人会沿直线移动。

代码解析

  • getDevice("left_wheel_motor") - 获取左轮电机设备
  • setPosition(float('inf')) - 设置为速度控制模式
  • setVelocity(speed) - 设置轮子速度(弧度/秒)
  • robot.step(time_step) - 执行仿真步骤,更新物理状态
  • 差动转向:左右轮速度相等时直线运动,不同时转向

3. 传感器基础

E-puck 配备了8个红外距离传感器,分布在机器人周围。这些传感器可以检测障碍物距离,是实现避障和导航的基础。让我们学习如何读取和使用这些传感器:

📝 动手实践 #2: 读取距离传感器:
from controller import Robot, DistanceSensor

# 创建机器人实例
robot = Robot()
time_step = int(robot.getBasicTimeStep())

# 获取所有距离传感器
sensors = []
for i in range(8):
    sensor = robot.getDevice(f"ps{i}")
    sensor.enable(time_step)
    sensors.append(sensor)

# 主控制循环
while robot.step(time_step) != -1:
    # 读取所有传感器值
    sensor_values = []
    for i, sensor in enumerate(sensors):
        value = sensor.getValue()
        sensor_values.append(value)
        print(f"传感器 {i}: {value:.2f}")
    
    # 计算平均距离
    avg_distance = sum(sensor_values) / len(sensor_values)
    print(f"平均距离: {avg_distance:.2f}")

E-puck 传感器布局

  • ps0-ps7:8个红外距离传感器,按顺时针编号
  • ps0:正前方,检测前方障碍物
  • ps1-ps2:右前方,检测右前方障碍物
  • ps3:右侧,检测右侧障碍物
  • ps4:右后方,检测右后方障碍物
  • ps5-ps6:左后方,检测左后方障碍物
  • ps7:左侧,检测左侧障碍物

4. 简单行为编程

现在让我们学习如何将传感器和执行器结合起来,实现一些简单的机器人行为。这是机器人编程的核心概念:感知-思考-行动循环。

📝 动手实践 #4: 基础避障行为:
from controller import Robot, DistanceSensor

# 创建机器人实例
robot = Robot()
time_step = int(robot.getBasicTimeStep())

# 获取左右电机
left_motor = robot.getDevice("left_wheel_motor")
right_motor = robot.getDevice("right_wheel_motor")

# 设置电机为速度控制模式
left_motor.setPosition(float('inf'))
right_motor.setPosition(float('inf'))

# 获取前方距离传感器
front_sensor = robot.getDevice("ps0")
front_sensor.enable(time_step)

# 基础速度设置
base_speed = 2.0
turn_speed = 1.5

# 主控制循环
while robot.step(time_step) != -1:
    # 读取前方传感器
    front_distance = front_sensor.getValue()
    
    # 简单的避障逻辑
    if front_distance > 100:  # 前方无障碍物
        # 直行
        left_motor.setVelocity(base_speed)
        right_motor.setVelocity(base_speed)
    else:  # 前方有障碍物
        # 左转避障
        left_motor.setVelocity(-turn_speed)
        right_motor.setVelocity(turn_speed)

行为编程要点

  • 感知-思考-行动:读取传感器 → 处理数据 → 控制执行器
  • 阈值设置:根据传感器特性设置合适的触发阈值
  • 状态机:机器人可以在不同行为状态间切换
  • 响应速度:控制循环频率影响机器人响应灵敏度
  • 调试技巧:使用print语句输出传感器值和执行器状态

5. 避障算法

避障是移动机器人的基本技能。E-puck机器人有8个距离传感器,可以检测周围360度的障碍物。让我们学习几种不同的避障策略。

📝 动手实践 #5: 多传感器避障算法:
from controller import Robot

# 创建机器人实例
robot = Robot()
time_step = int(robot.getBasicTimeStep())

# 获取左右电机
left_motor = robot.getDevice("left_wheel_motor")
right_motor = robot.getDevice("right_wheel_motor")
left_motor.setPosition(float('inf'))
right_motor.setPosition(float('inf'))

# 获取所有距离传感器
sensors = []
for i in range(8):
    sensor = robot.getDevice(f"ps{i}")
    sensor.enable(time_step)
    sensors.append(sensor)

# 速度设置
base_speed = 2.0
turn_speed = 1.5

def get_sensor_values():
    """读取所有传感器值"""
    return [sensor.getValue() for sensor in sensors]

def obstacle_avoidance(sensor_values):
    """基于传感器值的避障策略"""
    # 前方传感器 (ps0, ps1, ps7)
    front_left = sensor_values[7]   # ps7
    front = sensor_values[0]        # ps0  
    front_right = sensor_values[1]  # ps1
    
    # 侧方传感器
    left = sensor_values[6]         # ps6
    right = sensor_values[2]        # ps2
    
    # 避障逻辑
    if front < 100 or front_left < 80 or front_right < 80:
        # 前方有障碍物,后退并转向
        if left < right:
            # 左侧空间大,向左转
            return -turn_speed, turn_speed
        else:
            # 右侧空间大,向右转
            return turn_speed, -turn_speed
    elif left < 50:
        # 左侧太近,向右转
        return turn_speed, -turn_speed
    elif right < 50:
        # 右侧太近,向左转
        return -turn_speed, turn_speed
    else:
        # 无障碍物,直行
        return base_speed, base_speed

# 主控制循环
while robot.step(time_step) != -1:
    # 读取传感器
    sensor_values = get_sensor_values()
    
    # 计算左右轮速度
    left_speed, right_speed = obstacle_avoidance(sensor_values)
    
    # 设置电机速度
    left_motor.setVelocity(left_speed)
    right_motor.setVelocity(right_speed)

避障策略要点

  • 多传感器融合:结合多个传感器数据,提高避障可靠性
  • 优先级策略:前方障碍物优先级最高,侧方次之
  • 平滑转向:避免急转弯,保持运动稳定性
  • 阈值调优:根据实际环境调整传感器触发阈值
  • 行为组合:可以结合多种避障策略,如Bug算法、势场法等

6. 循线行驶

循线行驶是机器人导航的基础技能。E-puck机器人可以使用地面传感器来检测地面上的线条,实现自动循线行驶。

📝 动手实践 #6: 基础循线算法:
from controller import Robot

# 创建机器人实例
robot = Robot()
time_step = int(robot.getBasicTimeStep())

# 获取左右电机
left_motor = robot.getDevice("left_wheel_motor")
right_motor = robot.getDevice("right_wheel_motor")
left_motor.setPosition(float('inf'))
right_motor.setPosition(float('inf'))

# 获取地面传感器(如果有的话)
# 注意:标准E-puck可能没有地面传感器,这里用距离传感器模拟
ground_sensors = []
for i in range(3):  # 假设有3个地面传感器
    sensor = robot.getDevice(f"gs{i}")
    sensor.enable(time_step)
    ground_sensors.append(sensor)

# 速度设置
base_speed = 2.0
turn_speed = 1.5

def line_following_control(ground_values):
    """基于地面传感器值的循线控制"""
    # 假设地面传感器:0=黑线,1=白色地面
    left_sensor = ground_values[0]
    center_sensor = ground_values[1]
    right_sensor = ground_values[2]
    
    # 简单的PID控制逻辑
    if center_sensor < 0.5:  # 中心传感器在黑线上
        # 直行
        return base_speed, base_speed
    elif left_sensor < 0.5:  # 左侧传感器在黑线上
        # 向左转
        return -turn_speed, turn_speed
    elif right_sensor < 0.5:  # 右侧传感器在黑线上
        # 向右转
        return turn_speed, -turn_speed
    else:
        # 所有传感器都在白色区域,保持当前方向
        return base_speed * 0.5, base_speed * 0.5

# 主控制循环
while robot.step(time_step) != -1:
    # 读取地面传感器
    ground_values = [sensor.getValue() for sensor in ground_sensors]
    
    # 计算左右轮速度
    left_speed, right_speed = line_following_control(ground_values)
    
    # 设置电机速度
    left_motor.setVelocity(left_speed)
    right_motor.setVelocity(right_speed)

循线算法要点

  • 传感器布局:通常使用3-5个地面传感器,覆盖机器人前方区域
  • PID控制:可以使用比例-积分-微分控制算法提高循线精度
  • 速度调节:转弯时降低速度,直行时提高速度
  • 阈值设置:根据地面颜色对比度调整传感器触发阈值
  • 交叉路口:可以检测T字路口、十字路口等特殊路况

7. 沿墙行驶

沿墙行驶是机器人探索未知环境的重要技能。E-puck机器人可以使用侧方距离传感器来保持与墙壁的适当距离,实现沿墙导航。

📝 动手实践 #7: 沿墙行驶算法:
from controller import Robot

# 创建机器人实例
robot = Robot()
time_step = int(robot.getBasicTimeStep())

# 获取左右电机
left_motor = robot.getDevice("left_wheel_motor")
right_motor = robot.getDevice("right_wheel_motor")
left_motor.setPosition(float('inf'))
right_motor.setPosition(float('inf'))

# 获取侧方距离传感器
left_sensor = robot.getDevice("ps6")   # 左侧传感器
right_sensor = robot.getDevice("ps2")  # 右侧传感器
front_sensor = robot.getDevice("ps0")  # 前方传感器

# 启用传感器
left_sensor.enable(time_step)
right_sensor.enable(time_step)
front_sensor.enable(time_step)

# 速度设置
base_speed = 2.0
turn_speed = 1.5

# 目标距离(与墙壁保持的距离)
target_distance = 80.0

def wall_following_control(left_dist, right_dist, front_dist):
    """沿墙行驶控制算法"""
    # 检查前方是否有障碍物
    if front_dist < 100:
        # 前方有障碍物,停止并转向
        return -turn_speed, turn_speed
    
    # 沿墙行驶逻辑
    if left_dist < target_distance - 20:  # 左侧太近
        # 向右转,远离左侧墙壁
        return turn_speed, -turn_speed
    elif left_dist > target_distance + 20:  # 左侧太远
        # 向左转,靠近左侧墙壁
        return -turn_speed, turn_speed
    else:
        # 距离合适,直行
        return base_speed, base_speed

# 主控制循环
while robot.step(time_step) != -1:
    # 读取传感器
    left_distance = left_sensor.getValue()
    right_distance = right_sensor.getValue()
    front_distance = front_sensor.getValue()
    
    # 计算左右轮速度
    left_speed, right_speed = wall_following_control(
        left_distance, right_distance, front_distance
    )
    
    # 设置电机速度
    left_motor.setVelocity(left_speed)
    right_motor.setVelocity(right_speed)

沿墙行驶要点

  • 距离控制:保持与墙壁的适当距离,避免碰撞或偏离
  • 前方检测:同时检测前方障碍物,避免撞墙
  • 平滑转向:使用比例控制,避免急转弯
  • 边界处理:处理墙壁拐角、开口等特殊情况
  • 多传感器融合:结合多个传感器数据提高导航精度

8. 路径规划基础

路径规划是机器人导航的核心技术,它帮助机器人在复杂环境中找到从起点到目标点的最优路径。E-puck机器人可以使用多种算法来实现路径规划。

📝 动手实践 #8: 简单路径规划算法:
from controller import Robot
import math

class PathPlanner:
    def __init__(self, robot):
        self.robot = robot
        self.time_step = int(robot.getBasicTimeStep())
        
        # 获取电机和传感器
        self.left_motor = robot.getDevice("left_wheel_motor")
        self.right_motor = robot.getDevice("right_wheel_motor")
        self.left_motor.setPosition(float('inf'))
        self.right_motor.setPosition(float('inf'))
        
        # 获取距离传感器
        self.sensors = []
        for i in range(8):
            sensor = robot.getDevice(f"ps{i}")
            sensor.enable(self.time_step)
            self.sensors.append(sensor)
        
        # 路径规划参数
        self.target_x = 5.0  # 目标X坐标
        self.target_z = 5.0  # 目标Z坐标
        self.position_tolerance = 0.5  # 位置容差
        
    def get_robot_position(self):
        """获取机器人当前位置(简化版本)"""
        # 这里需要根据实际机器人实现位置获取
        # 可以使用GPS传感器或里程计
        return 0.0, 0.0  # 返回当前位置的x, z坐标
    
    def calculate_heading_to_target(self, current_x, current_z):
        """计算朝向目标的角度"""
        dx = self.target_x - current_x
        dz = self.target_z - current_z
        return math.atan2(dx, dz)
    
    def get_obstacle_info(self):
        """获取障碍物信息"""
        sensor_values = [sensor.getValue() for sensor in self.sensors]
        
        # 检测前方障碍物
        front_obstacle = min(sensor_values[0], sensor_values[1], sensor_values[7])
        left_obstacle = sensor_values[6]
        right_obstacle = sensor_values[2]
        
        return front_obstacle, left_obstacle, right_obstacle
    
    def navigate_to_target(self):
        """导航到目标点"""
        while self.robot.step(self.time_step) != -1:
            current_x, current_z = self.get_robot_position()
            
            # 检查是否到达目标
            distance_to_target = math.sqrt(
                (self.target_x - current_x)**2 + (self.target_z - current_z)**2
            )
            
            if distance_to_target < self.position_tolerance:
                print("到达目标点!")
                self.stop_motors()
                break
            
            # 获取障碍物信息
            front_dist, left_dist, right_dist = self.get_obstacle_info()
            
            # 路径规划决策
            if front_dist < 100:  # 前方有障碍物
                # 选择障碍物较少的一侧
                if left_dist > right_dist:
                    self.turn_left()
                else:
                    self.turn_right()
            else:
                # 计算朝向目标的角度
                target_heading = self.calculate_heading_to_target(current_x, current_z)
                # 这里需要实现转向控制逻辑
                self.move_forward()
    
    def move_forward(self):
        """前进"""
        self.left_motor.setVelocity(2.0)
        self.right_motor.setVelocity(2.0)
    
    def turn_left(self):
        """左转"""
        self.left_motor.setVelocity(-1.5)
        self.right_motor.setVelocity(1.5)
    
    def turn_right(self):
        """右转"""
        self.left_motor.setVelocity(1.5)
        self.right_motor.setVelocity(-1.5)
    
    def stop_motors(self):
        """停止电机"""
        self.left_motor.setVelocity(0.0)
        self.right_motor.setVelocity(0.0)

# 使用示例
robot = Robot()
planner = PathPlanner(robot)
planner.navigate_to_target()

路径规划要点

  • 目标导向:始终朝向目标点,避免随机游走
  • 障碍物检测:实时检测环境中的障碍物
  • 决策逻辑:根据障碍物分布选择最优路径
  • 位置跟踪:持续跟踪机器人当前位置
  • 容差设置:设置合适的位置和角度容差

9. 高级导航

高级导航结合了多种技术,包括SLAM(同时定位与地图构建)、路径优化、动态避障等。E-puck机器人可以通过这些技术实现更加智能和高效的导航。

📝 动手实践 #9: 高级导航控制器:
from controller import Robot
import math
import numpy as np

class AdvancedNavigator:
    def __init__(self, robot):
        self.robot = robot
        self.time_step = int(robot.getBasicTimeStep())
        
        # 获取设备
        self.left_motor = robot.getDevice("left_wheel_motor")
        self.right_motor = robot.getDevice("right_wheel_motor")
        self.left_motor.setPosition(float('inf'))
        self.right_motor.setPosition(float('inf'))
        
        # 获取传感器
        self.sensors = []
        for i in range(8):
            sensor = robot.getDevice(f"ps{i}")
            sensor.enable(self.time_step)
            self.sensors.append(sensor)
        
        # 导航状态
        self.navigation_state = "EXPLORING"  # EXPLORING, NAVIGATING, AVOIDING
        self.target_points = [(2, 2), (4, 2), (4, 4), (2, 4)]  # 目标点列表
        self.current_target_index = 0
        
        # 地图数据(简化版本)
        self.occupancy_grid = np.zeros((10, 10))  # 10x10网格地图
        
    def update_occupancy_grid(self):
        """更新占用栅格地图"""
        sensor_values = [sensor.getValue() for sensor in self.sensors]
        
        # 根据传感器数据更新地图
        # 这里简化处理,实际应用中需要更复杂的算法
        for i, value in enumerate(sensor_values):
            if value < 100:  # 检测到障碍物
                # 计算障碍物在地图中的位置
                angle = i * math.pi / 4  # 传感器角度
                distance = value / 1000.0  # 转换为米
                
                # 更新地图(简化版本)
                x = int(5 + distance * math.cos(angle))
                z = int(5 + distance * math.sin(angle))
                
                if 0 <= x < 10 and 0 <= z < 10:
                    self.occupancy_grid[x, z] = 1  # 标记为障碍物
    
    def find_path_to_target(self, target_x, target_z):
        """简单的A*路径规划(简化版本)"""
        # 这里实现简化的路径规划算法
        # 实际应用中可以使用完整的A*算法
        return [(0, 0), (target_x, target_z)]  # 简化路径
    
    def execute_navigation(self):
        """执行导航控制"""
        if self.current_target_index >= len(self.target_points):
            print("所有目标点已访问完成!")
            return False
        
        target_x, target_z = self.target_points[self.current_target_index]
        
        # 更新地图
        self.update_occupancy_grid()
        
        # 检查是否到达当前目标
        current_pos = self.get_robot_position()
        distance_to_target = math.sqrt(
            (target_x - current_pos[0])**2 + (target_z - current_pos[1])**2
        )
        
        if distance_to_target < 0.5:
            print(f"到达目标点 {self.current_target_index + 1}")
            self.current_target_index += 1
            return True
        
        # 执行导航
        self.navigate_to_point(target_x, target_z)
        return True
    
    def navigate_to_point(self, target_x, target_z):
        """导航到指定点"""
        current_pos = self.get_robot_position()
        
        # 计算朝向目标的角度
        dx = target_x - current_pos[0]
        dz = target_z - current_pos[1]
        target_angle = math.atan2(dx, dz)
        
        # 获取障碍物信息
        front_dist = min(self.sensors[0].getValue(), self.sensors[1].getValue())
        
        if front_dist < 80:  # 前方有障碍物
            # 避障
            self.avoid_obstacle()
        else:
            # 朝向目标
            self.turn_towards_target(target_angle)
            self.move_forward()
    
    def avoid_obstacle(self):
        """避障行为"""
        left_dist = self.sensors[6].getValue()
        right_dist = self.sensors[2].getValue()
        
        if left_dist > right_dist:
            self.turn_left()
        else:
            self.turn_right()
    
    def turn_towards_target(self, target_angle):
        """转向目标角度"""
        # 这里需要实现角度控制逻辑
        pass
    
    def move_forward(self):
        """前进"""
        self.left_motor.setVelocity(2.0)
        self.right_motor.setVelocity(2.0)
    
    def turn_left(self):
        """左转"""
        self.left_motor.setVelocity(-1.5)
        self.right_motor.setVelocity(1.5)
    
    def turn_right(self):
        """右转"""
        self.left_motor.setVelocity(1.5)
        self.right_motor.setVelocity(-1.5)
    
    def get_robot_position(self):
        """获取机器人位置(简化版本)"""
        return 0.0, 0.0  # 实际应用中需要真实位置

# 使用示例
robot = Robot()
navigator = AdvancedNavigator(robot)

while robot.step(32) != -1:
    if not navigator.execute_navigation():
        break

高级导航要点

  • 状态机管理:使用状态机管理不同的导航模式
  • 地图构建:实时构建和更新环境地图
  • 路径优化:使用算法优化路径规划
  • 多目标导航:支持多个目标点的连续导航
  • 动态避障:在导航过程中实时避障

10. 群体行为

群体行为研究多个机器人如何协同工作,实现复杂的集体任务。E-puck机器人非常适合群体行为研究,因为它们体积小、成本低、易于控制。

📝 动手实践 #10: 群体行为控制器:
from controller import Robot
import math
import random

class SwarmRobot:
    def __init__(self, robot, robot_id):
        self.robot = robot
        self.robot_id = robot_id
        self.time_step = int(robot.getBasicTimeStep())
        
        # 获取设备
        self.left_motor = robot.getDevice("left_wheel_motor")
        self.right_motor = robot.getDevice("right_wheel_motor")
        self.left_motor.setPosition(float('inf'))
        self.right_motor.setPosition(float('inf'))
        
        # 获取传感器
        self.sensors = []
        for i in range(8):
            sensor = robot.getDevice(f"ps{i}")
            sensor.enable(self.time_step)
            self.sensors.append(sensor)
        
        # 群体行为参数
        self.separation_distance = 0.3  # 分离距离
        self.alignment_strength = 0.5   # 对齐强度
        self.cohesion_strength = 0.3   # 凝聚强度
        
        # 机器人状态
        self.position = [0, 0, 0]
        self.velocity = [0, 0, 0]
        self.heading = 0
        
    def update_position(self):
        """更新机器人位置(简化版本)"""
        # 实际应用中需要从GPS或里程计获取
        pass
    
    def get_neighbor_info(self):
        """获取邻居机器人信息(简化版本)"""
        # 实际应用中需要通信模块
        return []  # 返回邻居信息列表
    
    def calculate_flocking_forces(self):
        """计算群体行为力"""
        neighbors = self.get_neighbor_info()
        
        if not neighbors:
            return 0, 0  # 没有邻居,返回零力
        
        # 分离力(避免碰撞)
        separation_force_x = 0
        separation_force_z = 0
        
        # 对齐力(与邻居保持相同方向)
        alignment_force = 0
        
        # 凝聚力(向邻居中心移动)
        cohesion_force_x = 0
        cohesion_force_z = 0
        
        neighbor_count = len(neighbors)
        
        for neighbor in neighbors:
            # 计算分离力
            dx = self.position[0] - neighbor['x']
            dz = self.position[2] - neighbor['z']
            distance = math.sqrt(dx*dx + dz*dz)
            
            if distance < self.separation_distance and distance > 0:
                # 分离力与距离成反比
                force = (self.separation_distance - distance) / distance
                separation_force_x += dx * force
                separation_force_z += dz * force
            
            # 计算对齐力
            alignment_force += neighbor['heading']
            
            # 计算凝聚力
            cohesion_force_x += neighbor['x']
            cohesion_force_z += neighbor['z']
        
        # 平均化
        if neighbor_count > 0:
            alignment_force /= neighbor_count
            cohesion_force_x /= neighbor_count
            cohesion_force_z /= neighbor_count
            
            # 计算凝聚力(指向邻居中心)
            cohesion_force_x = (cohesion_force_x - self.position[0]) * self.cohesion_strength
            cohesion_force_z = (cohesion_force_z - self.position[2]) * self.cohesion_strength
        
        # 综合力
        total_force_x = separation_force_x + cohesion_force_x
        total_force_z = separation_force_z + cohesion_force_z
        
        return total_force_x, total_force_z
    
    def execute_swarm_behavior(self):
        """执行群体行为"""
        # 更新位置
        self.update_position()
        
        # 计算群体行为力
        force_x, force_z = self.calculate_flocking_forces()
        
        # 获取障碍物信息
        front_dist = min(self.sensors[0].getValue(), self.sensors[1].getValue())
        
        if front_dist < 100:  # 前方有障碍物
            # 避障
            self.avoid_obstacle()
        else:
            # 应用群体行为力
            self.apply_swarm_forces(force_x, force_z)
    
    def apply_swarm_forces(self, force_x, force_z):
        """应用群体行为力"""
        # 将力转换为电机控制
        # 这里简化处理,实际应用中需要更复杂的控制算法
        
        # 计算转向角度
        target_heading = math.atan2(force_x, force_z)
        heading_diff = target_heading - self.heading
        
        # 标准化角度差
        while heading_diff > math.pi:
            heading_diff -= 2 * math.pi
        while heading_diff < -math.pi:
            heading_diff += 2 * math.pi
        
        # 根据角度差控制转向
        if abs(heading_diff) > 0.1:
            if heading_diff > 0:
                self.turn_right()
            else:
                self.turn_left()
        else:
            self.move_forward()
    
    def avoid_obstacle(self):
        """避障行为"""
        left_dist = self.sensors[6].getValue()
        right_dist = self.sensors[2].getValue()
        
        if left_dist > right_dist:
            self.turn_left()
        else:
            self.turn_right()
    
    def move_forward(self):
        """前进"""
        self.left_motor.setVelocity(2.0)
        self.right_motor.setVelocity(2.0)
    
    def turn_left(self):
        """左转"""
        self.left_motor.setVelocity(-1.5)
        self.right_motor.setVelocity(1.5)
    
    def turn_right(self):
        """右转"""
        self.left_motor.setVelocity(1.5)
        self.right_motor.setVelocity(-1.5)

# 使用示例
robot = Robot()
swarm_robot = SwarmRobot(robot, 1)

while robot.step(32) != -1:
    swarm_robot.execute_swarm_behavior()

群体行为要点

  • 分离:避免机器人之间碰撞
  • 对齐:保持群体运动方向一致
  • 凝聚:保持群体聚集在一起
  • 通信:机器人之间交换信息
  • 协调:实现集体任务目标

11. 参数优化

参数优化是提高机器人性能的关键技术。通过系统性地调整控制参数,可以找到最优的机器人行为配置。

📝 动手实践 #11: 参数优化算法:
from controller import Robot
import math
import random
import numpy as np

class ParameterOptimizer:
    def __init__(self, robot):
        self.robot = robot
        self.time_step = int(robot.getBasicTimeStep())
        
        # 获取设备
        self.left_motor = robot.getDevice("left_wheel_motor")
        self.right_motor = robot.getDevice("right_wheel_motor")
        self.left_motor.setPosition(float('inf'))
        self.right_motor.setPosition(float('inf'))
        
        # 获取传感器
        self.sensors = []
        for i in range(8):
            sensor = robot.getDevice(f"ps{i}")
            sensor.enable(self.time_step)
            self.sensors.append(sensor)
        
        # 优化参数
        self.parameters = {
            'speed': 2.0,
            'turn_rate': 1.5,
            'obstacle_threshold': 100,
            'separation_distance': 0.3,
            'alignment_strength': 0.5,
            'cohesion_strength': 0.3
        }
        
        # 优化历史
        self.optimization_history = []
        
    def evaluate_performance(self, params):
        """评估参数性能"""
        # 设置参数
        self.parameters.update(params)
        
        # 运行测试(简化版本)
        test_duration = 30  # 30秒测试
        start_time = self.robot.getTime()
        
        total_distance = 0
        collision_count = 0
        smoothness_score = 0
        
        while self.robot.getTime() - start_time < test_duration:
            if self.robot.step(self.time_step) == -1:
                break
            
            # 执行控制
            self.execute_control()
            
            # 计算性能指标
            # 这里简化处理,实际应用中需要更复杂的计算
            total_distance += 0.1  # 假设每步移动0.1米
            
            # 检查碰撞
            if self.check_collision():
                collision_count += 1
            
            # 计算平滑度
            smoothness_score += self.calculate_smoothness()
        
        # 综合性能评分
        performance_score = (
            total_distance * 0.4 +           # 距离权重40%
            (1.0 / (1 + collision_count)) * 0.3 +  # 安全性权重30%
            smoothness_score * 0.3           # 平滑度权重30%
        )
        
        return performance_score, {
            'distance': total_distance,
            'collisions': collision_count,
            'smoothness': smoothness_score
        }
    
    def execute_control(self):
        """执行控制逻辑"""
        # 获取传感器数据
        sensor_values = [sensor.getValue() for sensor in self.sensors]
        front_dist = min(sensor_values[0], sensor_values[1])
        
        # 避障控制
        if front_dist < self.parameters['obstacle_threshold']:
            self.avoid_obstacle()
        else:
            self.move_forward()
    
    def avoid_obstacle(self):
        """避障行为"""
        left_dist = self.sensors[6].getValue()
        right_dist = self.sensors[2].getValue()
        
        if left_dist > right_dist:
            self.turn_left()
        else:
            self.turn_right()
    
    def move_forward(self):
        """前进"""
        speed = self.parameters['speed']
        self.left_motor.setVelocity(speed)
        self.right_motor.setVelocity(speed)
    
    def turn_left(self):
        """左转"""
        turn_rate = self.parameters['turn_rate']
        self.left_motor.setVelocity(-turn_rate)
        self.right_motor.setVelocity(turn_rate)
    
    def turn_right(self):
        """右转"""
        turn_rate = self.parameters['turn_rate']
        self.left_motor.setVelocity(turn_rate)
        self.right_motor.setVelocity(-turn_rate)
    
    def check_collision(self):
        """检查碰撞(简化版本)"""
        # 实际应用中需要更复杂的碰撞检测
        return False
    
    def calculate_smoothness(self):
        """计算运动平滑度(简化版本)"""
        # 实际应用中需要计算加速度变化等指标
        return 1.0
    
    def genetic_algorithm_optimization(self, generations=50, population_size=20):
        """遗传算法优化"""
        # 初始化种群
        population = self.initialize_population(population_size)
        
        for generation in range(generations):
            print(f"第 {generation + 1} 代优化...")
            
            # 评估种群
            fitness_scores = []
            for individual in population:
                score, metrics = self.evaluate_performance(individual)
                fitness_scores.append(score)
                
                # 记录优化历史
                self.optimization_history.append({
                    'generation': generation,
                    'parameters': individual.copy(),
                    'score': score,
                    'metrics': metrics
                })
            
            # 选择优秀个体
            selected = self.selection(population, fitness_scores)
            
            # 交叉和变异
            new_population = []
            while len(new_population) < population_size:
                parent1, parent2 = random.sample(selected, 2)
                child1, child2 = self.crossover(parent1, parent2)
                child1 = self.mutate(child1)
                child2 = self.mutate(child2)
                new_population.extend([child1, child2])
            
            population = new_population[:population_size]
            
            # 输出当前最佳结果
            best_score = max(fitness_scores)
            best_index = fitness_scores.index(best_score)
            best_params = population[best_index]
            print(f"最佳分数: {best_score:.3f}")
            print(f"最佳参数: {best_params}")
        
        return self.get_best_parameters()
    
    def initialize_population(self, size):
        """初始化种群"""
        population = []
        for _ in range(size):
            individual = {}
            for param, value in self.parameters.items():
                if isinstance(value, float):
                    # 在参数值附近随机变化
                    individual[param] = value * random.uniform(0.5, 1.5)
                else:
                    individual[param] = value
            population.append(individual)
        return population
    
    def selection(self, population, fitness_scores):
        """选择操作"""
        # 锦标赛选择
        selected = []
        for _ in range(len(population)):
            tournament = random.sample(range(len(population)), 3)
            winner = max(tournament, key=lambda i: fitness_scores[i])
            selected.append(population[winner])
        return selected
    
    def crossover(self, parent1, parent2):
        """交叉操作"""
        child1 = parent1.copy()
        child2 = parent2.copy()
        
        # 随机选择交叉点
        crossover_point = random.random()
        for param in self.parameters:
            if random.random() < crossover_point:
                child1[param], child2[param] = child2[param], child1[param]
        
        return child1, child2
    
    def mutate(self, individual):
        """变异操作"""
        for param in individual:
            if random.random() < 0.1:  # 10%变异概率
                if isinstance(individual[param], float):
                    individual[param] *= random.uniform(0.8, 1.2)
        return individual
    
    def get_best_parameters(self):
        """获取最佳参数"""
        if not self.optimization_history:
            return self.parameters
        
        best_record = max(self.optimization_history, key=lambda x: x['score'])
        return best_record['parameters']

# 使用示例
robot = Robot()
optimizer = ParameterOptimizer(robot)

# 运行遗传算法优化
best_params = optimizer.genetic_algorithm_optimization(generations=20, population_size=10)
print(f"优化完成!最佳参数: {best_params}")

参数优化要点

  • 性能指标:定义明确的评估标准
  • 搜索算法:使用合适的优化算法
  • 参数范围:设置合理的参数搜索空间
  • 自动化测试:实现自动化的参数评估
  • 结果分析:分析参数对性能的影响

12. 实际应用

E-puck机器人在实际应用中有广泛的用途,从教育研究到工业应用,都可以看到它的身影。

教育应用

  • 机器人学教学:学习机器人控制、传感器融合、路径规划等概念
  • 编程教育:通过实际编程控制机器人,提高编程技能
  • 算法验证:验证各种机器人算法的有效性
  • 团队协作:多人协作完成复杂任务
  • 竞赛平台:参与机器人竞赛,提高实践能力

研究应用

  • 群体智能:研究多机器人系统的协同行为
  • 机器学习:应用强化学习、神经网络等算法
  • 环境探索:未知环境的自主探索和地图构建
  • 人机交互:研究机器人与人类的交互方式
  • 生物启发:模拟生物的行为模式

工业应用

  • 仓储物流:自动货物搬运和分拣
  • 清洁服务:自动地面清洁和消毒
  • 安全监控:环境安全监测和预警
  • 质量检测:产品缺陷检测和质量控制
  • 协作制造:与人类工人协作完成制造任务

13. 总结与进阶

恭喜你完成了E-puck机器人学习教程!通过本教程,你已经掌握了从基础运动控制到高级导航的完整技能体系。

已掌握的核心技能

  • 基础控制:电机控制、传感器读取、基本行为编程
  • 导航技能:避障、循线、沿墙、路径规划
  • 高级功能:群体行为、参数优化、监督者控制
  • 实际应用:了解机器人在各个领域的应用
  • 编程思维:机器人编程的思维方式和设计模式

进阶学习方向

  • SLAM技术:同时定位与地图构建
  • 深度学习:神经网络在机器人控制中的应用
  • 多机器人系统:大规模机器人群体控制
  • 人机协作:机器人与人类的协作技术
  • 实际部署:将仿真算法部署到真实机器人

实践建议

  • 循序渐进:从简单任务开始,逐步增加复杂度
  • 多实验:尝试不同的参数和算法组合
  • 记录分析:详细记录实验结果,分析成功和失败的原因
  • 团队协作:与他人合作,分享经验和想法
  • 持续学习:关注机器人技术的最新发展

E-puck机器人是一个优秀的学习平台,通过本教程的学习,你已经具备了机器人编程的坚实基础。希望你能继续探索机器人技术的奥秘,创造出更多有趣和有用的应用!

下一步学习资源

  • 官方文档:E-puck官方文档
  • 社区论坛:参与Webots和E-puck相关讨论
  • 开源项目:研究优秀的开源机器人项目
  • 学术论文:阅读相关领域的研究论文
  • 实践项目:设计和实现自己的机器人项目