一、忠告

ubuntu版本:20.04
ros版本:noetic
webots版本:webots_2021a_amd64.deb
所有版本严格按照教程的来,如版本不一样, 报错自己解决。
———————————————————————————————————————————

二、下载webots

当然最推荐的还是去官网下载,只不过会有点慢,下面给出百度网盘链接,需要的自取。
链接: https://pan.baidu.com/s/19wk2C7DhH5SqCT63Tftj1A?pwd=6666 提取码: 6666
所含版本如下:(本教程使用webots_2021a_amd64.deb)
下载完成后进入目标文件夹运行以下命令进行安装:

sudo dpkg -i webots_2020b-rev1_amd64.deb

———————————————————————————————————————————

三、下载安装webots_ros

  1. 安装相应版本的webots_ros(melodic的就把下面代码的noetic改成melodic,如此类推)
    运行以下命令:
sudo apt install ros-noetic-webots-ros
  1. 主目录下新建一个工作空间
mkdir catkin_webots
cd catkin_webots
mkdir src
  1. 进入/usr/local/webots/projects/languages/ros/文件夹下将webots_ros整个文件夹复制到catkin_webots/src下面。
    如果没找到webots_ros,从github下载下来,同样也是放到catkin_webots/src下面。
    下载地址:https://github.com/cyberbotics/webots_ros/

  2. 进入/usr/local/webots/projects/default/controllers/ros/include/文件夹下面的srv和msg文件夹复制到刚刚放在catkin_webots工作空间下的webots_ros功能包内,最终webots_ros文件夹内容如下:

  3. 配置环境变量
    打开bashrc文件

sudo gedit ~/.bashrc

在文件最后添加export WEBOTS_HOME=/usr/local/webots/
上述方法似乎不管用所以我们直接在命令行里输入

export WEBOTS_HOME=/usr/local/webots/
  1. 编译
cd catkin_webots
catkin_make
  1. ros运行webots
    编译成功后接着输入以下代码
source devel/setup.bash
roslaunch webots_ros pioneer3at.launch

如果你成功打开了webots并且控制器显示如下,恭喜你webots和ros已经成功连接了。
———————————————————————————————————————————

四、下载安装Cartographer

参考链接: https://blog.csdn.net/jianyoutianxia99/article/details/120901805?spm=1001.2014.3001.5506

  1. 前提

    1. ros安装成功
    2. rosdep update成功
      命令行输入下面指令不报错即为成功
rosdep update
  1. 安装依赖
sudo apt-get update
sudo apt-get install -y \clang \cmake \g++ \git \google-mock \libboost-all-dev \libcairo2-dev \libceres-dev \protobuf-compiler\ros-neotic-tf2-eigen\liblapack-dev\libatlas-base-dev\libprotobuf-dev\libwebp-dev\libcurl4-openssl-dev \libeigen3-dev \libgflags-dev \libgoogle-glog-dev \liblua5.2-dev \libsuitesparse-dev \lsb-release \ninja-build \python3-sphinx \python-wstool\python-rosdep\stow
  1. 初始化工作空间
mkdir catkin_cg
cd catkin_cg
wstool init src
  1. 下载安装cartographer和cartographer_ros
cd catkin_cg/src
git clone https://gitee.com/liu_xiao_eu/cartographer.git
git clone https://gitee.com/liu_xiao_eu/cartographer_ros.git
  1. 在src文件夹下,获取ceres-solver源码
wget ceres-solver.org/ceres-solver-1.13.0.tar.gz #在文件夹中进行解压后再进行下一步
cd ~/catkin_cg/src/ceres-solver-1.13.0
mkdir build
cd build
cmake ..
make

然后测试一下是否通过

make test
sudo make install
  1. 安装cartographer_ros的依赖项(proto3)
    为了提高下载速度,以免超时,先做如下操作:
    通过该路径找到并编辑install_proto3.sh文件src/cartographer/scripts/install_proto3.sh
    更改为如下下载地址:
cd catkin_cg
src/cartographer/scripts/install_proto3.sh
  1. 安装 abseil-cpp library
cd catkin_cg
src/cartographer/scripts/install_abseil.sh
  1. 编译Cartographer
