【ROS21讲介绍】十三讲~二十一讲

ROS入门-笔记下,每一步都可以进行,新手必备,有问题可以留言,一起学习

本人跟着古月老师ROS入门21讲进行,汇集了本人的笔记,每一步都有代码,以及其中的代码实现和小误区,和古月老师的视频搭配观看效果最佳,b站就可以找到视频,本人总结的第一讲到第十二讲也可以参考~

十三、客户端Client的编程实现

1、话题模型

本讲我们所实现的服务话题模型为:
在这里插入图片描述
实现在海归模拟器中生成了一只新的海龟,server端是我们的海龟仿真器,Client发送一个生成新海龟的请求给server端,收到请求后产生新海龟,反馈一个response。消息为/spawn。

2、创建功能包

创建功能包指令:

cd ~/catkin_ws/src
catkin_create_pkg learning_service roscpp rospy std_msgs geometry_msgs turtlesim

3、创建客户端代码(C++)

客户端turtle_spawn.cpp代码如下:

/**
* 该例程将请求/spawn服务,服务数据类型turtlesim::Spawn
*/

#include <ros/ros.h>
#include <turtlesim/Spawn.h>

int main(int argc, char** argv)
{
    //初始化ROS节点
    ros::init(argc, argv, "turtle_spawn");
    
    //创建节点句柄
    ros::NodeHandle node;

    //发现/spawn服务后,创建一个服务客户端,链接名为/spawn的service
    ros::service::waitForService("/spawn");
    ros::ServiceClient add_turtle = node.serviceClient<turtlesim::Spawn>("/spawn");

    //初始化turtlesim::Spawn的请求数据
    turtlesim::Spawn srv;
    srv.request.x = 2.0;
    srv.request.y = 2.0;
    srv.request.name = "turtles2";

    //请求服务调用
    ROS_INFO("Call service to spawn turtle[x:%0.6f , y:%0.6f , name:%s]", srv.request.x,srv.request.y,srv.request.name.c_str());
    add_turtle.call(srv);

    //显示服务调用结果
    ROS_INFO("Spawn turtle successfully [name:%s]",srv.response.name.c_str());

    return 0;
}

同样我们要养成写完一个cpp文件创建节点就要在CmakeLists.txt文件里加上代码:

add_executable(turtle_spawn src/turtle_spawn.cpp)
target_link_libraries(turtle_spawn ${catkin_LIBRARIES} )

至此,客户端创建完成,编译可看到节点出现
然后编译运行即可:

cd ~/catkin_ws
catkin_make
source devel/setup.bash
roscore

新开终端
rosrun turtlesim turtlesim_node

新开终端运行我们的节点
rosrun learning_service turtle_spawn

这里我运行之后发现一直等待/spawn:
waitForService: Service [/spawm] has not been advertised, waiting...
检查了好久发现打错了,打成了/spawm,所以如果出现问题,我们首先要检查我们是否打错了,以及错误信息里都会有说。

十四、服务端Server的编程实现

1、服务模型

在这里插入图片描述
本讲是实现Service功能,主要是给海龟发送速度的指令,通过topic来发,client发布request控制是不是要和海龟发指令,让它动起来,相当于海龟的开关,发一个request海归运动,再发一个停止,server来接受开关的指令,并完成海龟运动topic指令的发送,service名字是自定义的/turtle_command,关于消息数据类型定义是Trigger触发信号,服务端既包含一个service的实现,也会包含一个发布者的实现。

2、实现代码

turtle_command_server.cpp代码为:

