25、基于传感器的机器人蒙特卡罗定位技术详解

基于传感器的机器人蒙特卡罗定位技术详解

1. 利用传感器跟踪相对姿态

要跟踪机器人的相对姿态,我们首先需要计算编码器读数的增量,并将这些增量输入到 convert_odometry_to_motion 函数中:

rot1, trans, rot2 = self.convert_odometry_to_motion(
    new_encoder_left - self.last_encoder_left, 
    new_encoder_right - self.last_encoder_right
)

之后,更新最后的编码器读数,以便下次计算增量:

self.last_encoder_left = new_encoder_left
self.last_encoder_right = new_encoder_right

最后,将这些里程计值应用到机器人的姿态上:

self.move_poses(rot1, trans, rot2)

为了调用这个运动模型,在 Simulation.main 中添加以下代码:

while True:
    await asyncio.sleep(0.05)
    self.motion_model()
    send_poses(self.poses)

此代码会在每个周期应用运动模型,然后发送姿态信息。由于运动模型的运行需要时间,因此减少了 sleep 时间以保持 UART 数据速率稳定。将 robot 文件夹的内容复制到 Raspberry Pi Pico 上,并启动 display_from_robot 应用程序。按下启动按钮后,你将看到机器人在场地中移动时姿态的变化。

2. 姿态移动概率

在现实世界中,机器人的移动并非完全确定。即使使用了编码器,车轮可能会打滑,车轮尺寸可能存在细微差异,计算也可能不完全准确。如图 13.11 所示,初始的机器人姿态猜测会在某个点周围形成一个集群,当机器人朝特定方向移动时,由于运动的不确定性,这个集群会散开。

为了模拟这种不确定性,我们使用以 0 为均值的概率分布。这里选择将两个从 -1.0 到 1.0 的均匀分布样本相加并除以 2 的方式,得到近似三角形的分布(n = 2)。在 robot/code.py 中,在 class Simulation 之前添加以下代码:

def get_random_sample(mean, scale):
    return mean + (random.uniform(-scale, scale) + random.uniform(-scale, scale)) / 2

同时,考虑到运动越大,随机误差因子也越大,我们在 Simulation.__init__ 类中添加以下参数:

self.last_encoder_right = robot.right_encoder.read()
self.alpha_rot = 0.09
self.alpha_rot_trans = 0.05
self.alpha_trans = 0.12
self.alpha_trans_rot = 0.05

这些参数的值应在 0 到 1 之间,并且需要根据机器人的实际误差情况进行调整。

接下来,在 Simulation 类中添加 randomise_motion 方法:

def randomise_motion(self, rot1, trans, rot2):
    rot1_scale = self.alpha_rot * abs(rot1) + self.alpha_rot_trans * abs(trans)
    trans_scale = self.alpha_trans * abs(trans) + self.alpha_trans_rot * (abs(rot1) + abs(rot2))
    rot2_scale = self.alpha_rot * abs(rot2) + self.alpha_rot_trans * abs(trans)
    rot1_model = np.array([get_random_sample(rot1, rot1_scale) for _ in range(self.poses.shape[0])])
    trans_model = np.array([get_random_sample(trans, trans_scale) for _ in range(self.poses.shape[0])])
    rot2_model = np.array([get_random_sample(rot2, rot2_scale) for _ in range(self.poses.shape[0])])
    return rot1_model, trans_model, rot2_model

motion_model 方法中使用这个随机化的运动模型:

def motion_model(self):
    """Apply the motion model"""
    new_encoder_left = robot.left_encoder.read()
    new_encoder_right = robot.right_encoder.read()
    rot1, trans, rot2 = self.convert_odometry_to_motion(
        new_encoder_left - self.last_encoder_left, 
        new_encoder_right - self.last_encoder_right
    )
    self.last_encoder_left = new_encoder_left
    self.last_encoder_right = new_encoder_right
    rot1_model, trans_model, rot2_model = self.randomise_motion(rot1, trans, rot2)
    self.move_poses(rot1_model, trans_model, rot2_model)

