Cyberbotics 机器人课程/初级编程练习
本章由一系列针对初学者的练习组成。我们假设已经掌握了之前的练习。前几个练习仍然使用 BotStudio。我们将使用此模块创建更复杂的自动机。然后,我们将介绍 C 语言编程。您将详细了解 e-puck 设备。
本练习的目的是创建一个更复杂的自动机。此外,您将同时操作多个虚拟 e-puck。此仿真使用了更多 e-puck,您的计算机必须是近期的,以避免延迟和故障。
打开以下世界文件
.../worlds/novice_train.wbt
最靠近仿真摄像头的 e-puck 是队列的最后一个。每个 e-puck 都有自己的 BotStudio 窗口。BotStudio 窗口的顺序与 e-puck 的顺序相同,即队列中的第一个 e-puck 与最上面的 BotStudio 窗口相关联。
建议在上传之前停止仿真。选择一个 BotStudio 窗口(比如最下面的那个)。您可以像往常一样修改其自动机。您可以为每个 e-puck 使用相同的机器人控制器,也可以为每个 e-puck 使用不同的机器人控制器。如果您想为每个 e-puck 使用相同的控制器,请保存所需的自动机并将保存的文件加载到其他 e-puck 上。这种方法是推荐的。
[P.1] 创建一个自动机,使 e-puck 形成一条链,即第一个 e-puck 行驶到某处,第二个 e-puck 跟随第一个,第三个跟随第二个,等等。(提示:创建两个自动机;一个用于链中的第一个 e-puck(“火车头”)和一个用于其他 e-puck(“车厢”)。火车头应该比车厢行驶得慢得多。)
如果您没有成功,您可以打开以下自动机并尝试改进它
.../novice_train/novice_train_corr.bsg
请注意,在一个文件中有两个自动机。车厢必须以“车厢初始化”状态作为初始状态,而火车头必须以“火车头初始化”状态作为初始状态。
本练习的目的是创建一个循壁自动机。您将看到这并不容易。本练习仍然使用 BotStudio,但比之前的练习更难。
打开以下世界文件
.../worlds/novice_remain_in_shadow.wbt
您会观察到世界已经改变。板子更大,有更多障碍物,还有一堵双层墙。双层墙的目的是执行内壁或外壁循壁,障碍物的目的是绕过它们。因此,不要犹豫,通过 Shift 键加单击移动 e-puck 或障碍物。
让我们思考一下循壁算法。有很多不同的方法可以解决这个问题。建议的解决方案可以使用有限状态机来实现。首先,e-puck 必须向前行驶,直到遇到障碍物,然后它向左或向右旋转(比如向右),使其垂直于墙壁。然后,它必须沿着墙壁行驶。当然,它不知道墙壁的形状。因此,如果它离墙壁太近,它必须向左校正其轨迹。相反,如果它离墙壁太远,它必须向右校正。
[P.1] 创建一个自动机,对应于前面的描述。仅在虚拟 e-puck 上进行测试。(提示:设置条件的参数是一项艰巨的任务。如果您没有找到解决方案,请将您的 e-puck 运行到墙壁附近,观察传感器的值并思考条件。不要犹豫,添加更多状态(如“简单校正 - 左”和“困难校正 - 左”。)
如果您没有找到解决方案,请在 BotStudio 中打开以下自动机(这是一个良好的开端,但不是完美的解决方案)
.../controllers/novice_remain_in_shadow/novice_remain_in_shadow_corr.bsg
[P.2] 如果您在内壁上测试了您的自动机,请将其修改为在外壁上工作,反之亦然。
[P.3] 到目前为止,环境没有改变。添加一个转换,以便在您失去与障碍物的接触时重新找到墙壁。如果 e-puck 绕过一个被移除的障碍物,它应该找到另一个墙壁。
[P.4] 修改自动机的参数,以便在真实的 e-puck 上复制相同的行为。
你的进度
[edit | edit source]通过前两个练习,您已经了解了
- 如何使用 BotStudio 构建复杂的 FSM
- BotStudio 的局限性是什么
以下练习将教您另一种编程 e-puck 的方法:C 语言。
C 编程简介
[edit | edit source]到目前为止,您一直使用 BotStudio 来编程机器人行为。该工具使您可以快速直观地编程简单的行为。您可能也注意到了该工具的局限性,特别是表达式自由度有限,并且一些复杂的程序很快变得难以阅读。出于这个原因,需要更强大的编程工具:C 编程语言。这种编程语言具有重要的表达式自由度。借助它和 Webots 库,您可以通过编写程序来编程机器人控制器。问题是您必须了解其语法。学习 C 语言超出了本文档的范围。因此,请参考有关 C 编程的书籍。网络上也有一些关于此主题非常有用的教程,例如 C 编程的维基教科书
您不必了解这种语言的每一个细节就能成功完成以下练习。如果您是完全的初学者,请首先关注:变量、数组、函数、控制结构(布尔测试、if ... else ...、switch、for、while 等)。
在接下来的四个练习中,您将独立探索 e-puck 设备。关于设备的练习按难度排序,即分别为:LED、步进电机、红外传感器、加速度计和摄像头。
Webots 模拟的结构
[edit | edit source]要在 Webots 中创建模拟,需要两种类型的文件
- 世界文件:它定义了虚拟环境,即每个对象的形状、物理边界、位置和方向(包括机器人),以及一些其他全局参数,例如窗口的位置、模拟摄像头的参数、光源的参数、重力向量等。此文件是用 VRML[1] 语言编写的。
- 控制器文件:它是机器人使用的程序。它定义了机器人的行为。您已经看到控制器文件可以是 BotStudio 自动机,您还将看到它也可以是使用 Webots 库的 C 程序。
请注意,本文档中几乎所有世界文件都使用位于
webots_root/project/default/protos/EPuck.proto
此文件包含标准 e-puck 的描述,尤其包括设备名称。这将有助于获取设备标签。
最简单的程序
[edit | edit source]这里编写了最简单的 Webots 程序。此脚本使用 Webots 库(参考第一行)来获得基本的机器人功能。
// included libraries
#include <webots/robot.h>
// global defines
#define TIME_STEP 64 // [ms]
// global variables...
int main() {
// Webots init
wb_robot_init();
// put here your initialization code
// main loop
while(wb_robot_step(TIME_STEP) != -1) {
}
// put here your cleanup code
// Webots cleanup
wb_robot_cleanup();
return 0;
}
K-2000 [新手]
[edit | edit source]这是第一次使用 C 编程。您将创建一个围绕机器人的 LED 循环,就像您之前在练习 闪烁的 e-puck 中所做的那样。
打开世界文件和文本编辑器窗口
[edit | edit source]打开以下世界文件
.../worlds/curriculum_novice_k2000.wbt
这将打开一个小型面板。实际上,当使用 LED 时,我们不需要太多空间。您还会看到一个新窗口:文本编辑器窗口(您可以在图片中看到它)。在这个窗口中,您可以编写 C 程序,加载、保存和编译[2] 它们(要编译,请点击编译按钮)。
[P.1] 在虚拟 e-puck 上运行程序(通常,它应该在打开世界文件后自动运行。如果不是这样,您需要编译控制器并恢复模拟)。观察 e-puck 的行为。
[P.2] 仔细观察此练习的 C 编程代码。注意第二个包含语句。
[Q.1] 使用哪个函数更改 LED 的状态?您可以在哪个库中找到此函数?解释全局变量 i 在主函数中的作用。
模拟、远程控制会话和交叉编译
[edit | edit source]e-puck 有三种使用模式
- 模拟:使用 Webots 库,您可以编写机器人控制器,编译它并在虚拟 3D 环境中运行它。这是您在上一节中所做的。
- 远程控制会话:您可以编写相同的程序,像以前一样编译它,并通过蓝牙连接在真实的 e-puck 上运行它。
- 交叉编译:您可以编写相同的程序,为 e-puck 处理器交叉编译它,并将其上传到真实的机器人。在这种情况下,旧的 e-puck 程序(固件)将被您的程序替换。在这种情况下,您的程序不依赖于 Webots,并且可以在 e-puck 重启后继续运行。
如果您想创建远程控制会话,您只需在机器人窗口中选择您的蓝牙而不是模拟。您的机器人必须具有正确的固件,如部分 E-puck 先决条件 中所述。
对于交叉编译,请先在文本编辑器窗口中选择构建 | 交叉编译...菜单(或点击工具栏中的对应图标)。此操作将创建一个.hex文件,该文件可以在e-puck上执行。执行交叉编译后,Webots会要求您上传生成的文件(位于e-puck的目录中)。点击“是”按钮,然后选择要使用的蓝牙连接。文件应该上传到e-puck上。您也可以通过在仿真窗口中选择工具 | 上传到e-puck机器人...菜单来上传文件。
要了解机器人处于哪种模式,您可以调用wb_robot_get_mode()函数。在仿真中返回0,在交叉编译中返回1,在远程控制会话中返回2。
[P.4] 将固件上传到e-puck(参见E-puck 先决条件部分)。编译程序并启动远程控制会话。
修改
[edit | edit source][P.6] 修改给定的编程代码以使所有LED以同步方式闪烁。
[P.7] 通过测试确定每个设备名称对应的LED。例如,“led0”设备名称对应于e-puck最前面的LED。
电机 [新手]
[edit | edit source]本练习的目的是使用一些其他的e-puck设备:两个步进电机。
打开世界文件
[edit | edit source]打开以下世界文件
.../worlds/novice_motors.wbt
回旋镖
[edit | edit source]“步进电机是一种机电装置,它将电脉冲转换为离散机械运动”[3]。它可以将一个完整的旋转分成大量的步骤。一个e-puck步进电机有1000步。这种类型的电机具有±1步的精度。它与数字技术直接兼容。您可以使用wb_differential_wheels_set_speed(...)函数设置电机速度。该函数接收两个参数:左电机速度和右电机速度。e-puck接受-1000到1000之间的速度值。最大速度对应于大约每秒旋转一次。
要了解车轮的位置,可以使用编码器设备。请注意,e-puck没有像其他一些机器人那样测量车轮位置的物理编码器设备。但是,当执行电机步骤时,计数器会递增,如果车轮转到另一侧,则会递减。这是车轮位置的良好近似值。不幸的是,如果e-puck被阻塞并且车轮没有滑动,即使车轮没有转动,编码器计数器也可能被递增。
编码器在远程控制模式下尚未实现。因此,如果您想在真实的e-puck上使用它,请使用交叉编译。
[Q.1] 在不运行仿真情况下,描述e-puck的行为将是什么。
修改
[edit | edit source][P.2] 修改给定的编程代码以获得以下行为:e-puck向前移动,并在其车轮完全旋转一圈后停止。尝试在真实和虚拟e-puck上运行您的程序。
[P.3] 修改给定的编程代码以获得以下行为:e-puck向前移动,并在精确移动10厘米后停止。(提示:e-puck车轮半径为2.1厘米)
[P.4] [挑战] 修改给定的编程代码以获得以下行为:e-puck移动到特定的XZ坐标(相对于e-puck的初始位置)。
红外传感器 [新手]
[edit | edit source]在本练习中,您将操作红外传感器。这个设备不像前面的设备那样直观。实际上,红外传感器可以有多种用途。在本练习中,您将了解该设备提供的哪些信息以及如何使用它。日志窗口也会被介绍。
红外传感器
[edit | edit source]八个红外传感器以非规则的方式放置在e-puck周围。e-puck的前部比后部有更多传感器。红外传感器由两部分组成:红外发射器和光电传感器。这种配置使红外传感器能够发挥两种作用。
首先,它们可以测量自身与障碍物之间的距离。红外发射器发射红外光,红外光照射到潜在的障碍物上并反射回来。接收到的光线由光电传感器测量。光线的强度直接反映了物体的距离。第一个应用可能是最有趣的,因为它可以让 e-puck 了解其周围环境。在 Webots 中,这种模式下的红外传感器通过使用 *距离传感器* 来建模。需要注意的是,红外传感器的测量值是非线性的。为了说明这一点,我们进行了以下实验。将一个 e-puck 放在一面墙前。当实验开始时,e-puck 向后移动。前右红外传感器的值存储在一个文件中。这些值在图中绘制出来。请注意,两条曲线的步长并不相同。e-puck 与墙壁之间的距离呈线性增长,但红外传感器的测量值是非线性的。然后,观察偏移值。该值主要取决于光照环境。因此,这个偏移值通常是没有意义的。还要注意,距离估计取决于障碍物(颜色、方向、形状、材料)和红外传感器(特性和校准)。
其次,光电传感器可以单独使用。在这种情况下,红外传感器量化接收到的红外光的量。一个典型的应用是趋光性,即机器人跟随或避免光刺激。这种行为是受生物学启发的(特别是昆虫)。在 Webots 中,在这种模式下的红外传感器通过使用光传感器来建模。请注意,在本练习中,只操作距离传感器。但是,光传感器也可以使用。
打开以下世界文件
.../worlds/novice_ir_sensors.wbt
你应该看到一个小板,上面只有一个障碍物。为了测试红外传感器,你可以移动 e-puck 或障碍物。请注意图中所示的窗口。这个窗口称为 *日志窗口*。它显示文本。两个实体可以在此窗口中写入内容:机器人控制器或 Webots。
[P.1] 在不运行模拟的情况下,仔细观察本练习的编程代码。
[Q.1] 为什么距离传感器值要减去一个偏移值?描述一种计算此偏移值的方法。
[Q.3] 在不运行模拟的情况下,描述 e-puck 的行为将是什么。
[P.2] 在虚拟和真实 e-puck 上运行模拟,观察当物体靠近 e-puck 时 e-puck 的行为。
[P.3] 到目前为止,偏移值是任意定义的。本部分的目标是使用 calibrate 函数来校准你真实 e-puck 的红外传感器偏移值。首先,在主函数中,取消对 calibrate 函数调用的注释,并编译程序。你的真实 e-puck 必须放在通风的地方。在你的真实 e-puck 上运行程序。校准函数的运行时间取决于 n 的值。将校准函数的运行结果从日志窗口复制粘贴到程序中的ps_offset_real数组中。再次编译。你的红外传感器偏移值已校准到你的环境。
[P.4] 通过测试确定每个设备名称对应哪个红外传感器。例如,设备名称“ps2”对应于 e-puck 的右侧红外传感器。
幸运的是,红外传感器可以更简单地使用。为了绕过红外传感器的校准和对其返回值的处理,可以使用 e-puck 的对称性。如果你想创建一个简单的避碰算法,左右两侧之间的差异(示例中的 delta 变量)比红外传感器的值更重要。
[P.5] 取消 run 函数最后部分的注释并编译程序。观察代码和 e-puck 的行为。请注意,只使用了红外传感器返回的值。也可以在远程控制模式或交叉编译中尝试这部分代码在真实机器人上的效果。
[P.6] 获得与之前相同的行为,但向后移动而不是向前移动。
在本练习中,我们将首次使用 e-puck 的加速度计。你将学习这个设备的作用以及如何使用它。对这个设备的解释涉及到一些超出本文档范围的概念,例如加速度和向量。如果你想了解更多关于这些主题的信息,请分别查阅物理书籍和数学书籍。
打开以下世界文件
.../worlds/novice_accelerometer.wbt
这将打开一个包含弹簧板的世界。这个物体的作用是在斜坡上以及 e-puck 坠落时观察加速度计的行为。在测试时,不要犹豫,移动你的 e-puck(SHIFT + 鼠标按钮)并使用“步进”按钮。为了垂直移动 e-puck,请使用 SHIFT + 鼠标滚轮。
加速度可以定义为瞬时速度的变化。它的 SI 单位是 。加速度计是一种测量自身加速度(以及 e-puck 的加速度)的设备,它以 3D 向量的形式测量。加速度计的轴线如图形所示。在静止状态下,加速度计至少会测量重力加速度。电机速度的改变、机器人的旋转以及外力的影响也会影响加速度向量。e-puck 加速度计主要用于
- 测量机器人静止时地面倾斜度和方向。这些值可以通过使用重力加速度向量 3 个分量的三角函数来计算。在本练习的控制器代码中,请观察getInclination(float x,float y, float z)和getOrientation(float x,float y, float z)函数。
- 检测与障碍物的碰撞。事实上,如果加速度的模数(观察本练习的getAcceleration(float x,float y, float z)函数)在没有改变电机速度的情况下发生了剧烈变化,则可以假设发生了碰撞。
- 检测机器人的坠落。事实上,如果加速度的模数变得过低,则可以假设机器人坠落。
[Q.1] 重力加速度的方向应该是什么?加速度计测量的向量方向是什么?
[P.1] 验证您的先前答案,即在模拟中,当 e-puck 静止时,通过观察日志窗口观察重力加速度的方向。(提示:使用“步进”按钮。)
练习
[edit | edit source][P.2] 获取以下行为:当 e-puck 坠落时,身体上的 LED 会亮起。如果您想在现实中尝试,请记住 e-puck 是易碎的。
[P.3] 获取以下行为:只有最下面的 LED 亮起(根据垂直方向)。
相机 [初学者]
[edit | edit source]在 [sec:Line-following] 部分中,您已经学习了 e-puck 相机的基本知识。您通过处理 BotStudio 界面将 e-puck 相机用作线性相机。通过使用此界面,您或多或少地局限于跟随黑线。在本练习中,您将观察到,通过使用 C 编程,您可以以不同的方式使用相机。首先,您的 e-puck 将使用线性相机。它将能够跟随特定颜色的线。其次,您的 e-puck 将使用相机的整个视野跟随光源,光源以光点的形式表示。
打开世界文件
[edit | edit source]打开以下世界文件
.../worlds/novice_linear_camera.wbt
这将打开一块长木板,上面绘制了三条彩色线。
线性相机 - 跟踪彩色线
[edit | edit source]在木板上,有一条青色线、一条黄色线和一条洋红色线。这三种颜色(原色)不是随机选择的。它们具有可以使用红色、绿色或蓝色滤镜(原色)独立查看的特性。这四张图显示了模拟首先以彩色模式 (RGB) 进行,然后通过应用红色、绿色或蓝色滤镜进行。如表格所示,如果使用红色滤镜,则青色在红色通道中没有分量,因此看起来是黑色的,而洋红色有分量,因此看起来像地面一样是白色的。
颜色 | 红色通道 | 绿色通道 | 蓝色通道 |
---|---|---|---|
青色 | 0 | 1 | 1 |
洋红色 | 1 | 0 | 1 |
黄色 | 1 | 1 | 0 |
黑色 | 0 | 0 | 0 |
白色 | 1 | 1 | 1 |
在实际配置中,e-puck 相机以 RGB 模式获取图像。Webots 软件也使用这种渲染模式。因此,很容易分离这三个通道,只看到其中的一条线。在代码中,这将通过使用wb_camera_image_get_red(...), wb_camera_image_get_green(...)和wb_camera_image_get_blue(...)函数来完成,这些函数来自webots/camera.h库。
[Q.1] 根据当前的机器人控制器,e-puck 跟踪的是黄色线。您需要在控制器代码中更改什么才能跟踪蓝色线?
[Q.2]find_middle(...)函数的作用是什么?(注意:与 BotStudio 中使用的find_middle(...)函数相同)
[Q.4] 解释宏变量TIME_STEP和TIME_STEP_CAM.
[P.1] 在您的真实 e-puck 上尝试此机器人控制器。要创建真实环境,请使用一张大纸,并用荧光笔在上面描绘线条。(提示:结果很大程度上取决于您房间的光线)
打开另一个世界文件
[edit | edit source]打开以下世界文件
.../worlds/novice_camera.wbt
这将打开一块黑色的木板,上面有一个白色的球。要移动球,请使用箭头键。通过按 M 键,此球也可以随机移动。
跟踪白色物体 - 更改相机分辨率
[edit | edit source]本节的其余部分将教您如何配置 e-puck 相机。事实上,根据您的目标,您不需要使用相同的分辨率。您必须根据您的问题将分辨率降至最低。从 e-puck 传输图像到 Webots 需要时间。图像越大,传输时间越长。e-puck 的相机分辨率为 480x640 像素。但是蓝牙连接仅支持传输 2028 个彩色像素。因此,52x39 像素的分辨率可以最大限度地利用蓝牙连接并保持 4:3 的比例。
带有 e-puck 视野的图显示了 e-puck 相机的物理参数在哪里。它们对应于以下值:
- a:约 6 厘米
- b:约 4.5 厘米
- c:约 5.5 厘米
- :约 0.47 弧度
- :约 0.7 弧度
在文本编辑器窗口中,打开 world 文件。
.../worlds/novice_camera.wbt
这将打开本练习世界的解密。在文件末尾,您将找到以下节点:
EPuck { translation -0.03 0 0.7 rotation 0 1 0 0 controller "curriculum_novice_camera" camera_fieldOfView 0.7 camera_width 52 camera_height 39 }
这部分定义了虚拟的 e-puck。e-puck 的原型[4]存储在外部文件中(参见 Webots 模拟的结构)。只有一部分字段可以修改。特别是,e-puck 的位置、方向和机器人控制器将是什么。您还将在那里找到相机的属性。首先,您可以修改视野。此字段接受大于 0 且不超过 0.7 的值,因为这是您真实 e-puck 相机的范围。此字段还将定义真实 e-puck 相机的缩放属性。其次,您还可以修改虚拟相机的宽度和高度。您可以将它们设置为 1 到 127 之间的任何值。但它们的乘积不能超过 2028。当 world 文件修改完成后,保存 world 文件并恢复模拟。
当前版本的 e-puck 固件[5]只允许获得居中的图像。为了获得真实相机最后一行以模拟线性相机,需要一个技巧。如果虚拟 e-puck 相机倾斜且高度为 1,Webots 会调用 e-puck 固件的另一个例程来获取最后一行。因此,如果您想使用线性相机,您必须使用另一个虚拟相机倾斜的 e-puck 原型。
epuck_linear_camera { translation -0.03 0 0.7 rotation 0 1 0 0 controller "curriculum_novice_camera" camera_fieldOfView 0.7 camera_width 60 }
请注意,相机的 height 未定义。此字段隐式设置为 1。
该表比较了 world 文件的值与真实 e-puck 相机产生的值。请注意,视野(β)会影响缩放属性。缩放值为 8 表示欠采样(每 8 个像素取一个像素)。X 和 Y 显示真实相机窗口的相对位置(参见图 [fig:utilisation-camera])。
宽度(模拟) | 高度(模拟) | 角度[6] | 宽度 | 高度 | 缩放 | x | y | |
---|---|---|---|---|---|---|---|---|
52 | 39 | 0.7 | false | 416 | 312 | 8 | 32 | 164 |
39 | 52 | 0.7 | false | 468 | 624 | 12 | 6 | 8 |
52 | 39 | 0.08 | false | 52 | 39 | 1 | 214 | 300 |
39 | 52 | 0.08 | false | 39 | 52 | 1 | 222 | 294 |
120 | 1 | 0.7 | true | 480 | 1 | 4 | 0 | 639 |
60 | 1 | 0.7 | true | 480 | 1 | 8 | 0 | 639 |
40 | 1 | 0.35 | false | 240 | 1 | 6 | 120 | 320 |
[P.3] 尝试表格中的每种配置。观察您虚拟 e-puck 和真实 e-puck 上的结果。(提示:将表格左侧的值放到 world 文件中)
你的进度
[edit | edit source]在前五个练习中,您详细了解了 e-puck 的五个设备:LED、步进电机、红外传感器、加速度计和相机。您了解了它们的用途以及如何使用 C 编程语言使用它们。现在,您拥有了开始编程 e-puck 行为所需的所有技术知识。这是本课程其余部分的主要主题。