/**
 * 该例程将执行/turtle_command服务,服务数据类型std_srvs/Trigger
 */

 #include <ros/ros.h>
 #include <geometry_msgs/Twist.h>
 #include <std_srvs/Trigger.h>

 ros::Publisher turtle_vel_pub;
 bool pubCommand = false;

 //service回调函数,输入参数req,输出参数res
 bool commandCallback(std_srvs::Trigger::Request &req, std_srvs::Trigger::Response &res)
 {
     pubCommand = !pubCommand;

     //显示请求数据
     ROS_INFO("Publish turtle velocity command [%s]", pubCommand==true?"Yse":"No");

     //设置反馈数据
     res.success = true;
     res.message = "Change turtle command state!";
     
     return true;
 }

 int main(int argc, char **argv)
 {
     //ROS节点初始化
     ros::init(argc, argv, "turtle_command_server");
     
     //创建节点句柄
     ros::NodeHandle n;

     //创建一个名为/turtle_command的server,注册回调函数commandCallback
     ros::ServiceServer command_service = n.advertiseService("/turtle_command", commandCallback);

     //创建一个Publisher,发布名为/turtle1/cmd_vel的topic,消息类型为geometry_msgs::Twist ,队列长度为10
     turtle_vel_pub = n.advertise<geometry_msgs::Twist>("/turtlr1/cmd_vel",10);
     
     //循环等待回调函数
     ROS_INFO("Ready to receive turtle command.");

     //设置循环的频率
     ros::Rate loop_rate(10);

     while (ros::ok())
     {
         //查看一次回调函数队列
         ros::spinOnce();

         //如果标志为true,则发布速度指令
         if(pubCommand)
         {
             geometry_msgs::Twist vel_msg;
             vel_msg.linear.x = 0.5;
             vel_msg.angular.z = 0.2;
             turtle_vel_pub.publish(vel_msg);
         }
         //按照循环频率延时
         loop_rate.sleep();
     }
     return 0;
 }

同样,这里也需要在CMakeLists.txt文件里加上:

add_executable(turtle_command_server src/turtle_command_server.cpp)
target_link_libraries(turtle_command_server ${catkin_LIBRARIES} )

3、编译代码并运行

cd ~/catkin_ws
catkin-make
source devel/setup.bash
roscore

新开终端
rosrun turtlesim turtlesim_node

新开终端
rosrun learning_service turtle_command_server

新开终端
rosservice call /turtle_command "{}"

可以看到执行最后一句命令,小乌龟开始移动。

十五、服务数据的定义与使用

1、服务模型

在这里插入图片描述
这里可以每request一次,发布一次,同时判断是否发送成功;client要发布显示人信息的请求,信息发出去,service会接受请求和信息,再通过response反馈显示结果;这里用到的service是自定义的/show_person;用到的数据类型是learning_service::Person,这是这一讲马上要定义的服务数据类型,也就是要实现的案例。

2、自定义服务数据

2.1、定义srv文件:
在路径~/catkin_ws/src/learning_service/下新建文件夹srv,然后在srv/下创建一个新的文件Person.srv(注意首字母大写),然后该文件内容为:

string name
uint8 age
uint8 sex

uint8 unknown = 0
uint8 male = 1
uint8 female = 2
---
string result
  • 三个横杠之上是request数据,三个横杠之下是response数据

2.2、在package.xml中添加功能包依赖

<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>

2.3、在CMakeLists.txt添加编译选项

* find_package( ...... message_generation)
* add_service_files(FILES Person.srv)
//自动搜索srv文件夹下的文件
	generate_message(DEPENDENCIES std_msgs)
//根据文件的定义依赖来产生对应的头文件
* catkin_package( ...... message_runtime)
//这里建议是
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES learning_service
  CATKIN_DEPENDS geometry_msgs roscpp rospy std_msgs turtlesim message_runtime
#  DEPENDS system_lib
)

在这里插入图片描述
会发现编译成三个文件,横杠上面编译成一个文件,横杠下面编译成一个文件,第一个文件包含后面两个,实际用的时候一般只用第一个就可以

2.4、编译生成语言相关文件

cd catkin_ws
catkin_make

那么如何查看service文件编译之后的结果?
在路径~/catkin_ws/devel/include/learning_service/下可以看到编译成了三个.h文件

