9、教程-3控制器的更多方面

现在我们开始讨论与机器人控制器编程相关的主题。我们将设计一个简单的控制器,以避免在前面的教程中创建的障碍。
本教程将向您介绍Webots中机器人编程的基础知识。在本章末尾,您应该了解场景树节点和控制器API之间的链接是什么,机器人控制器必须如何初始化和清理,如何初始化机器人设备,如何获取传感器值,如何命令执行器,以及如何编程简单的反馈环。
本教程仅介绍Webots函数的正确用法。机器人算法的研究超出了本教程的目标,因此此处不再赘述。处理本章需要一些基本的编程知识(任何C教程都应该是足够的介绍)。在本章的最后,给出了进一步的机器人算法的链接。

将之前的.wbt文件保存为新的文件epuck_avoid_collision.wbt

理解e-puck 模型

控制器编程需要一些与电子吸盘模型相关的信息。为了创建防撞算法,我们需要读取其炮塔周围的8个红外距离传感器的值,并启动其两轮。距离传感器分布在转台周围的方式和电子吸盘方向如图所示。
距离传感器由机器人层次结构中的8个DistanceSensor节点建模。这些节点由它们的名称字段(从ps0到ps7)引用。我们稍后将解释如何定义这些节点。现在,只需注意,可以通过Webots API的相关模块(通过Webots/distance_sensor.h包含文件)访问DistanceSensor节点。距离传感器返回的值在0和4096之间按比例缩放(与距离分段线性)。4096表示测量到大量的光(障碍物很近),0表示没有测量到光(没有障碍物)。
控制器API是一个编程接口,可以让您访问机器人的模拟传感器和执行器。例如,包含webots/distance_sensor.h文件允许使用wb_dinstance_sensor_*函数,并且使用这些函数可以查询DistanceSensor节点的值。有关API函数的文档可以在参考手册中找到,并附带每个节点的说明。

 编程一个控制器

我们想编程一个非常简单的防撞行为。您将对机器人进行编程,使其向前移动,直到前方距离传感器检测到障碍物,然后转向无障碍方向。为了做到这一点,我们将使用图中UML状态机中描述的简单反馈循环。
该控制器的完整代码将在下一小节中给出。

在控制器文件的开头,添加与Robot、DistanceSensor和Motor节点相对应的include指令,以便能够使用相应的API:

#include <webots/robot.h>
#include <webots/distance_sensor.h>
#include <webots/motor.h>

在include语句之后添加一个宏,定义每个物理步骤的持续时间。此宏将用作wb_robot_step函数的参数,也将用于启用设备。此持续时间以毫秒为单位指定,并且必须是WorldInfo节点的basicTimeStep字段中值的倍数。

#define TIME_STEP 64

主要功能是控制器程序开始执行的地方。传递给主函数的参数由Robot节点的controllerArgs字段给定。Webots API必须使用wb_robot_init函数进行初始化,并且必须使用wp_robot_cleanup函数进行清理。

编写主要功能的原型如下:

// entry point of the controller
int main(int argc, char **argv) {
  // initialize the Webots API
  wb_robot_init();
  // initialize devices
  // feedback loop: step simulation until receiving an exit event
  while (wb_robot_step(TIME_STEP) != -1) {
    // read sensors outputs
    // process behavior
    // write actuators inputs
  }
  // cleanup the Webots API
  wb_robot_cleanup();
  return 0; //EXIT_SUCCESS
}

机器人设备由WbDeviceTag引用。WbDeviceTag由wb_robot_get_device函数检索。然后,它被用作与该设备有关的每个函数调用的第一个参数。使用前必须启用DistanceSensor等传感器。启用函数的第二个参数定义了刷新传感器的速率。

注释//初始化设备后,按如下方式获取并启用距离传感器:

// initialize devices
int i;
WbDeviceTag ps[8];
char ps_names[8][4] = {
  "ps0", "ps1", "ps2", "ps3",
  "ps4", "ps5", "ps6", "ps7"
};

for (i = 0; i < 8; i++) {
  ps[i] = wb_robot_get_device(ps_names[i]);
  wb_distance_sensor_enable(ps[i], TIME_STEP);
}

设备初始化后,对电机进行初始化:

WbDeviceTag left_motor = wb_robot_get_device("left wheel motor");
WbDeviceTag right_motor = wb_robot_get_device("right wheel motor");
wb_motor_set_position(left_motor, INFINITY);
wb_motor_set_position(right_motor, INFINITY);
wb_motor_set_velocity(left_motor, 0.0);
wb_motor_set_velocity(right_motor, 0.0);

