本文章最早发布于我的个人博客
http://120.76.72.211/archives/webots-fang-zhen-ru-men–zai-ji-qi-ren-zhong-tian-jia-chuan-gan-qi-bing-kong-zhi-ta
如需转载,请联系
如有侵权,请联系我
上一篇中,我们在 Webots 中创建了一个两轮的差速控制机器人,并且写了一段简单的控制程序让机器人动了起来。
在这一篇中,我们将继续完善我们的机器人,我们将在机器人上安装传感器,并用 C 语言实现传感器的使用。
那就开始吧。
我们上一篇的机器人搭建里已经创建了一个控制器了,可以直接在这个控制器的基础上继续修改。
Robot"robot"
;编辑控制器
;你也可以重新建一个新的控制器。
点击菜单栏的 向导
,选择 新机器人控制器
,记得创建的是 C 语言的控制器。
我们把距离传感器安装到机器人的眼睛上,左右各一个。
Robot"robot"
;children
;DEF Eye_Right Solid
;children
;Base node
s,选择 DistanceSensor
,添加;右眼
的子节点下面,就会有一个 DistanceSensor
的节点。但是这时候机器人上什么变化也没有;查看
,在可选显示里勾选 显示距离传感器射线
;在下图中箭头所指的白色射线就是距离传感器的射线,只不过我现在的距离传感器的射线方向有点奇怪;name
,修改成你喜欢的名字。我这里修改成 distance_sensor_right,一会控制的时候是要用到这个名字的。rotation
,在 angle
里输入 1.57
(PI/2),使其绕着 Z 轴逆时针旋转90°;距离传感器控制的思路如下:
1.获取距离传感器的设备句柄,通过 name;
2.使能距离传感器的控制;
3.获取距离传感器的值;
代码控制如下:
/*
* File: my_controller.c
* Date:
* Description:
* Author:
* Modifications:
*/
/*
* You may need to add include files like or
* , etc.
*/
#include
#include //头文件要添加
#include
/*
* You may want to add macros here.
*/
#define TIME_STEP 64
#define MAX_SPEED (6.28f)
/*
* This is the main program.
* The arguments of the main function can be specified by the
* "controllerArgs" field of the Robot node
*/
int main(int argc, char **argv) {
/* necessary to initialize webots stuff */
wb_robot_init();
/*
* You should declare here WbDeviceTag variables for storing
* robot devices like this:
* WbDeviceTag my_sensor = wb_robot_get_device("my_sensor");
* WbDeviceTag my_actuator = wb_robot_get_device("my_actuator");
*/
//Initial motor
WbDeviceTag left_motor = wb_robot_get_device("motor_2");
WbDeviceTag right_motor = wb_robot_get_device("motor_1");
wb_motor_set_position(left_motor, INFINITY);
wb_motor_set_position(right_motor, INFINITY);
wb_motor_set_velocity(left_motor, 0.0f);
wb_motor_set_velocity(right_motor, 0.0f);
// 获取控制句柄
WbDeviceTag left_dis_sensor = wb_robot_get_device("distance_sensor_left");
WbDeviceTag right_dis_sensor = wb_robot_get_device("distance_sensor_right");
// 使能控制
wb_distance_sensor_enable(left_dis_sensor, TIME_STEP);
wb_distance_sensor_enable(right_dis_sensor, TIME_STEP);
/* main loop
* Perform simulation steps of TIME_STEP milliseconds
* and leave the loop when the simulation is over
*/
while (wb_robot_step(TIME_STEP) != -1) {
/*
* Read the sensors :
* Enter here functions to read sensor data, like:
* double val = wb_distance_sensor_get_value(my_sensor);
*/
// 获取传感器的值
float dis_left_val = wb_distance_sensor_get_value(left_dis_sensor);
float dis_right_val = wb_distance_sensor_get_value(right_dis_sensor);
printf("distance: %.03f, %.03f\r\n", dis_left_val, dis_right_val);
/* Process sensor data here */
/*
* Enter here functions to send actuator commands, like:
* wb_motor_set_position(my_actuator, 10.0);
*/
wb_motor_set_velocity(left_motor, MAX_SPEED); // rad/s
wb_motor_set_velocity(right_motor, MAX_SPEED); // rad/s
};
/* Enter your cleanup code here */
/* This is necessary to cleanup webots resources */
wb_robot_cleanup();
return 0;
}
编译完成后仿真,在控制台就可以看到打印的距离值。
如果你的窗口上没有控制台,点击菜单栏中的 工具
,选择 New Console
创建一个新的控制台。
我们可以通过电机编码器计算当前机器人的车轮转速,进而计算出机器人当前的前进速度。
device
节点;PositionSensor
;编码器的控制思路如下:
1.获取传感器的设备句柄,通过 name;
2.使能传感器的控制;
3.获取传感器的值;
代码实现如下:
/*
* File: my_controller.c
* Date:
* Description:
* Author:
* Modifications:
*/
/*
* You may need to add include files like or
* , etc.
*/
#include
#include
#include
#include
/*
* You may want to add macros here.
*/
#define TIME_STEP 64
#define MAX_SPEED (6.28f)
#define WHEEL_RADIUS (0.025f)
#define MATH_PI (3.141593f)
/*
* This is the main program.
* The arguments of the main function can be specified by the
* "controllerArgs" field of the Robot node
*/
int main(int argc, char **argv) {
/* necessary to initialize webots stuff */
wb_robot_init();
/*
* You should declare here WbDeviceTag variables for storing
* robot devices like this:
* WbDeviceTag my_sensor = wb_robot_get_device("my_sensor");
* WbDeviceTag my_actuator = wb_robot_get_device("my_actuator");
*/
//Initial motor
WbDeviceTag left_motor = wb_robot_get_device("motor_left");
WbDeviceTag right_motor = wb_robot_get_device("motor_right");
wb_motor_set_position(left_motor, INFINITY);
wb_motor_set_position(right_motor, INFINITY);
wb_motor_set_velocity(left_motor, 0.0f);
wb_motor_set_velocity(right_motor, 0.0f);
WbDeviceTag left_pos = wb_robot_get_device("position_sensor_left");
WbDeviceTag right_pos = wb_robot_get_device("position_sensor_right");
wb_position_sensor_enable(left_pos, TIME_STEP);
wb_position_sensor_enable(right_pos, TIME_STEP);
float wheel_cirum = 2 * MATH_PI * WHEEL_RADIUS;
float encoder_unit = wheel_cirum / (2 * MATH_PI);
float last_left_pos_val = 0.0f;
float last_right_pos_val = 0.0f;
/* main loop
* Perform simulation steps of TIME_STEP milliseconds
* and leave the loop when the simulation is over
*/
while (wb_robot_step(TIME_STEP) != -1) {
/*
* Read the sensors :
* Enter here functions to read sensor data, like:
* double val = wb_distance_sensor_get_value(my_sensor);
*/
float left_pos_val = wb_position_sensor_get_value(left_pos);
float right_pos_val = wb_position_sensor_get_value(right_pos);
/* Process sensor data here */
/*
* Enter here functions to send actuator commands, like:
* wb_motor_set_position(my_actuator, 10.0);
*/
wb_motor_set_velocity(left_motor, MAX_SPEED); // rad/s
wb_motor_set_velocity(right_motor, MAX_SPEED); // rad/s
float left_diff = left_pos_val - last_left_pos_val;
float right_diff = right_pos_val - last_right_pos_val;
printf("left_diff = %f, right_diff = %f\r\n", left_diff, right_diff);
if (left_diff < 0.0001)
{
left_diff = 0.0f;
left_pos_val = last_left_pos_val;
}
if (right_diff < 0.0001)
{
right_diff = 0.0f;
right_pos_val = last_right_pos_val;
}
float left_speed = left_diff / (float)(TIME_STEP/1000.); // rad/s
left_speed = left_speed * encoder_unit; // m/s
float right_speed = right_diff / (float)(TIME_STEP / 1000.);
right_speed = right_speed * encoder_unit;
last_left_pos_val = left_pos_val;
last_right_pos_val = right_pos_val;
printf("left speed :%f m/s, right speed:%f m/s\r\n", left_speed, right_speed);
};
/* Enter your cleanup code here */
/* This is necessary to cleanup webots resources */
wb_robot_cleanup();
return 0;
}
我们在电机控制里,给电机设置的速度 wb_motor_set_velocity(left_motor, MAX_SPEED);
,其中 MAX_SPEED
的单位是 rad/s
。
从编码器中获取到的值 wb_position_sensor_get_value(left_pos);
,其单位是 rad
,表示当前转过的弧度。
在数学关系中,车轮转过一圈的长度 2 * PI * r
,对应的弧度是 2 * PI
。
因此,我们需要计算在单位时间内,轮子转过的弧度,在匹配当前轮子的半径,就可以得出在单位时间内,车子前进的速度。
$$
\begin{align} \
车轮周长 l = 2 * PI * radius\
转动单位 unit = \frac{2 * PI * radius}{2 * PI} \
编码器弧度差 Val_d = Val_c - Val_l\
单位时间转动量 Val_s = \frac{Val_d}{TIMESTEP * 1000} \
转速 V = Val_s * unit
\end{align} \
$$
$$
$$
先在机器人的脑袋上加上一个点,给激光雷达一个支点。
简单粗暴点的方法就是复制一个眼睛的节点,修改名称,删除距离传感器,然后修改参数即可。
修改后的坐标参数如下:
x = 0
y = 0
z = 0.08
新增
;Base nodes
,选择 Lidar
,添加;Lidar"lidar"
的新节点;Show Lidar Ray Paths
和 Show Lidar Point Cloud
;显示效果如下,但这时候还有问题,激光的朝向是错误的;Lidar"lidar"
节点,在 rotation
里设置 angle
为1.57,最终参数如下:x = 0
y = 0
z = 1
angle = 1.57
numberOfLayers
为 1;控制思路如下:
1.获取激光雷达的设备句柄,通过 name;
2.使能激光雷达;
3.使能激光雷达点云;
4.获取激光雷达队列指针;
5.通过索引获取相应点的值;
代码实现如下:
/*
* File: my_controller.c
* Date:
* Description:
* Author:
* Modifications:
*/
/*
* You may need to add include files like or
* , etc.
*/
#include
#include
#include
#include
/*
* You may want to add macros here.
*/
#define TIME_STEP 64
#define MAX_SPEED (6.28f)
#define WHEEL_RADIUS (0.025f)
#define MATH_PI (3.141593f)
/*
* This is the main program.
* The arguments of the main function can be specified by the
* "controllerArgs" field of the Robot node
*/
int main(int argc, char **argv) {
/* necessary to initialize webots stuff */
wb_robot_init();
/*
* You should declare here WbDeviceTag variables for storing
* robot devices like this:
* WbDeviceTag my_sensor = wb_robot_get_device("my_sensor");
* WbDeviceTag my_actuator = wb_robot_get_device("my_actuator");
*/
//Initial motor
WbDeviceTag left_motor = wb_robot_get_device("motor_left");
WbDeviceTag right_motor = wb_robot_get_device("motor_right");
wb_motor_set_position(left_motor, INFINITY);
wb_motor_set_position(right_motor, INFINITY);
wb_motor_set_velocity(left_motor, 0.0f);
wb_motor_set_velocity(right_motor, 0.0f);
WbDeviceTag lidar = wb_robot_get_device("lidar");
wb_lidar_enable(lidar, TIME_STEP);
wb_lidar_enable_point_cloud(lidar);
/* main loop
* Perform simulation steps of TIME_STEP milliseconds
* and leave the loop when the simulation is over
*/
while (wb_robot_step(TIME_STEP) != -1) {
/*
* Read the sensors :
* Enter here functions to read sensor data, like:
* double val = wb_distance_sensor_get_value(my_sensor);
*/
// 小车前进的左边为队列起点
const float *lidar_array = wb_lidar_get_range_image(lidar);
printf("lidar distance degree 90:%f\r\n", lidar_array[90]); // 90°位置的距离值
};
/* Enter your cleanup code here */
/* This is necessary to cleanup webots resources */
wb_robot_cleanup();
return 0;
}
显示效果如下图,蓝色的线和点是激光的点云。
[Webots官方传感器文档](Webots: (cyberbotics.com))
[Webots控制器节点和API函数文档](Webots: (cyberbotics.com))
Webots Github仓库
本地有关于传感器使用介绍的文档
C:\Program Files\Webots\docs\reference
阅读原文