3 使用自定义的服务数据

  1. 首先在learning_service/src文件下创建两个文件:person_client.cpp和person_server.cpp
  2. person_client.cpp
/**
 * 该例程将请求/show_person服务,服务数据类型learning_service::Person
 */

#include <ros/ros.h>
#include "learning_service/Person.h"

int main(int argc, char** argv)
{
    // 初始化ROS节点
	ros::init(argc, argv, "person_client");

    // 创建节点句柄
	ros::NodeHandle node;

    // 发现/show_person服务后,创建一个服务客户端,连接名为/show_person的service
	ros::service::waitForService("/show_person");
	ros::ServiceClient person_client = node.serviceClient<learning_service::Person>("/show_person");

    // 初始化learning_service::Person的请求数据
	learning_service::Person srv;
	srv.request.name = "Tom";
	srv.request.age  = 20;
	srv.request.sex  = learning_service::Person::Request::male;

    // 请求服务调用
	ROS_INFO("Call service to show person[name:%s, age:%d, sex:%d]", 
			 srv.request.name.c_str(), srv.request.age, srv.request.sex);

	person_client.call(srv);

	// 显示服务调用结果
	ROS_INFO("Show person result : %s", srv.response.result.c_str());

	return 0;
};


  1. person_server.cpp
/**

 * 该例程将执行/show_person服务,服务数据类型learning_service::Person

 */

 

#include <ros/ros.h>

#include "learning_service/Person.h"



// service回调函数,输入参数req,输出参数res

bool personCallback(learning_service::Person::Request  &req,

         			learning_service::Person::Response &res)

{

    // 显示请求数据

    ROS_INFO("Person: name:%s  age:%d  sex:%d", req.name.c_str(), req.age, req.sex);



	// 设置反馈数据

	res.result = "OK";



    return true;

}



int main(int argc, char **argv)

{

    // ROS节点初始化

    ros::init(argc, argv, "person_server");



    // 创建节点句柄

    ros::NodeHandle n;



    // 创建一个名为/show_person的server,注册回调函数personCallback

    ros::ServiceServer person_service = n.advertiseService("/show_person", personCallback);



    // 循环等待回调函数

    ROS_INFO("Ready to show person informtion.");

    ros::spin();



    return 0;

}
  1. 既然创建了两个节点,那自然要修改外面的CMakeLists.txt,添加上:
add_executable(person_client src/person_client.cpp)
add_executable(person_server src/person_server.cpp)
#add_dependencies(person_server ${PROJECT_NAME}_gencpp)
#注释的这一句话,我的没加也可以运行,当然加了也可以,这句是动态依赖

target_link_libraries(person_client ${catkin_LIBRARIES})
target_link_libraries(person_server ${catkin_LIBRARIES})
#add_dependencies(person_client ${PROJECT_NAME}_gencpp)
#注释的这一句话,我的没加也可以运行
  1. 然后编译成功
    在catkin_ws路径下执行catkin_make
    在这里插入图片描述

6.运行
分别启动三个终端,然后分别执行

roscore
rosrun 

在这里插入图片描述

十六、ROS通信编程-动作编程

1、什么是动作(action)

  • 一种问答通信机制
  • 带有连续反馈
  • 可以在任务过程中止运行
  • 基于ROS的消息机制实现

2、Action的接口

  • goal:发布任务目标;
  • cancel:请求取消任务;
  • status:通知客户端当前的状态
  • feedback:周期反馈任务运行的监控数据
  • result:向客户端发送任务的执行结果,只发布一次

3、自定义动作消息

  1. 首先在功能包下创建action文件夹
  2. 然后在该文件夹下创建文件DoDishes.action
# 定义目标信息
uint32 dishwasher_id
# Specify which dishwasher we want to use
---
# 定义结果信息
uint32 total_dishes_cleaned
---
# 定义周期反馈的消息
float32 percent_complete