在主循环中,就在注释//读取传感器输出之后,读取距离传感器值,如下所示

// read sensors outputs
double ps_values[8];
for (i = 0; i < 8 ; i++)
  ps_values[i] = wb_distance_sensor_get_value(ps[i]);

在主循环中,就在注释//处理行为之后,检测是否发生碰撞(即,距离传感器返回的值大于阈值),如下所示:

// detect obstacles
bool right_obstacle =
  ps_values[0] > 80.0 ||
  ps_values[1] > 80.0 ||
  ps_values[2] > 80.0;
bool left_obstacle =
  ps_values[5] > 80.0 ||
  ps_values[6] > 80.0 ||
  ps_values[7] > 80.0;

最后,使用有关障碍物的信息按如下方式启动车轮:

#define MAX_SPEED 6.28
...
// initialize motor speeds at 50% of MAX_SPEED.
double left_speed  = 0.5 * MAX_SPEED;
double right_speed = 0.5 * MAX_SPEED;
// modify speeds according to obstacles
if (left_obstacle) {
  // turn right
  left_speed  = 0.5 * MAX_SPEED;
  right_speed = -0.5 * MAX_SPEED;
}
else if (right_obstacle) {
  // turn left
  left_speed  = -0.5 * MAX_SPEED;
  right_speed = 0.5 * MAX_SPEED;
}
// write actuators inputs
wb_motor_set_velocity(left_motor, left_speed);
wb_motor_set_velocity(right_motor, right_speed);

通过选择Build/Build菜单项编译代码。编译错误在控制台中显示为红色。如果有,请修复它们,然后重试编译。重新加载世界。

完整代码如下:

#include <webots/robot.h>
#include <webots/distance_sensor.h>
#include <webots/motor.h>

// time in [ms] of a simulation step
#define TIME_STEP 64

#define MAX_SPEED 6.28

// entry point of the controller
int main(int argc, char **argv) {
  // initialize the Webots API
  wb_robot_init();

  // internal variables
  int i;
  WbDeviceTag ps[8];
  char ps_names[8][4] = {
    "ps0", "ps1", "ps2", "ps3",
    "ps4", "ps5", "ps6", "ps7"
  };

  // initialize devices
  for (i = 0; i < 8 ; i++) {
    ps[i] = wb_robot_get_device(ps_names[i]);
    wb_distance_sensor_enable(ps[i], TIME_STEP);
  }

  WbDeviceTag left_motor = wb_robot_get_device("left wheel motor");
  WbDeviceTag right_motor = wb_robot_get_device("right wheel motor");
  wb_motor_set_position(left_motor, INFINITY);
  wb_motor_set_position(right_motor, INFINITY);
  wb_motor_set_velocity(left_motor, 0.0);
  wb_motor_set_velocity(right_motor, 0.0);

  // feedback loop: step simulation until an exit event is received
  while (wb_robot_step(TIME_STEP) != -1) {
    // read sensors outputs
    double ps_values[8];
    for (i = 0; i < 8 ; i++)
      ps_values[i] = wb_distance_sensor_get_value(ps[i]);

    // detect obstacles
    bool right_obstacle =
      ps_values[0] > 80.0 ||
      ps_values[1] > 80.0 ||
      ps_values[2] > 80.0;
    bool left_obstacle =
      ps_values[5] > 80.0 ||
      ps_values[6] > 80.0 ||
      ps_values[7] > 80.0;

    // initialize motor speeds at 50% of MAX_SPEED.
    double left_speed  = 0.5 * MAX_SPEED;
    double right_speed = 0.5 * MAX_SPEED;

    // modify speeds according to obstacles
    if (left_obstacle) {
      // turn right
      left_speed  = 0.5 * MAX_SPEED;
      right_speed = -0.5 * MAX_SPEED;
    }
    else if (right_obstacle) {
      // turn left
      left_speed  = -0.5 * MAX_SPEED;
      right_speed = 0.5 * MAX_SPEED;
    }

    // write actuators inputs
    wb_motor_set_velocity(left_motor, left_speed);
    wb_motor_set_velocity(right_motor, right_speed);
  }

  // cleanup the Webots API
  wb_robot_cleanup();
  return 0; //EXIT_SUCCESS
}

 

posted on 2023-07-27 18:50  gary_123  阅读(25)  评论(0编辑  收藏  举报

导航