robot 文件夹复制到机器人上,并在计算机上运行 display_from_robot.py 应用程序,你会看到机器人的运动带有一定的随机性。

3. 故障排除

如果上述示例无法正常工作,可以尝试以下方法:
- 将机器人支撑起来并连接到计算机,通过 Mu 编辑器的串口查看其状态,以检查代码是否存在错误。
- 如果机器人的移动距离过大或过小,调整 robot/robot.py 中的测量值,使其与你的机器人匹配。
- 如果遇到传感器或 I2C 问题,检查布线和之前的传感器演示示例,并确保使用的是新电池。

4. 蒙特卡罗定位

机器人的姿态可能会超出场地范围,而距离传感器的读数可以帮助我们判断哪些姿态猜测更有可能。蒙特卡罗模拟可以根据传感器读数的可能性来改进这些猜测。

模拟过程包括移动姿态、观察传感器状态以创建基于可能性的权重(观察模型),然后根据权重重新采样猜测,得到新的一代猜测。这个过程也被称为粒子滤波。

4.1 从位置生成姿态权重

初始的权重生成可以基于一个简单的问题:机器人是否在场地内?如果不在,降低该姿态的概率。在 robot/arena.py 文件中进行以下操作:
1. 添加一个表示极低概率的值:

low_probability = 10 ** -10
  1. 添加一个函数来检查场地是否包含某个点:
def contains(x, y):
    if x < 0 or x > width \
            or y < 0 or y > height:
        return False
    if x > (width - cutout_width) and y < cutout_height:
        return False
    return True
  1. robot/code.py Simulation 类中添加 observation_model 方法来生成权重:
def observation_model(self):
    weights = np.ones(self.poses.shape[0], dtype=np.float)
    for index, pose in enumerate(self.poses):
        if not arena.contains(pose[0], pose[1]):
            weights[index] = arena.low_probability
    return weights
4.2 重新采样姿态

为了让后续的粒子更倾向于更有可能的姿态,我们使用低方差重采样方法。在 robot/code.py Simulation 类中添加 resample 方法:

def resample(self, weights, sample_count):
    samples = np.zeros((sample_count, 3))
    interval = np.sum(weights) / sample_count
    shift = random.uniform(0, interval)
    cumulative_weights = weights[0]
    source_index = 0
    for current_index in range(sample_count):
        weight_index = shift + current_index * interval
        while weight_index > cumulative_weights:
            source_index += 1
            source_index = min(len(weights) - 1, source_index)
            cumulative_weights += weights[source_index]
        samples[current_index] = self.poses[source_index]
    return samples

Simulation.__init__ 中设置种群大小:

def __init__(self):
    self.population_size = 200

Simulation.main 的主循环中应用观察模型和重采样:

while True:
    weights = self.observation_model()
    send_poses(self.resample(weights, 20))
    self.poses = self.resample(weights, self.population_size)
    await asyncio.sleep(0.05)
    self.motion_model()

robot 文件夹发送到 Raspberry Pi Pico 并启动应用程序,你会看到场地外的样本数量逐渐减少。

5. 结合距离传感器

机器人配备了两个距离传感器,我们的代码将比较机器人感知的距离与模型数据。为了更高效地建模,我们创建一个查找表。

5.1 在空间中建模距离传感器

robot/arena.py 文件的顶部导入 numpy

from ulab import numpy as np

设置网格单元大小和过扫描:

grid_cell_size = 50
overscan = 2

添加计算到线段距离的函数:

def get_distance_to_segment(x, y, segment):
    x1, y1 = segment[0]
    x2, y2 = segment[1]
    if y1 == y2 and x >= min(x1, x2) and x <= max(x1, x2):
        return abs(y - y1)
    if x1 == x2 and y >= min(y1, y2) and y <= max(y1, y2):
        return abs(x - x1)
    return np.sqrt(
        min(
            (x - x1) ** 2 + (y - y1) ** 2, 
            (x - x2) ** 2 + (y - y2) ** 2
        )
    )