4、在package.xml中添加功能包依赖

  <build_depend>actionlib</build_depend>
  <build_depend>actionlib_msgs</build_depend>
  <exec_depend>actionlib</exec_depend>
  <exec_depend>actionlib_msgs</exec_depend>

5、在CMakeLists.txt添加编译选项

在这里插入图片描述

6、下面实例演示创建服务和客户端文件

首先是在src文件夹下创建文件DoDishes_client.cpp

#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& feedback)
{
    ROS_INFO(" percent_complete : %f ", feedback->percent_complete);
}

int main(int argc, char** argv)
{
    ros::init(argc, argv, "do_dishes_client");

    // 定义一个客户端
    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;
}

然后是创建DoDishes_server.cpp

#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& goal, Server* as)
{
    ros::Rate r(1);
    learning_communication::DoDishesFeedback feedback;

    ROS_INFO("Dishwasher %d is working.", goal->dishwasher_id);

    // 假设洗盘子的进度,并且按照1hz的频率发布进度feedback
    for(int i=1; i<=10; i++)
    {
        feedback.percent_complete = i * 10;
        as->publishFeedback(feedback);
        r.sleep();
    }

    // 当action完成后,向客户端返回结果
    ROS_INFO("Dishwasher %d finish working.", goal->dishwasher_id);
    as->setSucceeded();
}

int main(int argc, char** argv)
{
    ros::init(argc, argv, "do_dishes_server");
    ros::NodeHandle n;

    // 定义一个服务器
    Server server(n, "do_dishes", boost::bind(&execute, _1, &server), false);
    
    // 服务器开始运行
    server.start();

    ros::spin();

    return 0;
}

7、添加链接


add_executable(DoDishes_client src/DoDishes_client.cpp)
target_link_libraries( DoDishes_client ${catkin_LIBRARIES})
add_dependencies(DoDishes_client ${${PROJECT_NAME}_EXPORTED_TARGETS})

add_executable(DoDishes_server src/DoDishes_server.cpp)
target_link_libraries( DoDishes_server ${catkin_LIBRARIES})
add_dependencies(DoDishes_server ${${PROJECT_NAME}_EXPORTED_TARGETS})

然后编译就可以啦

8、运行历程

roscore
rosrun learning_communication DoDishes_client
rosrun learning_communication DoDishes_server

十七、分布式通信(目前仅一台电脑,没有)

  • ROS是一种分布式软件框架,节点之间通过松耦合的方式进行组合
  • 如何实现分布式多机通信
  1. 设置IP地址,确保底层链路的联通(得需要两台主机)暂时先不看吧,回校再看

十八、参数的使用与编程方法

1、参数模型

在这里插入图片描述
里面的参数可供所有的节点使用,Parameter Server可以简易的理解为一个全局的存储空间

2、创建功能包

cd ~/catkin_ws/src
catkin_create_pkg learning_parameter roscpp rospy std_srvs

3、参数命令行rosparam使用

3.1、列出当前多少参数

rosparam list

3.2、显示某个参数值

rosparam get param_key

3.3、设置某个参数值

rosparam set param_key param_value

3.4、保存参数到文件

rosparam dump file_name

3.5、从文件读取参数

rosparam load file_name

3.6、删除参数

rosparam delete param_key

4、YAML参数文件

可以把当前的参数都保存进一个yaml文件格式里面:

#在当前运行的前提下
rosparam dump param.yaml

5、参数使用实战

1、首先运行小海龟节点
然后进行rosparam实验:
首先代码:

rosparam list

结果为列出所有的参数:

/rosdistro
/roslaunch/uris/host_bupo_vpc__46285
/rosversion
/run_id
/turtlesim/background_b
/turtlesim/background_g
/turtlesim/background_r

代码:

rosparam get /background_b

结果为显示出该参数的值:

255

代码:

rosparam set /background_b 100

结果为设置该参数的值为100
这里我们修改了小乌龟背景的rgb值,但是并未发生变化,这是因为我们还需要发送一个请求

