ros操作系统笔记
ros操作系统笔记
ROS总体的设计
五个特点
1 点对点的设计
- 节点单元
- 分布式网络
- RPC+TCP/UDP通信系统
- 适合多机协助
2 多语言支持
- 支持Python,C++,Java 等编程语言
- 语言无关的接口定义
3 架构精简,集成度高
- 每一个功能可以单独编译
- 集成众多开源项目
- 接口统一,提高软件的复用性
4 组件化工具包丰富
- 3D可视化工具-----rviz
- 物理仿真环境------gazebo
- 数据记录工具 -----rosbag
- Qt工具箱 ---------rqt_*
5 免费并且开源
- BSD许可,可修改,可复用,可商用
- 软件包数据激增,良好的生态系统
四位一体
ROS = 通信机制 + 开发工具 + 应用系统 + 生态系统
ROS系统实现
三个层次
- 1 计算图:描述程序是如何运行的
- 2 文件系统:程序文件是如何组织和构建的
- 3 开源社区:ROS资源是如何分布式管理的
计算图
- 节点Node:软件模块
- 节点管理器ROS Master:控制中心,提供参数管理
- 话题TOpic:异步通信机制,传输消息Message
- 服务Service:同步通信机制,传输请求/应答数据
模型图如下
Topic通信机制步骤
-
Talker 注册
-
Lister 注册
-
ROS Master 进行信息匹配
-
Lister 发送连接请求
-
Talker 确认连接请求
-
建立网络连接
-
Talker向Lister发布数据
服务通信机制
- Talker 注册
- Listener 注册
- ROS Master 进行信息匹配
- 建立网络连接
- Talker 向Listener发布服务应答数据
参数通信机制
-
Talker设置变量
-
Listener查询参数值
-
ROS Master 向Listener发送参数值
(类似全局变量的概念,所有的节点都可以向Master申请访问参数。当Talker向Master更新了变量而Listener没有向Master进行更新此时Listener并不知道更新的参数)
Topic与Service的不同点
文件系统
- 功能包清单Package mainfest:记录功能包的基本信息,包含作者信息,许可信息,依赖选项,编译标志等
- 元功能包Meta Packages:组织多个用于同一目的功能包
- 元功能包清单:类似与功能包清单,不同之处在于元功能清单可能包含运行时需要的依赖的功能包或者声明一些引用标签
- 消息类型:消息是ROS节点之间发布/订阅的通信信息,可以使用ROS系统提供的消息类型,也可以使用.msg文件在功能包的msg文件夹自定义需要的消息类型
- 服务类型:服务类型定义了ROS服务器/客户端通信模型下的请求与应答数据类型,可以使用ROS系统提供的服务类型。也可以使用.srv文件在功能包的srv文件夹中进行定义
- 代码:放置功能包节点源代码的文件夹
开源社区
- 发行版:ROS发行版包括一系列的带有版本号,可以直接安装的功能包
- ROS wiki:记录ROS文档信息文档的主要论坛
- ROS Answers:咨询ROS相关问题的网站
- 博客:发布ROS社区中的新闻,图片,视频http://www.ros.org/news
命令工具
- catkin_create_pkg 创建功能包
- rospack 获取功能包信息
- catkin_make 编译工作空间中的功能包
- rosdep 自动安装功能包依赖的其他包
- roscd 功能包目录跳转
- roscp 拷贝功能包中的文件
- rosed 编辑功能包中的文件
- rosrun 运行功能包中的可执行文件
- roslaunch 运行启动文件
小海龟仿真
- 启动master
roscore
- 启动小海龟
rosrun turtlesim turtlesim_node
# turtlesim为功能包名字 turtlesim_node 节点名字 - 启动海龟控制点
rosrun turtlesim turtle_teleop_key
rqt_graph 可以显示当前启动的节点以及计算图
rqt_plot:可以把消息数据通过线表示出来
ROS应用架构
扩展资源
RPC协议补充
创建工作空间
工作空间是一个存放工程开发相关文件的文件夹。
- src :代码空间
- build:编译空间
- devel:开发空间
- install:安装空间
创建工作空间步骤
-
创建工作空间
mkdir -p ~/myros_ws/src cd ~/myros_ws/src catkin_init_workspace
-
编译工作空间
cd ~/myros_ws/
catkin_make
- 设置环境变量
source ~/myros_ws/devel/detup.bash
-
检查环境变量
echo $ROS_PACKAGE_PATH
创建功能包
catkin_create_pkg package_name depend1 depend2
-
创建功能包
cd ~/ship_ws/src catkin_create_pkg learning_communication std_msgs rospy roscpp
-
编译功能包
cd ~/catkin_ws catkin_make source ~/catkin_ws/devel/setup.bash 一开始设置了
工作空间覆盖
ROS工作空间OVerlaying机制,即工作空间覆盖
$ env | grep ROS
ROS_PACKAGE_PATH=/home/xj/ship_ws/src:/home/xj/ros_ws/src:/opt/ros/kinetic/share
ROS在使用功能包的时候会从ROS_PACKAGE_PATH 设置的路径下,一层层的找下去,新的的路径会自动放到最前面。
rospack find roscpp_tutorials 查找功能包路径
ROS通信编程
话题编程
实现一个发布者的步骤
-
初始化ROS节点
-
向ROS Master注册节点信息,包括发布的话题名和话题中的消息类型
-
按照一定频率循环发布消息
#include"sstream" #include"ros/ros.h" #include"std_msgs/String.h" int int main(int argc, char *argv[]) { //ROS节点初始化 ros::init(argc, argv, "talker"); //创建节点句柄 ros::NodeHandle n; //创建一个Pusher,发布名为chatter 的topic,消息类型为std_msgs::string ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter",1000); //设置循环频率 ros::Rate loop_rate(10); int count = 0; while (ros::ok()) { /* code for loop body */ std_msgs::String msg; std::stringstream ss; ss<<"hello word"<<count; msg.data = ss.str(); //发布消息 ROS_INFO("%s",msg.data.c_str()); chatter_pub.publish(msg) //循环等待回调函数,在此处无意义 ros::spinOnce() //按照循环频率延迟 loop_rate.sleep() ++count } return 0; }
实现一个订阅者的步骤
-
初始化ROS节点
-
订阅需要的话题
-
循环等待话题消息,接收到消息后进入回调函数
-
在回调函数中完成消息处理
#include"ros/ros.h" #include"std_msgs/String.h" //接收信息的处理函数,回调函数 void chatterCallback(const std_msgs::String::ConstPtr& msg) { ROS_INFO("I heard:[%s]",msg->data.c_str()) } int int main(int argc, char *argv[]) { //初始化ROS节点 ros::init(argc, argv, "listener"); //创建节点句柄 ros::NodeHandle n; //创建一个Subscriber ,订阅名为chatter的topic,注册回调函数 ros::Subscriber sub = n.subscribe("chatter",1000,chatterCallback) ros::spin(); return 0; }
如何编译代码
-
设置需要编译的代码和生成的可执行文件
-
设置链接库
-
设置依赖
-
add_executable(talker src/talker.cpp) target_link_libraries(talker ${catkin_LIBRARIES}) add_executable(listener src/lister.cpp) target_link_libraries(listener ${catkin_LIBRARIES}) #add_dependencies(talker ${PROJECT_NAME}_generate_messages_cpp)
自定义话题消息步骤
-
定义msg文件
创建一个msg文件夹,在文件夹中创建一个per.msg 文件
-
在package.xml中添加功能包依赖
<build_depend>message_generation</build_depend> <exec_depend>message_runtime</exec_depend>
-
在CMakeList.txt添加编译选项
find_package(... message_generation) add_message_files(FILES Person.msg) generate_messages(DEPENDENCIES std_msgs) catkin_package(CATKIN_DEPENDS geometry_msgs roscpp rospy std_msgs message_runtime)
注意:generate_messages()必须要放在catkin_package()之前
服务编程
步骤
-
定义srv文件
创建一个srv 文件夹并在文件夹中创建一个类似AddTwolnts.srv的文件
int64 a int64 b --- int64 sum
注意:上面的三个短横线 把服务的内容分成了 请求内容(上)和应答内容(下)
-
在package.xml中添加功能包依赖
<build_depend>message_generation</build_depend> <exec_depend>message_runtime</exec_depend>
-
在CMakeLists.txt添加编译选项
find_package(... message_generation) catkin_package(CATKIN_DEPENDS geometry_msgs roscpp rospy std_msgs message_runtime) add_service_files(FILES AddTwolnts.srv)
服务端的实现
-
初始化ROS节点
-
创建Server实例
-
循环等待服务请求,进入回调函数
-
在回调中函数中完成服务功能的处理,并反馈应答数据
#include"ros/ros.h" #include"learning_communication/AddTwolnts.h" bool add(learning_communication::AddTwolnts::Request &req,learning_communication::AddTwolnts::Response &res) { res.sum = req.a + req.b; ROS_INFO("request : x=%ld,y=%ld",(long int)req.a,(long int)req.b); ROS_INFO("sending back response:[%ld]",(long int)res.sum); return true; } int main(int argc, char *argv[]) { //ROS节点初始化 ros::init(argc, argv, "add_two_ints_server"); //创新节点句柄 ros::NodeHandle n; //创建一个add_two_ints的server,注册回调函数add ros::ServiceServer service = n.advertiseService("add_two_ints",add); //循环等待回调函数 ROS_INFO("Ready to add two ints."); ros::spin(); return 0; }
客户端实现
- 初始化ROS节点
- 创建一个Client实例
- 发布服务请求数据
- 等待Server处理之后的应答结果
#include<cstdlib>
#include"ros/ros.h"
#include"learning_communication/AddTwolnts.h"
int main(int argc, char *argv[])
{
//ROS节点初始化
ros::init(argc, argv, "add_two_ints_client");
if (argc!=3)
{
/* code for True */
ROS_INFO("usage:add_two_ints_client x y");
return 1;
}
//创建节点句柄
ros::NodeHandle n;
//创建一个client 请求add_two_int service,service消息类型是learning_communication::AddTwolnts
ros::ServiceClient client = n.serviceClient<learning_communication::AddTwolnts>("add_two_ints");
//创建learning_communication::AddTwolnts类型的service消息
learning_communication::AddTwolnts srv;
srv.request.a=atoll(argv[1]);
srv.request.b=atoll(argv[2]);
//如果发布service请求,等待结果。会堵塞的
if(client.call(srv))
{
ROS_INFO("Sum:%ld",(long int)srv.response.sum);
}else
{
ROS_INFO("failed to call service add_two+ints");
return 1;
}
return 0;
}
-
在CMakeList.txt添加编译选项
add_executable(server src/server.cpp) target_link_libraries(server ${catkin_LIBRARIES}) add_dependencies(server ${PROJECT_NAME}_gencpp) add_executable(client src/client.cpp) target_link_libraries(client ${catkin_LIBRARIES}) add_dependencies(client ${PROJECT_NAME}_gencpp)
注意:generate_messages()必须要放在catkin_package()之前
动作编程
什么是动作
-
一种问答通信机制
-
带有连续反馈
-
可以在任务过程中中止运行
-
基于ROS的消息机制实现
Action的接口
-
goal:发布任务目标
-
cancel:请求取消任务
-
status:通知客户端当前的状态
-
feedback:周期反馈任务运行的监控数据
-
result:向客户端发送任务的执行结果,只发布一次
自定义动作消息
-
定义action文件
-
创建action文件夹
-
创建类似DoDishes.action文件
#定义目标信息 uint32 dishwasher_id --- #定义结果信息 uint32 total_dishes_cleaned --- #定义周期反馈的消息 float32 percent_complete
-
-
在package.xml中添加功能包依赖
<build_depend>actionlib</build_depend> <build_depend>actionlib_msgs</build_depend> <exec_depend>actionlib</exec_depend> <exec_depend>actionlib_msgs</exec_depend>
-
在CMakeLists.txt添加编译选项
find_package(catkin REQUIRED actionlib_msgs actionlib) add_action_files(DIRECTORY action FILES DoDishes.action) generate_messages(DEPENDENCIES actionlib_msgs)
动作服务器的实现
-
初始化ROS节点
-
创建动作服务实例
-
启动服务器,等待动作请求
-
在回调函数中完成动作服务功能的处理,并反馈进度信息
-
动作完成后,发送结束信息
#include"ros/ros.h" #include<actionlib/server/simple_action_server.h> #include<learning_communication/DoDishesAction.h> typedef actionlib::SimpleActionServer<learning_communication::DoDishesAction> Server; //收到action的goal后回调该和回调函数进行处理 void execute(const learning_communication::DoDishesGoalConstPtr& gola,Server *as) { ros::Rate r(1); learning_communication::DoDishesFeedback feedback; ROS_INFO("Dishwasher %d is working ,",gola->dishwasher_id); //假设洗盘子的进度,并且按照1hz的频率发布进度feedback for (int i = 0; i < 10; i++) { /* code for loop body */ feedback.percent_complete = i*10; as->publishFeedback(feedback); r.sleep(); } //当action完成后,向客户端返回结果 ROS_INFO("Dishwasher %d finfish working ,",gola->dishwasher_id); as->setSucceeded(); } int main(int argc, char *argv[]) { ros::init(argc, argv, "do_dishes_server"); ros::NodeHandle n; //定义服务器,服务名为do_dishes boost进行绑定 Server server(n,"do_dishes",boost::bind(&execute,_1,&server),false); //服务器运行 server.start(); ros::spin(); return 0; }
动作客户端的实现
-
初始化ROS节点
-
创建动作客户端实例
-
连接动作服务端
-
发送动作目标
-
根据不同类型的服务端反馈处理回调函数
#include"ros/ros.h" #include<actionlib/client/simple_action_client.h> #include<learning_communication/DoDishesAction.h> typedef actionlib::SimpleActionClient<learning_communication::DoDishesAction> Client; //当action完成后会调用该回调函数一次 void doneCb(const actionlib::SimpleClientGoalState& state,const learning_communication::DoDishesResultConstPtr& result) { ROS_INFO("Yay! The dishes are now clean"); ros::shutdown(); } //当action**后回调用该回调函数一次 void activeCb() { ROS_INFO("Goal just went active"); } //收到feedback后调用该回调函数 void feedbackCb(const learning_communication::DoDishesFeedbackConstPtr& feeback) { ROS_INFO("percent_complete:%f",feeback->percent_complete); } int main(int argc, char *argv[]) { ros::init(argc, argv, "do_dishes_action"); //定义一个客户端 Client client("do_dishes",true); //等待服务端 ROS_INFO("Waiting for action server to start."); client.waitForServer(); ROS_INFO("Action server started ,sending goal"); //创建一个action的goal learning_communication::DoDishesGoal goal; goal.dishwasher_id =1; //发送action的goal给服务端,并设置回调函数 client.sendGoal(goal,&doneCb,&activeCb,&feedbackCb); ros::spin(); return 0; }
修改CmakeLists.txt
add_executable(Dodishes_client src/action_client.cpp)
target_link_libraries(Dodishes_client ${catkin_LIBRARIES})
add_dependencies(Dodishes_client ${${PROJECT_NAME}_EXPORTED_TARGETS})
add_executable(Dodishes_server src/action_server.cpp)
target_link_libraries(Dodishes_server ${catkin_LIBRARIES})
add_dependencies(Dodishes_server ${${PROJECT_NAME}_EXPORTED_TARGETS})
分布式通信
ROS是一种分布式软件框架,节点之间通过松耦合的方式组合的
实现分布式多机通信
-
设置IP地址,确保底层链路的联通
通过sudo vim /etc/hosts 把对方的ip和主机名 加入的hosts中
127.0.0.1 localhost 127.0.1.1 lv 192.168.43.26 xj #对方的ip和主机名 # The following lines are desirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters
然后ping对方主机名 看是否成功 ping xj
-
在从机端设置ROS_MASTER_URI,让从机找到ROS Master
export ROS_MASTER_URI=http://xj:11311 或 echo "export ROS_MASTER_URI=http://xj:11311">>~/.bashre
测试案例
$ rostopic list $ rostopic pub -r 10 /turtle1/cmd_vel geometry_msgs/Twist "linear: x: 2.0 y: 0.0 z: 0.0 angular: x: 0.0 y: 0.0 z: 2.0"
ROS中的关键组件
Launch文件
Launch文件:通过XML文件实现多个节点的配置和启动(可自启动ROS Master)
<launch>
<node pkg="trutlesim" name="sim1" type="trutlesim_node"/>
<node pkg="trutlesim" name="sim1" type="trutlesim_node"/>
</launch>
launch文件中的根元素采用标签定义
启动节点
pkg :节点所在功能包的名称
type:节点的可执行文件的名称
name:节点运行时名称
output:日志信息是否打印
respawn:如果此节点失败或失效从新启动
required:这个节点是个必须要启动的
ns:节点的命名空间
args:输入参数
类似全局变量,可以通过代码调用,运行成功会保存在服务器中
设置ROS系统运行中的参数,存储在参数服务器中 name:参数名 value:参数值加载参数文件中的多个参数
<rosparam file=“params.yaml”,command=“load” ns=“params”/>
launch文件中的局部变量,仅限于launch文件使用
name:参数名
value:参数值
调用:
重映射 :重映射ROS计算图资源的命名
from : 原命名 to:映射之后的命名
嵌套 包含其他的launch文件,类似c语言中的包含头文件
file:包含的其他launch文件路径
坐标变换(机器人导论)
TF功能包能干什么,默认保存10秒前的坐标变换关系
- 五秒之前,机器人头部坐标系相对于全局坐标系的关系是什么样的
- 机器人夹取的物体相对与机器人中心坐标系的位置在哪里
- 机器人中心坐标系相对与全局坐标系的位置在哪里
TF 坐标变换如何实现
- 广播TF变换
- 监听TF变换
rosrun tf view_frames #可以查看有几个坐标系
rosrun tf tf_echo turtle1 turtle2 #可以查看 turtle1 turtle2 的坐标关系
rosrun rviz rviz -d 'rospack find turtle_tf' /rviz/turtle_rviz.rviz #可视化查看
步骤
-
1 在src创建一个TF的功能包
catkin_create_pkg learning_communication std_msgs rospy roscpp geometry_msgs turtlesim tf
-
在工作目录下编译
catkin_make
-
实现广播和监听代码
实现一个TF广播器
-
定义TF广播器(TransformBroadcaster)
-
创建坐标变换值
-
发布坐标变换值(sendTransform)
#include<ros/ros.h> #include<tf/transform_broadcaster.h> #include<turtlesim/Pose.h> std::string turtle_name; void poseCallback(const turtlesim::PoseConstPtr& msg) { //tf广播器 static tf::TransformBroadcaster br; //根据乌龟当前的位资,设置相对于世界坐标系的坐标转换 tf::Transform transform; transform.setOrigin(tf::Vector3(msg->x,msg->y,0.0)); tf::Quaternion q; q.setRPY(0,0,msg->theta); transform.setRotation(q); //发布坐标变化 br.sendTransform(tf::StampedTransform(transform,ros::Time::now(),"world",turtle_name)); } int main(int argc, char *argv[]) { ros::init(argc, argv, "my_tf_broadcaster"); if(argc!=2) { ROS_ERROR("need turtle name as argument"); return -1; } turtle_name = argv[1]; //订阅乌龟的pose信息 ros::NodeHandle node; ros::Subscriber sub = node.subscribe(turtle_name+"/pose",10,&poseCallback); ros::spin(); return 0; }
实现TF监听器
- 定义TF监听器(TransformListener)
- 查找坐标变换(waitForTransform ,lookupTransform)
#include<ros/ros.h>
#include<tf/transform_listener.h>
#include<geometry_msgs/Twist.h>
#include<turtlesim/Spawn.h>
int main(int argc, char *argv[])
{
ros::init(argc, argv, "my_tf_listener");
ros::NodeHandle node;
//通过调用产生第二只乌龟
ros::service::waitForService("spawn");
ros::ServiceClient add_turtle = node.serviceClient<turtlesim::Spawn>("spawn");
turtlesim::Spawn srv;
add_turtle.call(srv);
// 定义turtle2的速度控制发布器
ros::Publisher turtle_vel = node.advertise<geometry_msgs::Twist>("turtle2/cmd_vel", 10);
//tf监听
tf::TransformListener listener;
ros::Rate rate(10.0);
while (node.ok())
{
/* code for loop body */
tf::StampedTransform transform;
try
{
//查找turtle2和turtle1的坐标变换
listener.waitForTransform("/turtle2","/turtle1",ros::Time(0),ros::Duration(3.0));
listener.lookupTransform("/turtle2","/turtle1",ros::Time(0),transform);
}
catch (tf::TransformException &ex)
{
/* code for Catch */
ROS_ERROR("%s",ex.what());
ros::Duration(1.0).sleep();
continue;
}
//根据turtle1和turtle2之间的坐标变换,计算turtle2需要的运动的速度和角数度
//并发布速度控制指令,使turtle1移动
geometry_msgs::Twist vel_msg;
vel_msg.angular.z=4.0* atan2(transform.getOrigin().y(),transform.getOrigin().x());
vel_msg.linear.x = 0.5* sqrt(pow(transform.getOrigin().x(),2)+pow(transform.getOrigin().y(),2));
turtle_vel.publish(vel_msg);
rate.sleep();
}
return 0;
}
配置编译环境
CmakeList.txt
add_executable(turtle_tf_broadcaster src/turtle_tf_broadcaster.cpp)
target_link_libraries(turtle_tf_broadcaster ${catkin_LIBRARIES})
add_executable(turtle_tf_listener src/turtle_tf_listener.cpp)
target_link_libraries(turtle_tf_listener ${catkin_LIBRARIES})
创建launch文件夹 创建launch文件方便启动
<launch>
<!--海归仿真器-->
<node pkg="turtlesim" type="turtlesim_node" name="sim"/>
<!--键盘控制-->
<node pkg="turtlesim" type="turtle_teleop_key" name="teleop" output="screen"/>
<!--两个海龟的tf广播-->
<node pkg="learning_tf" type="turtle_tf_broadcaster" args="/turtle1" name="turtle1_tf_broadcaster" />
<node pkg="learning_tf" type="turtle_tf_broadcaster" args="/turtle2" name="turtle2_tf_broadcaster"/>
<!--监听tf广播,并控制turtle2移动-->
<node pkg="learning_tf" type="turtle_tf_listener" name="listener"/>
</launch>
Qt的工具箱
-
日志输出工具:rqt_console
-
计算图的可视化工具:rqt_graph 便于查看系统结构
-
数据绘图工具 :rqt_plot 方便查看数据的变化
-
参数动态配置工具:rqt_reconfigure 一旦参数发生改变 系统其他使用次参数的节点都可以接收到
-
启动
rqt_console
Rviz可视化平台
启动Rviz rosrun rviz rviz
Gazebo物理仿真环境
启动一个模型
roslaunch gazebo_ros empty_world.launch
扩展阅读
作业
注意:当出现功能包找不到时要检查
1.src中是否有功能包文件
2,检查CMake文件中有没有设置相关的选项
3.page.xml的依赖设置有没有写
机器人系统设计
机器人的定义与组成
机器人构建
执行机构的实现
有机器人底盘,电机,舵机
驱动系统实现
- 1 电源子系统
- 12v/5v/3v
- 电源保护,滤波
- 2 电机子系统
- 电机驱动:控制信号-》电信号
- 电机控制:闭环驱动
- 传感器接口
- 超声波
- 里程计
可以淘宝买 机器人驱动板
内部传感器的实现
机器人里程计测距原理
- 根据单位时间内产生的脉冲数计算电机/*的旋转圈数
- 根据*的周长计算机器人的运动速度
- 根据机器人的运动速度积分计算里程
惯性测量单元(IMU)
测量物体速度姿态,主要包括三抽陀螺、三轴加速计、磁力计等
控制系统实现
外部环境系统实现
链接电脑摄像头
sudo apt-get install ros-kinetic-usb-caam 安装功能包
roslaunch usb_cam usb_cam-test.launch
rqt_image_view
链接Kinect
sudo apt-get install ros-kinetic-freenect-*
git clone https://github.com/avim2/SensorKinect.git
cd SensorKinect/Bin
tar xvf SensorKinect093-Bin-Linux-x86-v5.1.2.1.tar.bz2
sudo ./install.sh
链接激光雷达
sudo apt-get install ros-kinetic-rplidar-ros
rosrun rplidar_ros rplidarNode
若有串口权限问题
sudo gpasswd --add yonghuming doalout
完整事例
URDF机器人建模
-
什么是URDF
-
Unified Robot Description Format:统一机器人描述格式
-
ROS中一个非常重要的机器人模型的描述格式
-
可以解析URDF文件中使用XML格式描述的机器人模型
-
ROS同时也提供个URDF文件的C++解析器
-
-
- 描述机器人某个刚体部分的外观和物理属性
- 尺寸size、颜色color、形状shape、惯性矩阵inertial matrix、碰撞参数collision properties
- :描述机器人link部分的外观参数
- :描述link的惯性参数
- :描述link的碰撞参数
<link name="<link name>"> <inertial>.......</inertial> <visual>.........</visual> <collision>.......</collision> </link>
-
-
描述机器人关节的运动学和动力学属性
-
包括关节运动的位置和速度的限制
-
根据关节运动形式,可以将其分为六种类型
-
:关节的参考位置,用来校准关节的绝对位置
-
:描述关节的物理属性,例如阻尼值、物理静摩擦力、经常在动力学仿真中用到
-
:描述运动的一些极限值,包括关节运动上下限位置,速度限制、力距限制等
-
:描述该关节与已有关节的关系
-
<safety_controller>: 描述安全控制器参数
-
```xml
<joint name="<name of the joint>" type="<joint type>">
<parent link="parent_link" />
<child link="child_link" />
<dynamics damping ...../>
<limit effort .../>
....
</joint>
```
-
-
完整机器人模型的顶层标签
-
和标签都必须包含在标签内
<robot name="<name of the robot>"> <link>........</link> <link>........</link> <joint>.......</joint> <joint>.......</joint> </robot>
-
创建一个机器人模型
catkin_create_pkg mbot_description urdf xacro
-
urdf:存放机器人模型的URDF或xacro文件
-
meshes:放置URDF中引用的模型渲染文件
-
launch:保存相关启动文件
-
config:保存rviz的配置文件
joint_state_publisher:发布每个joint(除fixed类型)的状态,而且可以通过UI界面对jonit进行控制
robot_state_publisher:将机器人各个links、joints之间的关系通过TF的形式,整理成三维姿态信息发布
可以使用
urdf_to_graphiz mbot_base.urdf 来查看机器人的结构
机器人URDF模型优化
xacro模型文件
- 精简模型代码
- 创建宏定义
- 文件包含
- 提供编程接口
- 常量
- 变量
- 数学计算
- 条件语句
常量定义与使用
<xacro:property name="M_Pl" value="3.14159"/>
<origin xyz="0 0 0" rpy="${M_Pl/2} 0 0"/>
数学计算
<origin xyz="0 ${(motor_length+wheel_length)/2} 0" rpy="0 0 0"/>
:所有的数学运算都会转化成浮点数进行,以保证运算精度
宏定义与使用
<xacro:macro name="M_Pl" params="A B C">
.......
</xacro:macro>
<name A="A_value" B="B_value" C="C_value"/>
文件包含
<xacro:include filename="$(find mbot_description)/urdf/xacro/mbot_base.xacro"
模型展示
方法1 将xacro文件转换成URDF文件后显示
$ rosrun xacro xacro.py mbot.xacro > mbot.urdf
方法2 直接调用xacro文件解析器
<arg name="model" default="$(find xacro)/xacro --inorder '$(find mbot_description)/xacro/mbot.xacro'"/>
<param name="robot_description" command="$(arg mode)" />
$ roslaunch mbot_description display_mbot_base_xacro.launch
ArbotiX+rviz功能仿真
Arbotix是什么
- 一款控制电机、舵机的硬件控制板
- 提供了相应的ROS功能包
- 提高一个差速控制器,通过接收速度控制指令,更新机器人的里程状态
Arbptix的安装
indigo 版
$ sudo apt-get install ros-indigo-arbotix-*
Kinetic 版
$ git clone https://github.com/vanadiumlabs/arbotix_ros.git
$ catin_make
其中的python要有可执行权限
启动
$ roslaunch mbot_description arbotix_mbot_with_camera_xacro.launch
启动键盘控制
$ roslaunch mbot_teleop mbot_teleop.launch
<>
Gazebo物理仿真环境搭建
ros_control
ros_control 是什么
- ROS为开发者提供的机器人控制中间件
- 包含一系列控制接口、传动装置接口、硬件接口、控制工具箱
- 可以帮助机器人应用功能包快速落地,提高开发效率
控制流程图
- 控制管理器:提供一种通用的接口来管理不同的控制器
- 控制器:读取硬件状态、发布控制命令、完成每个joint的控制
- 硬件资源:为上下层提供硬件资源的接口
- 机器人硬件抽象:机器人硬件抽象和硬件资源直接打交道,通过write和read方法完成硬件操作
- 真实机器人:执行接受到的命令
控制器:(Controllers)
- joint_effort_controller
- joint_state_controller
- joint_position_controller
- joint_velocity_controller
配置机器人模型
第一步:为link添加惯性参数和碰撞属性
第二步:为link添加gazebo标签
第三步:为joint添加传动装置
第四步:添加gazebo控制插件
- 机器人的命名空间
- 和:左右轮转动的关节joint
- 和:机器人模型的相关尺寸,在计算差速参数时需要用到
- :控制器订阅的速度控制指令,生成全局命名时需要结合中设置的命名空间
- :里程计数据的参数坐标系,ROS中一般都命名为odom
创建仿真环境
1,直接放置物体
2,使用Building Editor
传感器仿真
摄像头仿真
-
标签:描述传感器>
-
type:传感器类型,camera
-
name:摄像头命名,*设置
-
-
标签:描述摄像头参数
- 分辨率,编码,图像范围,噪音
-
标签:加载摄像头仿真环境插件
- libgazebo_ros_camera.so
- 设置插件的命名空间、发布图像的参考坐标系