catkin_make_isolated --install --use-ninja   #比较慢需要等几分钟
  1. 下载官方测试数据
    下载地址: https://storage.googleapis.com/cartographer-public-data/bags/backpack_2d/cartographer_paper_deutsches_museum.bag
  2. 运行官方demo
cd catkin_cg
catkin_make_isolated --install --use-ninja
source install_isolated/setup.bash
roslaunch cartographer_ros demo_backpack_2d.launch bag_filenames:=${HOME}/Downloads/cartographer_paper_deutsches_museum.bag

如果你成功打开了rviz且建图如上,恭喜你,成功安装Cartographer!
———————————————————————————————————————————

五、搭建webots机器人基础教程

当你看到这里,你得保证前面的步骤都没有问题,也就是webots和ros连接以及Cartographer成功安装。接下来讲解webots搭建机器人的基本操作,如果你已经有相关经验,并且拥有自己的机器人模型,可以选择跳过这一步。
参考链接: https://blog.csdn.net/xiaokai1999/article/details/112545173

1. 创建一个新世界

  1. 打开webots,文件->新世界
  2. 然后向场景树添加以下三个节点
  3. 操作完场景树如下图所示,并且我们可以更改地板大小为5m*5m。

2.搭建机器人模型

  1. 添加Robot节点
  2. 从左侧场景树Robot->children添加节点Base_nodes->Shape
  3. 通过Robot->children->Shape定义DEF为body

  4. Robot->children->Shape->appearance NULL添加Base_nodes->Appearance
    Robot->children->Shape->geometry NULL添加Base_nodes->Box
    appearance Apearance->material添加Base_nodes->Material
    通过更改diffuseColor可以改变模型颜色;通过改变geometry Box->size可以改变模型大小。

  1. 添加碰撞体积和物理属性
    Robot->boundingObject NULL添加之前定义的body节点USE->body
    Robot->physics NULL添加节点Base_nodes->Physics

  2. 创建轮子

    1. Robot->children添加Base_nodes->HingeJoint定义DEF->left_wheel
    2. HingeJoint->jointParameters添加 HingeJointParameters
    3. HingeJoint->device添加Rotatioal Motor,Rotatioal Motor->name改为left_motor
    4. HingeJoint->endPoint添加Base_nodes->soild
    5. 接着从soild->children节点下创建一个shape节点,在shape节点下设置轮子的形状为Cylinder
    6. 点击查看–>可选显示–>show joint Axes或者同时按下ctrl+F5,可以显示出旋转轴,方便我们调整旋转轴及旋转原点。
    7. 通过调整translationrotation,将轮子设置到合适的位置,轮子半径为0.15则需将Robot的位置抬高0.15。
    8. 最后,在HingeJoint->endPoint节点下给轮子增加碰撞属性boundingObject及重力属性physics
    9. 右轮同理。



  1. 增加支撑导轮

    1. Robot->children下创建一个Base_nodes->HingeJoint节点。
    2. 向上面的教程一样创建jointParameters节点和endpoint节点,导轮不需要电机驱动则无需管device节点。
    3. 导轮的形状是圆球,因此在shape节点下设置导轮的形状为Sphere
    4. 调整导轮到合适位置,并设置好旋转中心。
    5. 同理完成前后两个导轮。


3.保存地图

将地图保存在路径catkin_webots/src/webots_ros/worlds
———————————————————————————————————————————

六、向已建好的机器人模型添加激光雷达

在这一步,你可以使用webots自带节点的雷达,
如在Robot->children添加PROTO nodes—>devices->sick->SickLms291(lidar)Sick_LMS_291,
也可以像我接下来教的一样创建一个可以调整参数的自定义激光雷达。

  1. Robot->children添加Base_nodes->Lidar定义DEF为lidar。

  2. Lidar->children添加Shape并在geometry节点选择形状Cylinder

  3. 调整雷达位置和大小。

  4. 修改雷达参数
    我们使用单线激光雷达,将Lidar->numberOfLayers改为1;将Lidar->type改为rotating

    点击查看–>可选显示–>Show Lidar Ray Paths或者同时按下ctrl+F7,可以显示出雷达扫描的范围。

    ————————————————————————————————————————————————————