rosservice call /clear "{}"

就可以看到小乌龟的蓝色背景发生了改变

此时保存当前的参数为

rosparam dump param.yaml

这个文件保存在所执行命令的路径下
在这里插入图片描述
可以加载这个文件,在当前路径下加载:

rosparam load param.yaml

6、编程方法

1、如何获取/设置参数

  • 初始化ROS节点
  • get函数获取参数
  • set函数设置参数

2、在learning_parameter/src路径下创建parameter_config.cpp文件,代码为:

/**
 * 该例程设置/读取海龟例程中的参数
 */
#include <string>
#include <ros/ros.h>
#include <std_srvs/Empty.h>
int main(int argc, char **argv)
{
	int red, green, blue;


    // ROS节点初始化
    ros::init(argc, argv, "parameter_config");


    // 创建节点句柄
    ros::NodeHandle node;

    // 读取背景颜色参数
	ros::param::get("/turtlesim/background_r", red);
	ros::param::get("/turtlesim/background_g", green);
	ros::param::get("/turtlesim/background_b", blue);

	ROS_INFO("Get Backgroud Color[%d, %d, %d]", red, green, blue);


	// 设置背景颜色参数
	ros::param::set("/turtlesim/background_r", 255);
	ros::param::set("/turtlesim/background_g", 255);
	ros::param::set("/turtlesim/background_b", 255);

	ROS_INFO("Set Backgroud Color[255, 255, 255]");

    // 读取背景颜色参数
	ros::param::get("/turtlesim/background_r", red);
	ros::param::get("/turtlesim/background_g", green);
	ros::param::get("/turtlesim/background_b", blue);

	ROS_INFO("Re-get Backgroud Color[%d, %d, %d]", red, green, blue);


	// 调用服务,刷新背景颜色
	ros::service::waitForService("/clear");
	ros::ServiceClient clear_background = node.serviceClient<std_srvs::Empty>("/clear");
	std_srvs::Empty srv;
	clear_background.call(srv);

	sleep(1);
    return 0;
}

7、配置编译规则

同样在CMakeLists.txt文件中加上:

add_executable(parameter_config src/parameter_config.cpp)
target_link_libraries(parameter_config ${catkin_LIBRARIES})

8、编译并运行发布

cd ~/catkin_ws
catkin-make
source devel/setup.bash
roscore

新开终端
rosrun turtlesim turtlesim_node

新开终端
rosrun learning_parameter parameter_config

十九、ROS中的坐标系管理系统

从这一讲开始我们将进入一个大的板块,ros中常用的组件
在这里插入图片描述
在这里插入图片描述

1、机器人中的坐标变换

例程:

sudo apt-get install ros-kinetic-turtle-tf # melodic
//这里注意用自己的ros版本
roslaunch turtle_tf turtle_tf_demo.launch
rosrun turtlesim turtle_teleop_key

可以看到两只小海龟,后面那只会一直跟着前面那只

2、实现原理分析-查看tf关系

可以直接可视化看到系统中所有tf的关系

rosrun tf view_frames

会把五秒钟之内所有的坐标系关系保存成一个pdf,在当前路径下
在这里插入图片描述

  • world 是世界坐标系
  • 其他两个是两个小海龟的坐标系

3、tf_echo工具

可以更直接查询在树中任意两个坐标系的关系:

rosrun tf tf_echo turtle1 turtle2
# 跟坐标系   目标坐标系

//实现这个例子,因为我们采用的小乌龟例子,所以得运行小乌龟跟踪demo
translation平移,xyz描述
rotationx旋转,三种描述方法:

  • 四元数(quaterntion):xyzw
  • RPY(弧度) 绕xyz旋转
  • RPY(角度)

4、tf中rviz

3V可视化显示平台

rosrun rviz rviz -d `rospack find turtle_tf`/rviz/turtle_rviz.rviz

在这里插入图片描述
Fixde Frame要选择world;添加一个TF
底层代码实现原理请看下一讲