添加将距离转换为似然值的函数:

def get_distance_likelihood(x, y):
    min_distance = None
    for segment in boundary_lines:
        distance = get_distance_to_segment(x, y, segment)
        if min_distance is None or distance < min_distance:
            min_distance = distance
    return 1.0 / (1 + min_distance/100) ** 2

添加生成距离网格的函数:

def make_distance_grid():
    grid = np.zeros((
        width // grid_cell_size + 2 * overscan, 
        height // grid_cell_size + 2 * overscan
    ), dtype=np.float)
    for x in range(grid.shape[0]):
        column_x = x * grid_cell_size - (overscan * grid_cell_size)
        for y in range(grid.shape[1]):
            row_y = y * grid_cell_size - (overscan * grid_cell_size)
            grid[x, y] = get_distance_likelihood(
                column_x, row_y
            )
    return grid

distance_grid = make_distance_grid()
5.2 从距离传感器生成权重

robot/robot.py 中添加距离传感器的位置信息:

dist_side_mm = 37
dist_forward_mm = 66

robot/arena.py 中添加查找距离网格中位置的函数:

def get_distance_likelihood_at(x, y):
    """Return the distance grid value at the given point."""
    grid_x = int(x // grid_cell_size + overscan)
    grid_y = int(y // grid_cell_size + overscan)
    if grid_x < 0 or grid_x >= distance_grid.shape[0] or \
            grid_y < 0 or grid_y >= distance_grid.shape[1]:
        return low_probability
    return distance_grid[grid_x, grid_y]

robot/code.py Simulation 类中添加计算传感器端点的方法:

def get_sensor_endpoints(self, sensor_reading, right=False):
    adjacent = sensor_reading + robot.dist_forward_mm
    angle = np.atan(robot.dist_side_mm / adjacent)
    if right:
        angle = - angle
    hypotenuse = np.sqrt(robot.dist_side_mm**2 + adjacent**2)
    pose_angles = np.radians(self.poses[:,2]) + angle
    sensor_endpoints = np.zeros((self.poses.shape[0], 2), dtype=np.float)
    sensor_endpoints[:,0] = self.poses[:,0] + hypotenuse * np.cos(pose_angles)
    sensor_endpoints[:,1] = self.poses[:,1] + hypotenuse * np.sin(pose_angles)
    return sensor_endpoints

添加 observe_distance_sensors 方法来应用传感器信息到现有权重:

def observe_distance_sensors(self, weights):
    left_sensor = self.get_sensor_endpoints(self.distance_sensors.left)
    right_sensor = self.get_sensor_endpoints(self.distance_sensors.right, True)
    for index in range(self.poses.shape[0]):
        sensor_weight = arena.get_distance_likelihood_at(left_sensor[index,0], left_sensor[index,1])
        sensor_weight += arena.get_distance_likelihood_at(right_sensor[index,0], right_sensor[index,1])
        weights[index] *= sensor_weight
    return weights

修改 observation_model 方法:

def observation_model(self):
    weights = np.ones(self.poses.shape[0], dtype=np.float)
    for index, pose in enumerate(self.poses):
        if not arena.contains(pose[0], pose[1]):
            weights[index] = arena.low_probability
    weights = self.observe_distance_sensors(weights)
    weights = weights / np.sum(weights)
    return weights

将此代码发送到机器人后,机器人的姿态会根据两个距离传感器的信息进行加权和重采样,在显示屏上你会看到姿态形成、分散和重新形成的过程。

总结

通过以上步骤,我们实现了基于编码器的姿态运动模型,并结合了距离传感器和场地数据进行蒙特卡罗定位。整个过程包括运动模型的应用、姿态权重的生成、重采样以及距离传感器信息的融合,最终提高了机器人姿态估计的准确性。在实际应用中,需要根据机器人的具体情况调整参数,以达到最佳效果。同时,遇到问题时可以按照故障排除部分的方法进行检查和修复。

基于传感器的机器人蒙特卡罗定位技术详解

6. 关键技术点分析

为了更好地理解整个机器人蒙特卡罗定位的过程,我们对其中的关键技术点进行详细分析。

6.1 运动模型的随机化

运动模型的随机化是为了模拟现实世界中机器人运动的不确定性。通过 get_random_sample 函数生成随机样本,结合 alpha 参数来调整随机误差的大小。以下是随机化运动模型的关键步骤:
1. 计算缩放因子 :根据 alpha 参数和当前的旋转、平移值计算缩放因子,如 rot1_scale trans_scale rot2_scale
2. 生成随机样本 :使用 get_random_sample 函数,以当前的旋转、平移值为均值,缩放因子为范围,生成随机样本。
3. 应用随机样本 :将生成的随机样本应用到 move_poses 方法中,实现姿态的随机化移动。

这个过程的流程图如下:

graph TD
    A[开始] --> B[计算旋转、平移值]
    B --> C[计算缩放因子]
    C --> D[生成随机样本]
    D --> E[应用随机样本到姿态]
    E --> F[结束]
6.2 低方差重采样方法

低方差重采样方法是蒙特卡罗定位中的重要步骤,用于根据姿态的权重重新采样,使得更有可能的姿态被保留下来。具体步骤如下:
1. 设置样本间隔和偏移 :根据权重总和和样本数量计算样本间隔,并随机生成偏移值。
2. 计算累积权重 :初始化累积权重和源样本索引。
3. 循环采样 :对于每个样本,计算权重索引,找到满足条件的源样本索引,并将其添加到新样本中。

这个过程的伪代码如下:

function resample(weights, sample_count):
    samples = zeros(sample_count, 3)
    interval = sum(weights) / sample_count
    shift = random(0, interval)
    cumulative_weights = weights[0]
    source_index = 0
    for current_index from 0 to sample_count - 1:
        weight_index = shift + current_index * interval
        while weight_index > cumulative_weights:
            source_index = source_index + 1
            source_index = min(length(weights) - 1, source_index)
            cumulative_weights = cumulative_weights + weights[source_index]
        samples[current_index] = poses[source_index]
    return samples
7. 代码优化建议

在实际应用中,为了提高代码的性能和稳定性,可以考虑以下优化建议:

7.1 减少随机样本生成的次数

get_random_sample 函数中,每次调用都会生成两个随机样本。可以考虑缓存一些随机样本,减少随机数生成的开销。

7.2 优化距离网格的生成

距离网格的生成需要遍历整个网格,计算每个单元格的距离似然值。可以考虑使用并行计算或优化算法,减少生成时间。

7.3 动态调整参数

alpha 参数和其他测量值可以根据机器人的运行情况进行动态调整,以适应不同的环境和任务。

8. 应用案例与效果展示

通过实际应用,我们可以看到机器人蒙特卡罗定位技术的效果。以下是一个具体的应用案例:

在一个室内场地中,机器人配备了编码器和两个距离传感器。将上述代码部署到机器人上,并运行 display_from_robot.py 应用程序。随着机器人的移动,我们可以观察到以下现象:
- 姿态随机化 :机器人的运动带有一定的随机性,模拟了现实世界中的不确定性。
- 样本空间缩小 :通过蒙特卡罗模拟和重采样,样本空间逐渐缩小到更有可能的姿态,减少了场地外的样本数量。
- 姿态聚类 :机器人的姿态会根据距离传感器的信息形成聚类,集中在可能的位置上。

以下是一个简单的表格,展示了不同阶段的样本数量变化:
| 阶段 | 总样本数量 | 场地内样本数量 | 场地外样本数量 |
| ---- | ---- | ---- | ---- |
| 初始 | 200 | 150 | 50 |
| 运行一段时间后 | 200 | 180 | 20 |

9. 总结与展望

通过本文的介绍,我们详细了解了基于传感器的机器人蒙特卡罗定位技术。从利用编码器跟踪相对姿态,到引入姿态移动概率的随机化,再到结合距离传感器和场地数据进行蒙特卡罗模拟,整个过程逐步提高了机器人姿态估计的准确性。

在未来的研究和应用中,我们可以进一步探索以下方向:
- 多传感器融合 :除了编码器和距离传感器,还可以结合其他传感器,如摄像头、惯性测量单元等,提高定位的精度和可靠性。
- 实时优化 :在机器人运行过程中,实时调整参数和算法,以适应不同的环境和任务。
- 复杂环境应用 :将该技术应用到更复杂的环境中,如室外环境、动态环境等,拓展其应用范围。

总之,机器人蒙特卡罗定位技术为机器人的自主定位和导航提供了一种有效的方法,具有广阔的应用前景。通过不断的研究和优化,我们可以让机器人在各种环境中更加准确地定位和导航。

【四轴飞行器】非线性三自由度四轴飞行器模拟器研究(Matlab代码实现)内容概要:本文围绕非线性三自由度四轴飞行器模拟器的研究展开,重点介绍基于Matlab代码实现的四轴飞行器动力学建模与仿真方法。研究构建了考虑非线性特性的飞行器数学模型,涵盖姿态动力学与运动学方程,实现了三自由度(滚转、俯仰、偏航)的精确模拟。文中详细阐述了系统建模过程、控制算法设计思路及仿真结果分析,帮助读者深入理解四轴飞行器的飞行动力学特性与控制机制;同时,该模拟器可用于算法验证、控制器设计与教学实验。; 适合人群:具备一定自动控制理论基础和Matlab编程能力的高校学生、科研人员及无人机相关领域的工程技术人员,尤其适合从事飞行器建模、控制算法开发的研究生和初级研究人员。; 使用场景及目标:①用于四轴飞行器非线性动力学特性的学习与仿真验证;②作为控制器(如PID、LQR、MPC等)设计与测试的仿真平台;③支持无人机控制系统教学与科研项目开发,提升对姿态控制与系统仿真的理解。; 阅读建议:建议读者结合Matlab代码逐模块分析,重点关注动力学方程的推导与实现方式,动手运行并调试仿真程序,以加深对飞行器姿态控制过程的理解。同时可扩展为六自由度模型或加入外部干扰以增强仿真真实性。
基于分布式模型预测控制DMPC的多智能体点对点过渡轨迹生成研究(Matlab代码实现)内容概要:本文围绕“基于分布式模型预测控制(DMPC)的多智能体点对点过渡轨迹生成研究”展开,重点介绍如何利用DMPC方法实现多智能体系统在复杂环境下的协同轨迹规划与控制。文中结合Matlab代码实现,详细阐述了DMPC的基本原理、数学建模过程以及在多智能体系统中的具体应用,涵盖点对点转移、避障处理、状态约束与通信拓扑等关键技术环节。研究强调算法的分布式特性,提升系统的可扩展性与鲁棒性,适用于多无人机、无人车编队等场景。同时,文档列举了大量相关科研方向与代码资源,展示了DMPC在路径规划、协同控制、电力系统、信号处理等多领域的广泛应用。; 适合人群:具备一定自动化、控制理论或机器人学基础的研究生、科研人员及从事智能系统开发的工程技术人员;熟悉Matlab/Simulink仿真环境,对多智能体协同控制、优化算法有一定兴趣或研究需求的人员。; 使用场景及目标:①用于多智能体系统的轨迹生成与协同控制研究,如无人机集群、无人驾驶车队等;②作为DMPC算法学习与仿真实践的参考资料,帮助理解分布式优化与模型预测控制的结合机制;③支撑科研论文复现、毕业设计或项目开发中的算法验证与性能对比。; 阅读建议:建议读者结合提供的Matlab代码进行实践操作,重点关注DMPC的优化建模、约束处理与信息交互机制;按文档结构逐步学习,同时参考文中提及的路径规划、协同控制等相关案例,加深对分布式控制系统的整体理解。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值