一、话题通信、服务通信编程练习
工作空间(workspace)是一个存放工程开发相关文件的文件夹。
1.首先创建一个工作空间
mkdir -p ~/catkin_ws/src#创建文件夹
cd ~/catkin_ws/src#进入目录
catkin_init_workspace#初始化,使其成为ROS的工作空间
2.创建好工作空间后即可编译
cd ..
catkin_make
3.环境变量设置
source /home/haha/catkin_ws/devel/setup.bash#
sudo nano ~/.bashrc
该环境变量设置只对当前终端有效,haha是用户名
#将上面命令放置到~/.bashrc文件中,让其对所有终端都有效
4.检查环境变量
echo $ROS_PACKAGE_PATH
创建功能包
cd ~/catkin_ws/src
catkin_create_pkg learning_communication std_msgs rospy roscpp
#catkin_create_pkg 功能包名字 依赖
#std_msgs:定义的标准的数据结构
#rospy:提供python编程接口
#roscpp:提供c++编程接口
catkin_make
2. 话题编程
发布者代码
在 catkin_ws/src/learning_communication/src 目录下创建 talkre.cpp 文件,代码如下
#include <sstream>
#include "ros/ros.h"
#include "std_msgs/String.h"
int main(int argc, char **argv)
{
//ROS节点初始化
ros::init(argc, argv, "talker");
//创建节点句柄
ros::NodeHandle n;
//创建一个Publisher,发布名为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())
{
//初始化std_msgs::String类型的消息
std_msgs::String msg;
std::stringstream ss;
ss<<"hello world"<<count;
msg.data = ss.str();
//发布消息
ROS_INFO("%s", msg.data.c_str());
chatter_pub.publish(msg);
//循环等待回调函数
ros::spinOnce();
//接受循环频率延时
loop_rate.sleep();
++count;
}
return 0;
}
订阅者代码
在该目录下创建 listener.cpp 文件,代码如下
#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 main(int argc,char **argv)
{
//初始化ROS节点
ros::init(argc,argv,"listener");
//创建节点句柄
ros::NodeHandle n;
//创建一个Subscriber,订阅名为chatter的topic,注册回调函数chatterCallback
ros::Subscriber sub=n.subscribe("chatter",1000,chatterCallback);
//循环等待回调函数
ros::spin();
return 0;
}
编译代码
进入 learning_commuication 目录下的 CMakeLists.txt 中,添加以下代码
add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
3. 服务通信编程
在 /catkin_ws/src/learning_communication/srv 目录下创建 AddTwoInts.srv 文件,并添加以下代码
int64 a
int64 b
---
int64 sum
返回上级目录为:gedit CMakeLists.txt
弹出的.txt文档中修改代码
服务器端:
在 /catkin_ws/src/learning_communication/srv 目录下创建 server.cpp 文件
#include<ros/ros.h>
#include"learning_communication/AddTwoInts.h"
//service回调函数,输入参数req,输出参数res
bool add(learning_communication::AddTwoInts::Request &req,learning_communication::AddTwoInts::Response &res)
{
//将输入的参数中的请求数据相加,结果放到应答变量中
res.sum=req.a+req.b;
ROS_INFO("request: x=%1d,y=%1d",(long int)req.a,(long int)req.b);
ROS_INFO("sending back response:[%1d]",(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;
}
客户端:
在同个目录下创建 client.cpp 文件
#include<cstdlib>
#include<ros/ros.h>
#include"learning_communication/AddTwoInts.h"
int main(int argc,char **argv)
{
//ROS节点初始化
ros::init(argc,argv,"add_two_ints_client");
//从终端命令行获取两个加数
if(argc!=3)
{
ROS_INFO("usage:add_two_ints_client X Y");
return 1;
}
//创建节点句柄
ros::NodeHandle n;
//创建一个client,请求add_two_ints_service
//service消息类型是learning_communication::AddTwoInts
ros::ServiceClient client=n.serviceClient<learning_communication::AddTwoInts>("add_two_ints");
//创建learning_communication::AddTwoInts类型的service消息
learning_communication::AddTwoInts srv;
srv.request.a=atoll(argv[1]);
srv.request.b=atoll(argv[2]);
//发布service请求,等待加法运算的应答请求
if(client.call(srv))
{
ROS_INFO("sum: %1d",(long int)srv.response.sum);
}
else
{
ROS_INFO("Failed to call service add_two_ints");
return 1;
}
return 0;
}
继续编辑 CMakeLists.txt 文件
add_executable(server srv/server.cpp)
target_link_libraries(server ${catkin_LIBRARIES})
add_dependencies(server ${PROJECT_NAME}_gencpp)
add_executable(client srv/client.cpp)
target_link_libraries(client ${catkin_LIBRARIES})
add_dependencies(client ${PROJECT_NAME}_gencpp)
进入 catkin_ws 目录
编译:
catkin_make
二、使用 Rviz 显示电脑摄像头的视频
在进入 Ubuntu 之前先打开虚拟机设置,将 USB 控制器设置如下,usb控制器调为启用状态
在虚拟机设置里链接可移动设备
2. 按照课件上 gazebo 仿真内容,完成 gazebo 环境设置(包括家具和障碍物)、机器人传 感器(camera、kinect、Lidar)安装,用键盘控制机器人的行走,并在 Rviz 中查看各传感器 的采集信息。
Gazebo物理仿真环境搭建
机器人的地盘仿真:
代码
cd ~/catkin_ws/src/mbot_description/urdf/xacro
mkdir gazebo
cd gazebo
sudo gedit mbot_base_gazebo.xacro
xml文件的声明:
<?xml version="1.0"?>
<robot name="mbot" xmlns:xacro="http://www.ros.org/wiki/xacro">
<!--存放下面相关定义内容-->
</robot>
各link的质量(mass)属性声明及其他常量声明:
```handlebars
<!-- PROPERTY LIST -->
<xacro:property name="M_PI" value="3.1415926"/>
<xacro:property name="base_mass" value="20" />
<xacro:property name="base_radius" value="0.20"/>
<xacro:property name="base_length" value="0.16"/>
<xacro:property name="wheel_mass" value="2" />
<xacro:property name="wheel_radius" value="0.06"/>
<xacro:property name="wheel_length" value="0.025"/>
<xacro:property name="wheel_joint_y" value="0.19"/>
<xacro:property name="wheel_joint_z" value="0.05"/>
<xacro:property name="caster_mass" value="0.5" />
<xacro:property name="caster_radius" value="0.015"/> <!-- wheel_radius - ( base_length/2 - wheel_joint_z) -->
<xacro:property name="caster_joint_x" value="0.18"/>
颜色属性的声明:
<!-- Defining the colors used in this robot -->
<material name="yellow">
<color rgba="1 0.4 0 1"/>
</material>
<material name="black">
<color rgba="0 0 0 0.95"/>
</material>
<material name="gray">
<color rgba="0.75 0.75 0.75 1"/>
</material>
宏定义 球体惯性矩阵计算
<!-- Macro for inertia matrix -->
<xacro:macro name="sphere_inertial_matrix" params="m r">
<inertial>
<mass value="${m}" />
<inertia ixx="${2*m*r*r/5}" ixy="0" ixz="0"
iyy="${2*m*r*r/5}" iyz="0"
izz="${2*m*r*r/5}" />
</inertial>
</xacro:macro>
宏定义 圆柱体惯性矩阵计算:
<xacro:macro name="cylinder_inertial_matrix" params="m r h">
<inertial>
<mass value="${m}" />
<inertia ixx="${m*(3*r*r+h*h)/12}" ixy = "0" ixz = "0"
iyy="${m*(3*r*r+h*h)/12}" iyz = "0"
izz="${m*r*r/2}" />
</inertial>
</xacro:macro>
前后轮的宏定义:
<!-- Macro for robot caster -->
<xacro:macro name="caster" params="prefix reflect">
<joint name="${prefix}_caster_joint" type="continuous">
<origin xyz="${reflect*caster_joint_x} 0 ${-(base_length/2 + caster_radius)}" rpy="0 0 0"/>
<parent link="base_link"/>
<child link="${prefix}_caster_link"/>
<axis xyz="0 1 0"/>
</joint>
<link name="${prefix}_caster_link">
<visual>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<sphere radius="${caster_radius}" />
</geometry>
<material name="black" />
</visual>
<!-- 碰撞属性 -->
<collision>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<sphere radius="${caster_radius}" />
</geometry>
</collision>
<!-- 惯性属性 -->
<sphere_inertial_matrix m="${caster_mass}" r="${caster_radius}" />
</link>
<!--添加gazebo标签,为各link配颜色-->
<gazebo reference="${prefix}_caster_link">
<material>Gazebo/Black</material>
</gazebo>
</xacro:macro>
定义主体base并添加内容:
<xacro:macro name="mbot_base_gazebo">
<link name="base_footprint">
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<box size="0.001 0.001 0.001" />
</geometry>
</visual>
</link>
<!-- 给 base_footprint 添加标签 -->
<gazebo reference="base_footprint">
<turnGravityOff>false</turnGravityOff>
</gazebo>
<joint name="base_footprint_joint" type="fixed">
<origin xyz="0 0 ${base_length/2 + caster_radius*2}" rpy="0 0 0" />
<parent link="base_footprint"/>
<child link="base_link" />
</joint>
<!--base_link添加碰撞属性和惯性属性-->
<link name="base_link">
<visual>
<origin xyz=" 0 0 0" rpy="0 0 0" />
<geometry>
<cylinder length="${base_length}" radius="${base_radius}"/>
</geometry>
<material name="yellow" />
</visual>
<collision>
<origin xyz=" 0 0 0" rpy="0 0 0" />
<geometry>
<cylinder length="${base_length}" radius="${base_radius}"/>
</geometry>
</collision>
<cylinder_inertial_matrix m="${base_mass}" r="${base_radius}" h="${base_length}" />
</link>
<!--base_link添加gazebo标签-->
<gazebo reference="base_link">
<material>Gazebo/Blue</material>
</gazebo>
<wheel prefix="left" reflect="-1"/> <!-- 调用驱动轮子宏定义 -->
<wheel prefix="right" reflect="1"/> <!-- 调用驱动轮子宏定义 -->
<caster prefix="front" reflect="-1"/> <!--调用支撑轮子宏定义-->
<caster prefix="back" reflect="1"/> <!-- 调用支撑轮子宏定义 -->
</xacro:macro>
添加gazebo控制插件:
小车需要差速控制器,gazebo里差速控制器的插件是现成的
libgazebo_ros_diff_drive.so文件
<!-- controller -->
<gazebo>
<plugin name="differential_drive_controller"
filename="libgazebo_ros_diff_drive.so"> <!-- gazebo提供得差速控制器插件 -->
<!-- 控制器所需参数 -->
<rosDebugLevel>Debug</rosDebugLevel>
<publishWheelTF>true</publishWheelTF>
<robotNamespace>/</robotNamespace><!-- 机器人命名空间 订阅和发布得话题 前面 会加上命名空间 /说明没有添加-->
<publishTf>1</publishTf>
<publishWheelJointState>true</publishWheelJointState>
<alwaysOn>true</alwaysOn>
<updateRate>100.0</updateRate>
<legacyMode>true</legacyMode>
<leftJoint>left_wheel_joint</leftJoint> <!-- 控制得joint在哪里,必须和上面得joint名称一致 -->
<rightJoint>right_wheel_joint</rightJoint><!-- 控制得joint在哪里,必须和上面得joint名称一致 -->
<wheelSeparation>${wheel_joint_y*2}</wheelSeparation><!-- 两个轮子得间距 -->
<wheelDiameter>${2*wheel_radius}</wheelDiameter>
<broadcastTF>1</broadcastTF>
<wheelTorque>30</wheelTorque>
<wheelAcceleration>1.8</wheelAcceleration>
<commandTopic>cmd_vel</commandTopic> <!-- 订阅得话题:速度控制指令 -->
<odometryFrame>odom</odometryFrame>
<odometryTopic>odom</odometryTopic> <!-- 发布里程计信息 -->
<robotBaseFrame>base_footprint</robotBaseFrame><!-- 设置controler所控制的机器人的坐标系是哪个坐标系 -->
</plugin>
</gazebo>
sudo gedit mbot_gazebo.xacro
mbot_gazebo.xacro:
<?xml version="1.0"?>
<robot name="arm" xmlns:xacro="http://www.ros.org/wiki/xacro">
<xacro:include filename="$(find mbot_description)/urdf/xacro/gazebo/mbot_base_gazebo.xacro" /> <!-- 包含文件 -->
<mbot_base_gazebo/> <!-- 调用宏定义 -->
</robot>
launch文件:
cd ~/catkin_ws/src/mbot_description/launch/xacro
mkdir gazebo
cd gazebo
sudo gedit mbot_base_gazebo.launch
mbot_base_gazebo.launch:
<launch>
<!-- 设置launch文件的参数 -->
<arg name="paused" default="false"/>
<arg name="use_sim_time" default="true"/>
<arg name="gui" default="true"/>
<arg name="headless" default="false"/>
<arg name="debug" default="false"/>
<!-- 运行gazebo仿真环境 -->
<include file="$(find gazebo_ros)/launch/empty_world.launch">
<arg name="debug" value="$(arg debug)" />
<arg name="gui" value="$(arg gui)" />
<arg name="paused" value="$(arg paused)"/>
<arg name="use_sim_time" value="$(arg use_sim_time)"/>
<arg name="headless" value="$(arg headless)"/>
</include>
<!-- 加载机器人模型描述参数 -->
<param name="robot_description" command="$(find xacro)/xacro --inorder '$(find mbot_description)/urdf/xacro/gazebo/mbot_gazebo.xacro'" />
<!-- 运行joint_state_publisher节点,发布机器人的关节状态 -->
<node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" ></node>
<!-- 运行robot_state_publisher节点,发布tf -->
<node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" output="screen" >
<param name="publish_frequency" type="double" value="50.0" />
</node>
<!-- 在gazebo中加载机器人模型-->
<node name="urdf_spawner" pkg="gazebo_ros" type="spawn_model" respawn="false" output="screen"
args="-urdf -model mrobot -param robot_description"/>
</launch>
运行结果参考博客:https://blog.youkuaiyun.com/qq_43279579/article/details/115017677