十八、tf坐标系广播与监听的编程实现

1、创建功能包

cd ~/catkin_ws/src/
catkin_create_pkg learning_tf roscpp rospy tf turtlesim

2、创建一个tf广播器

1、如何实现一个tf广播器

  • 定义TF广播器(TranformBroadcaster)
  • 创建坐标变换值
  • 发布坐标变换(sendTransform)

2、创建turtle_tf_broadcaster.cpp文件在上述包里,代码如下:

/**
 * 该例程产生tf数据,并计算、发布turtle2的速度指令
 */

#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数据
	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);

	// 广播world与海龟坐标系之间的tf数据
	br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "world", turtle_name));
}

int main(int argc, char** argv)
{
    // 初始化ROS节点
	ros::init(argc, argv, "turtle_tf_broadcaster");

	// 输入参数作为海龟的名字
	if (argc != 2)
	{
		ROS_ERROR("need turtle name as argument"); 
		return -1;
	}

	turtle_name = argv[1];

	// 订阅海龟的位姿话题
	ros::NodeHandle node;
	ros::Subscriber sub = node.subscribe(turtle_name+"/pose", 10, &poseCallback); 
	//这里第一个是指话题,如turtle1/pose或者turtle2/pose

    // 循环等待回调函数
	ros::spin();

	return 0;
};

3、创建一个TF监听器

1、如何实现一个TF监听器

  • 定义TF监听器(TransformListenr)
  • 查找坐标变换(waitForTransform、lookupTrandform)

2、创建turtle_tf_listener.cpp文件在上述包里,代码如下:

/**
 * 该例程监听tf数据,并计算、发布turtle2的速度指令
 */

#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节点
	ros::init(argc, argv, "turtle_tf_listener");

    // 创建节点句柄
	ros::NodeHandle node;

	// 请求产生turtle2
	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())
	{
		// 获取turtle1与turtle2坐标系之间的tf数据
		tf::StampedTransform transform;
		try
		{
			listener.waitForTransform("/turtle2", "/turtle1", ros::Time(0), ros::Duration(3.0));
			listener.lookupTransform("/turtle2", "/turtle1", ros::Time(0), transform);
		}
		catch (tf::TransformException &ex) 
		{
			ROS_ERROR("%s",ex.what());
			ros::Duration(1.0).sleep();
			continue;
		}

		// 根据turtle1与turtle2坐标系之间的位置关系,发布turtle2的速度控制指令
		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;
};

4、配置编译规则

同样是在CMakeLists.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})

5、编译执行

cd ~/catkin_ws
catkin_make
source devel/setup.bash
roscore

新开终端
rosrun turtlesim turtlesim_node

新开终端
rosrun learning_tf turtle_tf_broadcaster __name:=turtle1_tf_broadcaster /turtle1

新开终端,这里用到了重映射,也就是给节点重新起名字为turtle2_tf_broadcaster,还要注意__name这是两个_(下划线)
rosrun learning_tf turtle_tf_broadcaster __name:=turtle2_tf_broadcaster /turtle2

新开终端
rosrun learning_tf turtle_tf_listener

新开终端
rosrun turtlesim turtle_teleop_key

6、创建start_demo_with_listener.launch文件

二十、launch启动文件的使用方法

1、launch节点的作用

1、可以启动多个节点,避免打开一堆终端
2、可以在自动启动ROS Master
3、launch文件,通过XML文件实现多节点的配置和启动

2、Launch文件的常用语法

2.1、launch最简单的格式

<launch>
	<node pkg="turtlesim" name="sim1" type="turtlesim_node"/>
	<node pkg="turtlesim" name="sim2" type="turtlesim_node"/>
<launch>

< launch > launch 文件中的根元素采用< launch >标签定义

2.2、< node >