七、测试激光雷达与ROS的通信

1.webots与ros连接

  1. 进入catkin_webots/src/webots_ros/launch目录下新建一个demo.launch文件,写入下列代码,用来启动你自己的机器人模型。
<?xml version="1.0"?>
<launch><!-- start Webots --><arg name="no-gui" default="false," doc="Start Webots with minimal GUI"/><include file="$(find webots_ros)/launch/webots.launch"><arg name="mode" value="realtime"/><arg name="no-gui" value="$(arg no-gui)"/><arg name="world" value="$(find webots_ros)/worlds/demo.wbt"/></include>
</launch>
  1. 运行以下代码启动webots:
cd catkin_webots
catkin_make
source devel/setup.bash
roslaunch webots_ros demo.launch
  1. Robot->controller改为ros

    此时webots与ros就连接成功了。
  2. 为了今后操作方便我们将该机器人的名字改一下
    Robot->controllerArgs添加--name=robot

    保存并重新加载运行世界,会发现我们机器人的名字已经更改。

2.查看激光雷达发布的话题

  1. 运行webots世界,打开一个新的终端,输入下列命令,
    可以看到webots发布了一系列服务,并且含有我们激光雷达的服务。
rosservice list

  1. 使能激光雷达
rosservice call /robot/my_Lidar/enable "value : 1"success: True    #证明激光雷达已经开启了

通过下面这个命令可以看到激光雷达已经发布了两个主题。

rostopic list

  1. 我们用rviz来验证一下
rviz

把Fixed Frame改为robot/my_Lidar;把LaserScan的Topic改为/robot/my_Lidar/laser_scan/layer0
即可看到激光雷达已经检测出障碍物了。

——————————————————————————————————————————————————————

八、webots使用Cartographer建图

  1. Cartographer建图简介
    首先我们要了解Cartographer建图的流程哈,它只需配置两个文件,一个是.launch文件,一个是.lua文件。
    下面我们来仔细看看这两个文件。

    1. luanch文件
      参考链接: https://blog.csdn.net/weixin_42156097/article/details/112471167
      Cartographer的luanch文件在路径catkin_cg/src/cartographer_ros/cartographer_ros/launch下,2d建图一般使用demo_revo_lds.launch作为模板去更改为符合我们机器人的launch文件。可以新建一个launch文件将其代码粘贴过来进行修改。
      其代码内容如下:
    2. lua文件
      我们在catkin_cg/src/cartographer_ros/cartographer_ros/configuration_files下找到与luanch文件对应的revo_lds.lua文件,同样供我们另存修改。
      其代码内容如下:
      做完这两件事之后记得编译一下
cd catkin_cg
catkin_make_isolated --install --use-ninja
  1. 启动webots节点,并配置tf树
    我们在自己的工作空间下catkin_webots/src/webots_ros/src新建一个broadcaster.cpp文件用来启动我们的激光雷达、GPS和IMU等节点,并进行tf的连接。
    详细操作请看参考链接: https://blog.csdn.net/xiaokai1999/article/details/112596613
    broadcaster.cpp的代码如下:
#include <signal.h>
#include <std_msgs/String.h>
#include "ros/ros.h"
#include <sensor_msgs/LaserScan.h>
#include <sensor_msgs/NavSatFix.h>
#include <sensor_msgs/Imu.h>
#include <tf/transform_broadcaster.h>
#include <webots_ros/set_float.h>
#include <webots_ros/set_int.h>
#include <webots_ros/Int32Stamped.h>
#include <rosgraph_msgs/Clock.h>using namespace std;
#define TIME_STEP 32    //时钟
#define NMOTORS 2       //电机数量
#define MAX_SPEED 2.0   //电机最大速度ros::NodeHandle *n;static int controllerCount;
static vector<string> controllerList; ros::ServiceClient timeStepClient;          //时钟通讯客户端
webots_ros::set_int timeStepSrv;            //时钟服务数据void controllerNameCallback(const std_msgs::String::ConstPtr &name) { controllerCount++; controllerList.push_back(name->data);//将控制器名加入到列表中ROS_INFO("Controller #%d: %s.", controllerCount, controllerList.back().c_str());
}void quit(int sig) {ROS_INFO("User stopped the '/robot' node.");timeStepSrv.request.value = 0; timeStepClient.call(timeStepSrv); ros::shutdown();exit(0);
}//tf坐标转换
void broadcastTransform()
{static tf::TransformBroadcaster br;tf::Transform transform;transform.setOrigin(tf::Vector3(-GPSvalues[2],GPSvalues[0],GPSvalues[1]));// 设置原点tf::Quaternion q(Inertialvalues[0],Inertialvalues[1],Inertialvalues[2],Inertialvalues[3]);// 四元数 ->欧拉角q = q.inverse();// 反转四元数transform.setRotation(q); //设置旋转数据br.sendTransform(tf::StampedTransform(transform,ros::Time::now(),"odom","base_link"));// 发送tf坐标关系transform.setIdentity();br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "base_link", "/robot/Sick_LMS_291"));
}//gps回调函数
void gpsCallback(const sensor_msgs::NavSatFix::ConstPtr &values)
{GPSvalues[0] = values->latitude;// 纬度GPSvalues[1] = values->altitude;// 海拔高度GPSvalues[2] = values->longitude;// 经度broadcastTransform(); // tf坐标转换
}
//IMU回调函数
void inertial_unitCallback(const sensor_msgs::Imu::ConstPtr &values)
{Inertialvalues[0] = values->orientation.x; Inertialvalues[1] = values->orientation.y;Inertialvalues[2] = values->orientation.z;Inertialvalues[3] = values->orientation.w;broadcastTransform(); // tf坐标转换
}int main(int argc, char **argv) {setlocale(LC_ALL, ""); // 用于显示中文字符string controllerName;// 在ROS网络中创建一个名为robot_init的节点ros::init(argc, argv, "robot_init", ros::init_options::AnonymousName);n = new ros::NodeHandle;// 截取退出信号signal(SIGINT, quit);//订阅gps服务    ros::ServiceClient gps_Client;          webots_ros::set_int gps_Srv;            ros::Subscriber gps_sub;gps_Client = n->serviceClient<webots_ros::set_int>("/robot/gps/enable"); // 使能GPS服务gps_Srv.request.value = TIME_STEP;// 判断gps使能服务是否成功if (gps_Client.call(gps_Srv) && gps_Srv.response.success) {ROS_INFO("gps enabled.");// 订阅gps话题,获取数据gps_sub = n->subscribe("/robot/gps/values", 1, gpsCallback);ROS_INFO("Topic for gps initialized.");while (gps_sub.getNumPublishers() == 0) {}ROS_INFO("Topic for gps connected.");} else {if (!gps_Srv.response.success)ROS_ERROR("Failed to enable gps.");return 1;}//订阅IMU服务ros::ServiceClient inertial_unit_Client;          webots_ros::set_int inertial_unit_Srv;            ros::Subscriber inertial_unit_sub;inertial_unit_Client = n->serviceClient<webots_ros::set_int>("/robot/inertial_unit/enable"); //订阅IMU使能服务inertial_unit_Srv.request.value = TIME_STEP;// 判断是否使能成功if (inertial_unit_Client.call(inertial_unit_Srv) && inertial_unit_Srv.response.success) {ROS_INFO("inertial_unit enabled.");// 获取话题数据inertial_unit_sub = n->subscribe("/robot/inertial_unit/roll_pitch_yaw", 1, inertial_unitCallback);ROS_INFO("Topic for inertial_unit initialized.");while (inertial_unit_sub.getNumPublishers() == 0) {}ROS_INFO("Topic for inertial_unit connected.");} else {if (!inertial_unit_Srv.response.success)ROS_ERROR("Failed to enable inertial_unit.");return 1;}//使能激光雷达ros::ServiceClient lidar_Client;          webots_ros::set_int lidar_Srv;            lidar_Client = n->serviceClient<webots_ros::set_int>("/robot/Sick_LMS_291/enable"); // 订阅lidar使能服务lidar_Srv.request.value = TIME_STEP;//判断是否使能成功if (lidar_Client.call(lidar_Srv) && lidar_Srv.response.success) {ROS_INFO("gps enabled.");} else {if (!lidar_Srv.response.success)ROS_ERROR("Failed to enable lidar.");return 1;}// 订阅webots中所有可用的model_nameros::Subscriber nameSub = n->subscribe("model_name", 100, controllerNameCallback);while (controllerCount == 0 || controllerCount < nameSub.getNumPublishers()) {ros::spinOnce();}ros::spinOnce();// 服务订阅time_step和webots保持同步timeStepClient = n->serviceClient<webots_ros::set_int>("robot/robot/time_step");timeStepSrv.request.value = TIME_STEP;// 如果在webots中有多个控制器的话,需要让用户选择一个控制器if (controllerCount == 1)controllerName = controllerList[0];else {int wantedController = 0;cout << "Choose the # of the controller you want to use:\n";cin >> wantedController;if (1 <= wantedController && wantedController <= controllerCount)controllerName = controllerList[wantedController - 1];else {ROS_ERROR("Invalid number for controller choice.");return 1;}}ROS_INFO("Using controller: '%s'", controllerName.c_str());// 退出主题,因为已经不重要了nameSub.shutdown();// main loopwhile (ros::ok()) {if (!timeStepClient.call(timeStepSrv) || !timeStepSrv.response.success) {ROS_ERROR("Failed to call service time_step for next step.");break;}ros::spinOnce();}timeStepSrv.request.value = 0;timeStepClient.call(timeStepSrv);ros::shutdown(); return 0;
}