启动节点

 <node pkg="package-name" type="executable-name" name="node-name"/>
  • pkg : 节点所在的功能包名称
  • type :节点的可执行文件名称
  • name:节点运行时的名称
  • output:用来控制某个节点是不是要把日信息打印到终端去
  • respawn:控制节点启动运行突然关闭,是否重启
  • required:launch文件某个节点是不是一定要启动起来
  • ns:命名空间,每个节点都可以有
  • args:输入参数

2.3、< param> / < rosparam>

设置ROS系统运行中的参数,存储在参数服务器中。

<param name="output_frame" value="odom"/>
  • name:参数名
  • value:参数值
    加载参数文件中的多参数
<rosparam file="params.yaml" command="load" ns="params">

2.4、< arg>

launch文件内部的局部变量,仅限于launch文件使用

<arg name="arg-name" default="arg-value"/>
  • name:参数名
  • value:参数值
    调用:
<param name="foo" value="$(arg arg-name)"/>
# arg-name 是参数名字
<node name="node" pkg="package" type="type" args="$(arg arg-name)"/>

2.5、< remap>

重映射ROS计算图资料的命名。

<remap from="/turtlebot/cmd_vel" to="/cmd_vel"/>
  • from:原命名
  • to:映射之后的命名

2.6、< include>

包含并启动其他launch文件,类似C语言中的头文件包含。

<include file="$(dirname)/other.launch"/>
  • file:包含的其他launch文件路径

2.7、其他

,这里只是介绍了一小小部分。其他更多标签参见http://wiki.ros.org/roslaunch/XML

3、launch实例四个讲解

3.1、首先在/catkin_ws/src下创建一个功能包:

catkin_create_pkg learning_launch

他本身不需要任何依赖,因为他是系统文件

3.2、在该包里创建一个文件夹叫launch,这个名字不一定非是launch,可以自定义,但一般都是叫这个,没必要自定义

simple.launch

3.3、在launch文件夹里创建一个simple.launch文件,代码为:

<launch>
    <node pkg="learning_topic" type="person_subscriber" name="talker" output="screen" />
    <node pkg="learning_topic" type="person_publisher" name="listener" output="screen" /> 
</launch>

这里的output=“screen”是日信息打印出来

3.4、启动该launch文件:

roslaunch learning_launch simple.launch

turtlesim_parameter_config.launch

3.5、创建一个配置参数的turtlesim_parameter_config.launch文件,代码为:

<launch>

	<param name="/turtle_number"   value="2"/>
	//存到参数服务器来
    <node pkg="turtlesim" type="turtlesim_node" name="turtlesim_node">
		<param name="turtle_name1"   value="Tom"/>
		<param name="turtle_name2"   value="Jerry"/>

		<rosparam file="$(find learning_launch)/config/param.yaml" command="load"/>
		//输出一个完整路径
	</node>

    <node pkg="turtlesim" type="turtle_teleop_key" name="turtle_teleop_key" output="screen"/>

</launch>

3.5、这里我们给提供了一个config/param.yaml,如果没有它的源码,也可以自己创建,很简单,首先在路径learning_launch路径下创建一个文件夹config,然后在里面创建文件param.yaml,里面的代码为:

A: 123
B: "hello"

group:
  C: 456
  D: "hello"

3.6、然后运行该launch文件:

roslaunch learning_launch turtlesim_parameter_config.launch 

会出现小乌龟节点,且可以通过键盘控制,除此之外,配置的参数已经发生改变,我们额可以查看:

rosparam list
结果为:
/background_b
/background_g
/background_r
/rosdistro
/roslaunch/uris/host_ros_vm__40421
/rosversion
/run_id
/turtle_number
/turtlesim_node/A
/turtlesim_node/B
/turtlesim_node/group/C
/turtlesim_node/group/D
/turtlesim_node/turtle_name1
/turtlesim_node/turtle_name2

//可以看到放在node下的参数前面带有一个node的前缀,优先加节点名为命名空间,其次加后面的设置,文件的设置等,紧接着加参数
查看参数
rosparam get /turtle_number 
//2