将下面几行写进CMakelist.txt文件中以正常编译

find_package(catkin REQUIRED COMPONENTS ) #在这行的括号内加入tf
catkin_package() #在这行的括号内加入tfadd_executable(broadcaster src/broadcaster.cpp)
add_dependencies(broadcaster webots_ros_generate_messages_cpp)
target_link_libraries(broadcaster   ${catkin_LIBRARIES})

package.xml中需要添加如下信息

  <build_depend>tf</build_depend><build_export_depend>tf</build_export_depend><exec_depend>tf</exec_depend>
  1. webots中最后一些小改动

    1. Robot->children下添加gps及imu节点
    2. Robot->controllerArgs添加以下字段
  2. 最后启动建图
    参考链接: https://blog.csdn.net/xiaokai1999/article/details/113347110

//分别用三个终端运行以下代码
//1、启动webots
cd catkin_webots
catkin_make
source devel/setup.bash
roslaunch webots_ros demo.launch//2、启动broadcaster.cpp
cd catkin_webots
catkin_make
source devel/setup.bash
rosrun webots_ros demo//3、启动launch文件
cd catkin_cg
catkin_make_isolated --install --use-ninja
source install_isolated/setup.bash
roslaunch cartographer_ros demo.launch
  1. 结果
    很遗憾的是,笔者按照网上教程一步步走来,到这最后一步却无法实现建图。
    能成功打开rviz而且没有报错,唯一不对劲的就是遇到了一个warning

    而且tf树上莫名其妙多出了一个空的圈

    找了很久都没有找到解决的办法,甚至不知道主要问题出在哪里。
    如果你解决了,请务必联系我,万分感谢。
    ————————————————————————————————————————————————————

未完待续…
参考链接: https://blog.csdn.net/xiaokai1999/article/details/112601720

webots联合Cartographyer建图教程相关推荐

  1. ROS联合Webots实现3d建图(一)Ubuntu20.04 A_LOAM环境搭建(完美运行)

    ROS联合Webots实现3d建图(一)Ubuntu20.04 A_LOAM环境搭建(完美运行) 注意: 再学习本系列教程时,应该已经安装过ROS了并且需要有一些ROS的基本知识 ubuntu版本:2 ...

  2. voxblox建图教程

    之前一直在摸索港科大的vins + fiest做定位和建图,但是实际上由于标定等多种原因,vins mono和vins fusion定位效果都不太好,然后orbslam系列对于快速运动也经常会跑丢.最 ...

  3. ROS中gmapping建图教程

    本文对应ubuntu版本:18.04 + melodic 1.下载gmapping源码 以下两中方式二选一 git clone https://github.com/ros-perception/sl ...

  4. gmapping建图与rviz实时显示中出现的问题记录

    网上关于gmapping建图教程基本都是: 用ros的数据记录指令rosbag去记录数据,然后再通过rviz去显示记录的数据. 其实可以用rviz去实时显示构建地图的过程,但是需要去配置ROS: 首先 ...

  5. ROS 教程2 机器人雷达建图 蒙特卡洛定位 导航 路径规划 仿真

    ros 机器人雷达建图 蒙特卡洛定位 导航 路径规划 仿真 move_base gmapping acml 博文github 一.安装 turtlebot 移动机器人底座 进行导航 1.安装系统依赖 ...

  6. walking机器人入门教程-视觉转激光建图-cartographer算法建图

    系列文章目录 walking机器人入门教程-目录 walking机器人入门教程-硬件清单 walking机器人入门教程-软件清单 walking机器人入门教程-测试底盘 walking机器人入门教程- ...

  7. ros修改map_server地图发布的map关联的坐标系frame_id(多机器人联合建图用)

    帮师弟做多机器人联合建图的时候,遇到了map的坐标系问题如下: map_server发布的/map话题包含了frame坐标系关联,想要正确的让多个机器人共同建图导航需要修改/map话题以及其绑定的fr ...

  8. Turbot4机器人入门教程-使用统一建图入口

      系列文章目录: Turbot4机器人入门教程-硬件清单 Turbot4机器人入门教程-软件清单 Turbot4机器人入门教程-NoMachine远程控制 Turbot4机器人入门教程-配置网络 T ...

  9. 从0.3开始搭建LeGO-LOAM+VLP雷达+小车实时建图(保姆级教程,小白踩坑日记)

    背景:SLAM小白,因为项目需要花了两天时间编译代码+连接雷达实现了交互. 踩了很多坑,简单记录一下,让后面感兴趣的朋友少走点弯路~ 肯定有很多不专业的.错误的地方,还请大家不吝赐教(噗通) 也可以见 ...

最新文章

  1. Unity 3D学习视觉脚本无需编码即可创建高级游戏
  2. 线性模型系数解读中的那些坑,以套索回归(LASSO)和岭回归(Ridege)为例
  3. 弹出页(指定高度,自由拖动,点击空白包括状态栏触发)
  4. 小程序二次贝塞尔曲线,购物车商品曲线飞入效果
  5. cmd查看python安装路径-从cmd如何查找python的安装路径?
  6. OpenCV-Python中的两种图像通道分离法
  7. imageNamed和imageWithContextOfFile的区别?哪个性能高
  8. [leveldb] 3.put/delete操作
  9. 数据科学与大数据排名思考题_排名前5位的数据科学课程
  10. linux有两种工作界面,Linux 向用户提供了两种界面:用户界面和系统调用。
  11. DesiredCapabilities内容详解(摘)
  12. A - 数据结构实验之栈与队列一:进制转换
  13. python生成yaml_使用python脚本自动生成K8S-YAML
  14. redis查看连接数
  15. 开闭原则(Open-closed principle)
  16. 图像质量评价 开源项目汇总
  17. 二层交换机、三层交换机、路由器的区别
  18. HTML中怎么改变一条线的粗细
  19. 手机通讯录、联系人的备份、恢复经验
  20. 【146期】面试官问:说一说 RabbitMQ 的几种工作模式和优化建议?

热门文章

  1. flask中的html模板及调用
  2. deepin安装python3.8.1_deepin安装Python3.8以及使用pip3遇到的问题
  3. 念整数—编程设计入门C语言
  4. 前端小奈叽须知---js/jquery(目前分不清)
  5. 当网络虚拟化不足以解决问题时
  6. Python3暴力解题,计算鬼谷子猜数问题
  7. 2022年湖北省新一代人工智能科技项目揭榜挂帅需求及限制条件
  8. 数据结构(Java)-持续更新补充
  9. 2008中国软件外包研发竞争力十强企业
  10. laravel框架中微信公众号推送消息