start_tf_demo_c++.launch

3.7、创建一个配置参数的start_tf_demo_c++.launch文件,代码为:

 <launch>

    <!-- Turtlesim Node-->
    <node pkg="turtlesim" type="turtlesim_node" name="sim"/>
    <node pkg="turtlesim" type="turtle_teleop_key" name="teleop" output="screen"/>

    <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" />

    <node pkg="learning_tf" type="turtle_tf_listener" name="listener" />

  </launch>


turtlesim_remap.launch

3.8、创建一个配置参数的turtlesim_remap.launch文件,代码为:

<launch>

	<include file="$(find learning_launch)/launch/simple.launch" />

    <node pkg="turtlesim" type="turtlesim_node" name="turtlesim_node">
		<remap from="/turtle1/cmd_vel" to="/cmd_vel"/>
	</node>

</launch>

二十一、常用可视化工具的使用

1、Qt工具箱

以海归历程为例

roscore
rosrun turtlesim turtlesim_node 
rosrun turtlesim turtle_teleop_key 

1.1、rqt_console 日志输出工具

在这里插入图片描述

1.2、rqt_graph 计算图可视化工具

在这里插入图片描述

1.3、rqt_plot 数据绘图工具

在这里插入图片描述

1.4、rqt_image_view 图像渲染工具

在这里插入图片描述

1.5 rosrun rqt_tf_tree rqt_tf_tree TF树

rosrun rqt_tf_tree rqt_tf_tree       

2、rqt实例

2.1、首先启动:

roscore

2.2、然后启动:

rosrun turtlesim turtlesim_node 

rqt_console

2.3、再启动:

 rqt_console 

结果:
在这里插入图片描述
打开后就会默认收集日志信息

rqt_plot

2.4、再启动

rqt_plot 

在这里插入图片描述
输入要看的topic再回车就可以看到所有信息都刷新起来

rqt_image_view

2.5、再启动

rqt_image_view

在这里插入图片描述
这是用来显示摄像头图像的

rqt

2.6、再启动

rqt

启动综合可视化界面,可以打开其他的,在上面的Plugins里

3、rviz

机器人开发过程中的数据可视化界面
指令(首先要启动roscore才可以启动rviz):

rviz

打开可以看到
在这里插入图片描述

4、Gazebo

4.1、Gazebo介绍
Gazebo是一款功能强大的三维物理仿真平台

  • 具备强大的物理引擎
  • 高质量的图形渲染
  • 方便的编程与图形接口
  • 开源免费

4.2、启动Gazebo
先尝试启动一个空环境

roslaunch gazebo_ros empty_world.launch

我的电脑启动不起来,会报错
看解决方案
https://blog.csdn.net/lzw508170827/article/details/108308433

以及

https://blog.csdn.net/weixin_45839124/article/details/106367520

这是两种问题都要解决,刚好上面两种方案,启动空的没问题,再尝试启动下面这个,会加载好长时间

roslaunch gazebo_ros willowgarage_world.launch

在这里插入图片描述

4.3. 如何使用gazebo进行仿真

  • 创建仿真环境

  • 配置机器人模型

  • 开始仿真

二十二、课程总结与进阶攻略-结束了吗还没开始喃

资源整理
1、斯坦福大学公开课-机器人学

https://www.bilibili.com/video/av4506104/
2、交通大学-机器人学

3、在这里插入图片描述
在这里插入图片描述

总结

至此,为期五天的学习结束啦,小伙伴们有问题可以留言,一起讨论呀!

二十三、补充知识点

23.1 得到对所发布的数据进行订阅的数量getNumSubscribers

		ros::Publisher pubSegmentedCloudPure;
		pubSegmentedCloudPure = nh.advertise<sensor_msgs::PointCloud2> ("/segmented_cloud_pure", 1);
        if (pubSegmentedCloudPure.getNumSubscribers() != 0){
        }
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值