文章目录
Linux系统基础操作
ROS安装
ROS核心概念
ROS命令行工具的使用
创作工作空间与功能包
发布者Publisher的编程实现
订阅者Subscriber的编程实现
话题消息的定义与使用
客户端Client的编程实现
服务端Server的编程实现
服务数据的定义与使用
参数的使用与编程方法
TF坐标系广播与监听的编程实现
launch启动文件的使用方法
常用可视化工具的使用
进阶攻略
Linux系统基础操作
cd命令
语法:cd<目录路径>
功能:改变工作目录.若没有指定’目录路径’,则回到用户的主目录
pwd命令
语法:pwd
功能:此命令显示当前工作目录的绝对路径.
mkdir命令
语法:mkdir[选项]<目录名称>
功能:创建一个目录.
ls命令
语法:ls[选项]<目录名称>
功能:列出目录的内容
touch命令
语法:touch[选项]<目录名称>
功能:改变文件或目录时间.
mv命令
语法:mv[选项]<源文件或目录><目的文件或目录>
功能:为文件或目录改名或将文件由一个目录移入另一个目录中
cp命令
语法:cp[选项]<源文件名称或目录名称><目的文件名称或目录名称>
功能:把给出的一个文件或目录拷贝到另一文件目录中,或者把多个源文件复制到目标目录中.
rm命令
语法:rm[选项]<文件名称或目录名称…>
功能:该命令的功能为删除一个目录中的一个或者多个文件或目录,它也可以将某个目录及其下的所有文件及子目录均删除.对于链接文件,只是删除了链接,原有文件均保持不变.
sudo命令
语法:sudo[选项][指令]
功能:以其他身份来执行指令.

ROS安装

1.软件和更新>ubuntu软件>点选前四个>选择合适的源>应用并重新载入
2.安装源(Ubuntu20.04)
sudo sh -c '. /etc/lsb-release && echo "deb http://mirrors.tuna.tsinghua.edu.cn/ros/ubuntu/ `lsb_release -cs` main" > /etc/apt/sources.list.d/ros-latest.list'
3.添加keys
sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654
4.更新软件源
sudo apt update
5.安装
sudo apt-get install ros-noetic-desktop-full
6.配置变量
source /opt/ros/noetic/setup.bash
7.环境配置
echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc
source ~/.bashrc

ROS核心概念
节点(Node) --执行单元
*执行具体任务的进程,独立运行的可执行文件;
*不同节点可使用不同的编程语言,可分布运行在不同的主机;
*节点在系统中的名称必须是唯一的.

节点管理器(ROS Master) --控制中心
*为节点提供命名和注册服务;
*跟踪和记录话题/服务通信,辅助节点互相查找,建立连接;
*提供参数服务器,节点使用此服务器存储和检索时的参数.

话题(Topic) --异步通信机制
*节点间用来传输数据的重要总线;
*使用发布/订阅模型,数据由发布者传输到订阅者,同一个话题的订阅者或发布者可以不唯一.

消息(Mwssage) --话题数据
*具有一定的类型和数据结构,包括ROS提供的标准类型和用户自定义类型;
*使用编程语言无关的.msg文件,编译过程中生成对应的代码文件.

服务(Service) --同步通信机制
*使用客户端/服务器(C/S)模型,客户端发送请求数据,服务器完成处理后返回问答数据;
*使用编程语言无关的.srv文件定义请求和应答数据结构,编译过程中生成对应的代码文件.

参数(Parameter) --全局共享字典
*可通过网络访问的共享,多变量字典;
*节点使用此服务器来储存和检索运行时的参数;
*适合存储静态,非二进制的配置参数,不适合存储动态配置的数据.

功能包(Package)
*ROS软件中的基本单元,包含节点源码,配置文件,数据定义等

功能包清单(Package manifest)
*记录功能包的基本信息,包含作者信息,许可信息,依赖选项.编译标志等

元功能包(Meta Packages)
*组织多个用于同一目的的功能包

ROS命令行工具的使用
启动ROS Master

roscore

启动小海龟仿真器

rosrun turtlesim turtlesim_node

启动海龟控制节点

rosrun turtlesim turtle_teleop_key

显示系统计算图

rqt_graph

显示系统节点相关信息

   rosnode
rosnode is a command-line tool for printing information about ROS Nodes.

Commands:
	rosnode ping	test connectivity to node
	rosnode list	list active nodes
	rosnode info	print information about node
	rosnode machine	list nodes running on a particular machine or list machines
	rosnode kill	kill a running node
	rosnode cleanup	purge registration information of unreachable nodes

显示系统话题相关信息

rostopic
rostopic is a command-line tool for printing information about ROS Topics.

Commands:
	rostopic bw	    display bandwidth used by topic
	rostopic delay	display delay of topic from timestamp in header
	rostopic echo	print messages to screen
	rostopic find	find topics by type
	rostopic hz	    display publishing rate of topic    
	rostopic info	print information about active topic
	rostopic list	list active topics
	rostopic pub	publish data to topic
	rostopic type	print topic or field type

显示系统消息相关信息

rosmsg
rosmsg is a command-line tool for displaying information about ROS Message types.

Commands:
	rosmsg show	    Show message description
	rosmsg info	    Alias for rosmsg show
	rosmsg list	    List all messages
	rosmsg md5	    Display message md5sum
	rosmsg package	List messages in a package
	rosmsg packages	List packages that contain messages

显示系统服务相关信息

rosservice 
Commands:
	rosservice args	print service arguments
	rosservice call	call the service with the provided args
	rosservice find	find services by service type
	rosservice info	print information about service
	rosservice list	list active services
	rosservice type	print service type
	rosservice uri	print service ROSRPC uri

数据记录.复现

rosbag
Usage: rosbag <subcommand> [options] [args]

A bag is a file format in ROS for storing ROS message data. The rosbag command can record, replay and manipulate bags.

Available subcommands:
   check  	    Determine whether a bag is playable in the current system, or if it can be migrated.
   compress  	Compress one or more bag files.
   decompress  	Decompress one or more bag files.
   decrypt  	Decrypt one or more bag files.
   encrypt  	Encrypt one or more bag files.
   filter  	    Filter the contents of the bag.
   fix  	    Repair the messages in a bag file so that it can be played in the current system.
   help  
   info  	    Summarize the contents of one or more bag files.
   play  	    Play back the contents of one or more bag files in a time-synchronized fashion.
   record  	    Record a bag file with the contents of specified topics.
   reindex  	Reindexes one or more bag files.

创作工作空间与功能包
工作空间(workspace)是一个存放工程开发相关文件的文件夹.
*src:代码空间(Source Space)
*build:编译空间(Build Space)
*devel:开发空间(Development Space)
*instll:安装空间(Install Space)
创建工作空间

mkdir catkin_ws
cd catkin_ws/
mkdir src
cd src/
catkin_init_workspace

编译工作空间

cd ..
catkin_make
catkin_make install

创建功能包

#语法
#catkin_create_pkg<package_name>[depend1][depend2][depend3]
cd src/
catkin_create_pkg test_pkg std_msgs rospy roscpp

编译功能包

cd ..
catkin_make

设置环境变量

source devel/setup.bash

检查环境变量

echo $ROS_PACKAGE_PATH

备注
同一个工作空间下,不允许存在同名功能包;
不同工作空间下,允许存在同名功能包.

发布者Publisher的编程实现

创建功能包

cd ~/catkin_ws/src
catkin_creat_pkg learning_topic roscpp rospy std_msgs geometry_msgs turtlesim

创建发布者代码(C++)
如何实现一个发布者
*初始化ROS节点
*向ROS Master注册节点信息,包括发布的话题名和话题中的消息类型
*创建消息数据
*按照一定频率循环发布消息

//创建cpp文件
cd learning_topic/src/
touch velocity_publisher.cpp
//代码
/**
 * 该例程将发布turtle1/cmd_vel话题,消息类型geometry_msgs::Twist
 */
 
#include <ros/ros.h>
#include <geometry_msgs/Twist.h>

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

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

    // 创建一个Publisher,发布名为/turtle1/cmd_vel的topic,消息类型为geometry_msgs::Twist,队列长度10
    ros::Publisher turtle_vel_pub = n.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel", 10);

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

    int count = 0;
    while (ros::ok())
    {
        // 初始化geometry_msgs::Twist类型的消息
        geometry_msgs::Twist vel_msg;
        vel_msg.linear.x = 0.5;
        vel_msg.angular.z = 0.2;

        // 发布消息
        turtle_vel_pub.publish(vel_msg);
        ROS_INFO("Publsh turtle velocity command[%0.2f m/s, %0.2f rad/s]", 
                vel_msg.linear.x, vel_msg.angular.z);

        // 按照循环频率延时
        loop_rate.sleep();
    }

    return 0;
}

配置发布者代码编译规则
如何配置CMakeLists.txt中的编译规则
*设置需要编译的代码和生成的可执行文件
*设置链接库.

//添加到# Install ##正上方
add_executable(velocity_publisher src/velocity_publisher.cpp)
target_link_libraries(velocity_publisher ${catkin_LIBRARIES})

编译并运行发布者

//编译
cd ~/catkin_ws
catkin_make
//打开home文件夹,ctrl+H显示隐藏文件,找到.bashrc文件
//打开.bashrc,并在文件的最后添加以下这段话
//source /home/tfb/catkin_ws/devel/setup.bash
//再重启终端即可。这样每次编译(catkin_make)之后就不需要再写source devel/setup.bash了
source devel/setup.bash
roscore
//新开一个终端,开启turtlesim
rosrun turtlesim turtlesim_node
//新开一个终端,运行发布者cpp程序
rosrun learning_topic velocity_publisher
//编译cpp生成的文件在home/catkin_ws/devel/lib/learning_topic下面

备注
错误:[rospack] Error: package ‘learning_service’ not found
解决方案:
手动配置环境变量,具体操作如下
//打开home文件夹,ctrl+H显示隐藏文件,找到.bashrc文件
//打开.bashrc,并在文件的最后添加以下这段话
//source /home/tfb/catkin_ws/devel/setup.bash
//再重启终端即可。这样每次编译(catkin_make)之后就不需要再写source devel/setup.bash了
python语言实现

#为了与cpp文件存放的地方——src文件夹区分。在/home/catkin_ws/src/learning_topic/下新建一个scripts文件夹,用来存放py文件
#创建py文件
touch velocity_publisher.py
#代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 该例程将发布turtle1/cmd_vel话题,消息类型geometry_msgs::Twist

import rospy
from geometry_msgs.msg import Twist

def velocity_publisher():
    # ROS节点初始化
    rospy.init_node('velocity_publisher', anonymous=True)

    # 创建一个Publisher,发布名为/turtle1/cmd_vel的topic,消息类型为geometry_msgs::Twist,队列长度10
    turtle_vel_pub = rospy.Publisher('/turtle1/cmd_vel', Twist, queue_size=10)

    #设置循环的频率
    rate = rospy.Rate(10) 

    while not rospy.is_shutdown():
        # 初始化geometry_msgs::Twist类型的消息
        vel_msg = Twist()
        vel_msg.linear.x = 0.5
        vel_msg.angular.z = 0.2

        # 发布消息
        turtle_vel_pub.publish(vel_msg)
        rospy.loginfo("Publsh turtle velocity command[%0.2f m/s, %0.2f rad/s]", 
                vel_msg.linear.x, vel_msg.angular.z)

        # 按照循环频率延时
        rate.sleep()

if __name__ == '__main__':
    try:
        velocity_publisher()
    except rospy.ROSInterruptException:
        pass

#在ros下运行python文件一定要注意待执行的python文件有可执行权限
#python不要配置代码编译规则
#其余步骤参考上述cpp文件流程

备注:
错误:import-im6.q16: not authorized `rospy’ @ error/constitute.c/WriteImage/1037.
解决方案:
在py文件前面添加#!/usr/bin/env python
#!/usr/bin/env python这种用法是为了防止操作系统用户没有将python装在默认的/usr/bin路径里。 当系统看到这一行的时候,首先会到env设置(环境变量)里查找python的安装路径,再调用对应路径下的解释器程序完成操作。

订阅者Subscriber的编程实现
创建订阅者代码(C++)
如何实现一个订阅者
*初始化ROS节点;
*订阅需要的话题;
*循环等待话题消息,接受到消息后进入回调函数;
*在回调函数中完成消息处理.

//创建cpp文件
cd learning_topic/src/
touch velocity_publisher.cpp
//代码
/**
 * 该例程将订阅/turtle1/pose话题,消息类型turtlesim::Pose
 */
 
#include <ros/ros.h>
#include "turtlesim/Pose.h"

// 接收到订阅的消息后,会进入消息回调函数
void poseCallback(const turtlesim::Pose::ConstPtr& msg)
{
    // 将接收到的消息打印出来
    ROS_INFO("Turtle pose: x:%0.6f, y:%0.6f", msg->x, msg->y);
}

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

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

    // 创建一个Subscriber,订阅名为/turtle1/pose的topic,注册回调函数poseCallback
    ros::Subscriber pose_sub = n.subscribe("/turtle1/pose", 10, poseCallback);

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

    return 0;
}

编译并运行订阅者

//配置CMakeLists.txt
add_executable(pose_subscriber src/pose_subscriber.cpp)
target_link_libraries(pose_subscriber ${catkin_LIBRARIES})
//编译并运行
cd ~/catkin_ws
catkin_make
source devel/setup.bash
roscore
//新开一个终端,开启turtlesim
rosrun turtlesim turtlesim_node
//新开一个终端,运行发布者cpp程序
rosrun learning_topic pose_subscriber
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 该例程将订阅/turtle1/pose话题,消息类型turtlesim::Pose

import rospy
from turtlesim.msg import Pose

def poseCallback(msg):
    rospy.loginfo("Turtle pose: x:%0.6f, y:%0.6f", msg.x, msg.y)

def pose_subscriber():
    # ROS节点初始化
    rospy.init_node('pose_subscriber', anonymous=True)

    # 创建一个Subscriber,订阅名为/turtle1/pose的topic,注册回调函数poseCallback
    rospy.Subscriber("/turtle1/pose", Pose, poseCallback)

    # 循环等待回调函数
    rospy.spin()

if __name__ == '__main__':
    pose_subscriber()

话题消息的定义与使用定义msg文件

//在文件夹learning_topic中新建一个命名为msg的文件夹,存放消息类文件,方便管理
//创建.msg文件 touch Person.msg
//打开该文件,输入以下信息后保存
string name
uint8 sex
uint8 age

uint8 unknown = 0
uint8 male = 1
uint8 female = 2
//这里写的并不是cpp,也不是python。但他在编译过程中会由ros自动编译成cpp或python

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

//打开文件夹learning_topic,打开package.xml
//gedit package.xml
//保存到最下方/<build_depend>类中
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
//<build_depend>用于添加编译依赖,这里添加message_generation功能包
//<exec_depend<用于添加执行依赖,这里添加message_runtime功能包

在CMakeLists.txt添加编译选项

//打开文件夹learning_topic,打开CMakeLists.txt。
//在最上方的find_package中添加以下语句
message_generation
//找到Declare ROS dynamic reconfigure parameters的位置,在上方添加以下语句
add_message_files(FILES Person.msg)
generate_messages(DEPENDENCIES std_msgs)
//第一句,告诉编译器Person.msg是我们定义的消息接口
//第二句,告诉编译器在编译Person.msg文件的时候,需要依赖ROS哪些已有的库或者包。
//找到catkin specific configuration(即Build上方),添加以下语句
CATKIN_DEPENDS geometry_msgs roscpp rospy std_msgs turtlesim message_runtime

编译生成语言相关文件

//回到工作空间的根目录catkin_ws下,打开命令行,尝试进行编译。输入指令
catkin_make

创建publisher和subscriber

//person_publisher.cpp
/**
 * 该例程将发布/person_info话题,自定义消息类型learning_topic::Person
 */
 
#include <ros/ros.h>
//!!!!!关键!!!!!
#include "learning_topic/Person.h"

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

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

    // 创建一个Publisher,发布名为/person_info的topic,消息类型为learning_topic::Person,队列长度10
    //!!!!!关键!!!!!
    ros::Publisher person_info_pub = n.advertise<learning_topic::Person>("/person_info", 10);

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

    int count = 0;
    while (ros::ok())
    {
        // 初始化learning_topic::Person类型的消息
        learning_topic::Person person_msg;
        person_msg.name = "Tom";
        person_msg.age  = 18;
        person_msg.sex  = learning_topic::Person::male;

        // 发布消息
        person_info_pub.publish(person_msg);

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

        // 按照循环频率延时
        loop_rate.sleep();
    }

    return 0;
}

//person_subscriber.cpp
/**
 * 该例程将订阅/person_info话题,自定义消息类型learning_topic::Person
 */
 
#include <ros/ros.h>
//!!!!!关键!!!!!
#include "learning_topic/Person.h"

// 接收到订阅的消息后,会进入消息回调函数
void personInfoCallback(const learning_topic::Person::ConstPtr& msg)
{
    // 将接收到的消息打印出来
    ROS_INFO("Subcribe Person Info: name:%s  age:%d  sex:%d", 
             msg->name.c_str(), msg->age, msg->sex);
}

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

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

    // 创建一个Subscriber,订阅名为/person_info的topic,注册回调函数personInfoCallback
    //!!!!!关键!!!!!
    ros::Subscriber person_info_sub = n.subscribe("/person_info", 10, personInfoCallback);

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

    return 0;
}

配置CMakeLists.txt中的编译规则
*设置需要编译的代码和生成的可执行文件;
*设置链接库;
*添加依赖项.

//这里相比之前配置CMakeLists.txt,多了add_dependencies的语句目的是让可执行文件(前两句做的工作)和动态生成的文件产生依赖关系
//位置依旧,找到Install位置的上方,添加以下语句,保存.
add_executable(person_publisher src/person_publisher.cpp)
target_link_libraries(person_publisher ${catkin_LIBRARIES})
add_dependencies(person_publisher ${PROJECT_NAME}_generate_messages_cpp)

add_executable(person_subscriber src/person_subscriber.cpp)
target_link_libraries(person_subscriber ${catkin_LIBRARIES})
add_dependencies(person_subscriber ${PROJECT_NAME}_generate_messages_cpp)


编译并运行publisher和subscriber

cd ~/catkin_ws
catkin_make
source devel/setup.bash
roscore
//新开一个终端,运行subscriber
rosrun learning_topic person_subscriber
//新开一个终端,运行publisher
rosrun learning_topic person_publisher
//ROS Master是帮助节点的创建和链接的。节点一旦创建和链接后,就不受ROS Master影响

publisher和subscriber(python)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 该例程将发布/person_info话题,自定义消息类型learning_topic::Person

import rospy
from learning_topic.msg import Person

def velocity_publisher():
    # ROS节点初始化
    rospy.init_node('person_publisher', anonymous=True)

    # 创建一个Publisher,发布名为/person_info的topic,消息类型为learning_topic::Person,队列长度10
    person_info_pub = rospy.Publisher('/person_info', Person, queue_size=10)

    #设置循环的频率
    rate = rospy.Rate(10) 

    while not rospy.is_shutdown():
        # 初始化learning_topic::Person类型的消息
        person_msg = Person()
        person_msg.name = "Tom";
        person_msg.age  = 18;
        person_msg.sex  = Person.male;

        # 发布消息
        person_info_pub.publish(person_msg)
        rospy.loginfo("Publsh person message[%s, %d, %d]", 
                person_msg.name, person_msg.age, person_msg.sex)

        # 按照循环频率延时
        rate.sleep()

if __name__ == '__main__':
    try:
        velocity_publisher()
    except rospy.ROSInterruptException:
        pass

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 该例程将订阅/person_info话题,自定义消息类型learning_topic::Person

import rospy
from learning_topic.msg import Person

def personInfoCallback(msg):
    rospy.loginfo("Subcribe Person Info: name:%s  age:%d  sex:%d", 
             msg.name, msg.age, msg.sex)

def person_subscriber():
    # ROS节点初始化
    rospy.init_node('person_subscriber', anonymous=True)

    # 创建一个Subscriber,订阅名为/person_info的topic,注册回调函数personInfoCallback
    rospy.Subscriber("/person_info", Person, personInfoCallback)

    # 循环等待回调函数
    rospy.spin()

if __name__ == '__main__':
    person_subscriber()

客户端Client的编程实现创建功能包

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

创建客户端代码(C++)
如何实现一个客户端
*初始化ROS客户端;
*创建一个Client实例;
*发布服务请求数据;
*等待Server处理之后的应答结果

/**
 * 该例程将请求/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 = "turtle2";

    // 请求服务调用
	ROS_INFO("Call service to spwan 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("Spwan turtle successfully [name:%s]", srv.response.name.c_str());

	return 0;
};

配置客户端代码编译规则
如何配置CMakeLists.txt中的编译规则
*设置需要编译的代码和生成的可执行文件
*设置链接库

//配置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
//新开一个终端,开启turtlesim
rosrun turtlesim turtlesim_node
//新开一个终端,运行发布者cpp程序
rosrun learning_service turtle_spawn

创建客户端代码(python)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 该例程将请求/spawn服务,服务数据类型turtlesim::Spawn

import sys
import rospy
from turtlesim.srv import Spawn

def turtle_spawn():
	# ROS节点初始化
    rospy.init_node('turtle_spawn')

	# 发现/spawn服务后,创建一个服务客户端,连接名为/spawn的service
    rospy.wait_for_service('/spawn')
    try:
        add_turtle = rospy.ServiceProxy('/spawn', Spawn)

		# 请求服务调用,输入请求数据
        response = add_turtle(2.0, 2.0, 0.0, "turtle2")
        return response.name
    except rospy.ServiceException, e:
        print "Service call failed: %s"%e

if __name__ == "__main__":
	#服务调用并显示调用结果
    print "Spwan turtle successfully [name:%s]" %(turtle_spawn())

服务端Server的编程实现

创建服务器代码(C++)

如何实现一个服务器
*初始化ROS节点;
*创建Server实例;
*循环等待服务请求,进入回调函数;
*在回调函数中完成服务功能的处理,并反馈应答数据

//代码
/**
 * 该例程将执行/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?"Yes":"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>("/turtle1/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中的编译规则
*设置需要编译的代码和生成的可执行文件
*设置链接库

//配置CMakeLists.txt
add_executable(turtle_command_server src/turtle_command_server.cpp)
target_link_libraries(turtle_command_server ${catkin_LIBRARIES})

编译并运行服务器

//编译并运行
cd ~/catkin_ws
catkin_make
source devel/setup.bash
roscore
//新开一个终端,开启turtlesim
rosrun turtlesim turtlesim_node
//新开一个终端,运行server
rosrun learning_service turtle_command_server
//新开一个终端,发送请求
rosservice call /turtle_command "{}"

创建服务器代码(Python)

#ros在Python中没有spinonce方法,可通过多线程来实现
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 该例程将执行/turtle_command服务,服务数据类型std_srvs/Trigger

import rospy
import thread,time
from geometry_msgs.msg import Twist
from std_srvs.srv import Trigger, TriggerResponse

pubCommand = False;
turtle_vel_pub = rospy.Publisher('/turtle1/cmd_vel', Twist, queue_size=10)

def command_thread():	
	while True:
		if pubCommand:
			vel_msg = Twist()
			vel_msg.linear.x = 0.5
			vel_msg.angular.z = 0.2
			turtle_vel_pub.publish(vel_msg)
			
		time.sleep(0.1)

def commandCallback(req):
	global pubCommand
	pubCommand = bool(1-pubCommand)

	# 显示请求数据
	rospy.loginfo("Publish turtle velocity command![%d]", pubCommand)

	# 反馈数据
	return TriggerResponse(1, "Change turtle command state!")

def turtle_command_server():
	# ROS节点初始化
    rospy.init_node('turtle_command_server')

	# 创建一个名为/turtle_command的server,注册回调函数commandCallback
    s = rospy.Service('/turtle_command', Trigger, commandCallback)

	# 循环等待回调函数
    print "Ready to receive turtle command."

    thread.start_new_thread(command_thread, ())
    rospy.spin()

if __name__ == "__main__":
    turtle_command_server()


服务数据的定义与使用定义srv文件

//在文件夹learning_service中新建一个命名为srv的文件夹,存放消息类文件,方便管理
//创建.srv文件 touch Person.srv
//打开该文件,输入以下信息后保存
string name
uint8 sex
uint8 age

uint8 unknown = 0
uint8 male = 1
uint8 female = 2
---
string result
//这里写的并不是cpp,也不是python。但他在编译过程中会由ros自动编译成cpp或python

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

//打开文件夹learning_service,打开package.xml
//gedit package.xml
//保存到最下方/<build_depend>类中
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
//<build_depend>用于添加编译依赖,这里添加message_generation功能包
//<exec_depend<用于添加执行依赖,这里添加message_runtime功能包

在CMakeLists.txt添加编译选项

//打开文件夹learning_service,打开CMakeLists.txt。
//在最上方的find_package中添加以下语句
message_generation
//找到Declare ROS dynamic reconfigure parameters的位置,在上方添加以下语句
add_message_files(FILES Person.msg)
generate_messages(DEPENDENCIES std_msgs)
//第一句,告诉编译器Person.msg是我们定义的消息接口
//第二句,告诉编译器在编译Person.msg文件的时候,需要依赖ROS哪些已有的库或者包。
//找到catkin specific configuration(即Build上方),添加以下语句
CATKIN_DEPENDS geometry_msgs roscpp rospy std_msgs turtlesim message_runtime

编译生成语言相关文件

//回到工作空间的根目录catkin_ws下,打开命令行,尝试进行编译。输入指令
catkin_make

创建服务器代码(C++)

如何实现一个服务器
*初始化ROS节点;
*创建Server实例;
*循环等待服务请求,进入回调函数;
*在回调函数中完成服务功能的处理,并反馈应答数据

//客户端
/**
 * 该例程将请求/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;

    // 发现/spawn服务后,创建一个服务客户端,连接名为/spawn的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的文件名相同
	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;
};


//服务端

/**
 * 该例程将执行/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;
}


配置服务器/客户端代码编译规则

如何配置CMakeLists.txt中的编译规则
*设置需要编译的代码和生成的可执行文件;
*设置链接库;
*添加依赖项.

//这里相比之前配置CMakeLists.txt,多了add_dependencies的语句目的是让可执行文件(前两句做的工作)和动态生成的文件产生依赖关系
//位置依旧,找到Install位置的上方,添加以下语句,保存.
add_executable(person_server src/person_server.cpp)
target_link_libraries(person_server ${catkin_LIBRARIES})
add_dependencies(person_server ${PROJECT_NAME}_gencpp)

add_executable(person_client src/person_client.cpp)
target_link_libraries(person_client ${catkin_LIBRARIES})
add_dependencies(person_client ${PROJECT_NAME}_gencpp)

编译并运行发布者和订阅者

//编译并运行
cd ~/catkin_ws
catkin_make
source devel/setup.bash
roscore
//新开一个终端,运行server
rosrun learning_service person_server
//新开一个终端,运行client
rosrun learning_service person_client

创建客户端和服务端代码(Python)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 该例程将请求/show_person服务,服务数据类型learning_service::Person

import sys
import rospy
from learning_service.srv import Person, PersonRequest

def person_client():
	# ROS节点初始化
    rospy.init_node('person_client')

	# 发现/spawn服务后,创建一个服务客户端,连接名为/spawn的service
    rospy.wait_for_service('/show_person')
    try:
        person_client = rospy.ServiceProxy('/show_person', Person)

		# 请求服务调用,输入请求数据
        response = person_client("Tom", 20, PersonRequest.male)
        return response.result
    except rospy.ServiceException, e:
        print "Service call failed: %s"%e

if __name__ == "__main__":
	#服务调用并显示调用结果
    print "Show person result : %s" %(person_client())

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 该例程将执行/show_person服务,服务数据类型learning_service::Person

import rospy
from learning_service.srv import Person, PersonResponse

def personCallback(req):
	# 显示请求数据
    rospy.loginfo("Person: name:%s  age:%d  sex:%d", req.name, req.age, req.sex)

	# 反馈数据
    return PersonResponse("OK")

def person_server():
	# ROS节点初始化
    rospy.init_node('person_server')

	# 创建一个名为/show_person的server,注册回调函数personCallback
    s = rospy.Service('/show_person', Person, personCallback)

	# 循环等待回调函数
    print "Ready to show person informtion."
    rospy.spin()

if __name__ == "__main__":
    person_server()

参数的使用与编程方法创建功能包

cd ~/catkin_ws/src
catkin_create_pkg learning_parameter roscpp rospy std_srvs

参数命令行使用rospram*列出当前所有参数

rosparam list

*显示某个参数值

rosparam get param_key

*设置某个参数值

rosparam set param_key param_value

*保存参数到文件

rosparam dump file_name

*从文件读取参数

rosparam load file_name

*删除参数

rosparam delete param_key

编程方法(C++)

如何获取/配置参数
*初始化ROS节点;
*get函数获取参数;
*set函数设置参数.

/**
 * 该例程设置/读取海龟例程中的参数
 */
#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("/background_r", red);
	ros::param::get("/background_g", green);
	ros::param::get("/background_b", blue);

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

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

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

    // 读取背景颜色参数
	ros::param::get("/background_r", red);
	ros::param::get("/background_g", green);
	ros::param::get("/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;
}


配置代码编译规则

如何配置CMakeLists.txt中的编译规则
*设置需要编译的代码和生成的可执行文件;
*设置链接库.

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

编译并运行发布者

//编译并运行
cd ~/catkin_ws
catkin_make
source devel/setup.bash
roscore
//新开一个终端,开启turtlesim
rosrun turtlesim turtlesim_node
//新开一个终端,运行发布者
rosrun learning_parameter parameter_config

编程方法(Python)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 该例程设置/读取海龟例程中的参数

import sys
import rospy
from std_srvs.srv import Empty

def parameter_config():
	# ROS节点初始化
    rospy.init_node('parameter_config', anonymous=True)

	# 读取背景颜色参数
    red   = rospy.get_param('/background_r')
    green = rospy.get_param('/background_g')
    blue  = rospy.get_param('/background_b')

    rospy.loginfo("Get Backgroud Color[%d, %d, %d]", red, green, blue)

	# 设置背景颜色参数
    rospy.set_param("/background_r", 255);
    rospy.set_param("/background_g", 255);
    rospy.set_param("/background_b", 255);

    rospy.loginfo("Set Backgroud Color[255, 255, 255]");

	# 读取背景颜色参数
    red   = rospy.get_param('/background_r')
    green = rospy.get_param('/background_g')
    blue  = rospy.get_param('/background_b')

    rospy.loginfo("Get Backgroud Color[%d, %d, %d]", red, green, blue)

	# 发现/spawn服务后,创建一个服务客户端,连接名为/spawn的service
    rospy.wait_for_service('/clear')
    try:
        clear_background = rospy.ServiceProxy('/clear', Empty)

		# 请求服务调用,输入请求数据
        response = clear_background()
        return response
    except rospy.ServiceException, e:
        print "Service call failed: %s"%e

if __name__ == "__main__":
    parameter_config()


备注
错误:
KeyError: ‘/background_r’
解决方案:
改为
/turtlesim/background_r
其余一样
ROS中的坐标管理系统

TF工具包能干什么?
*五秒钟之前,机器人头部坐标系相对于全局坐标系的关系是什么样的?
*机器人夹取的物体想对于机器人中心坐标系的位置在哪里?
*机器人中心坐标系相对于全局坐标系的位置在哪里?

TF坐标变换如何实现?
*广播TF变换
*监听TF变换

小海龟跟随实验

#安装功能包
sudo apt-get install ros-noetic-turtle-tf
#启动launch文件
roslaunch turtle_tf turtle_tf_demo.launch
#运行海龟键盘控制节点
rosrun turtlesim turtle_teleop_key
#可视化框架
rosrun tf view_frames
#查询位置关系
rosrun tf_echo turtle1 turtle2
#三维可视化位置关系
rosrun rviz rviz -d `rospack find turtle_tf` /rviz/turtle_rviz.rviz

TF坐标系广播与监听的编程实现创建功能包

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

如何实现一个tf广播站
*定义TF广播站(TransformBroadcaster)
*创建坐标变换值;
*发布坐标变换(sendTranform)

/**
 * 该例程产生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, "my_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);

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

	return 0;
};

如何实现一个TF监听器
*定义TF监听器(TransformListener);
*查找坐标变换(waitForTransform,lookupTransform)

/**
 * 该例程监听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, "my_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
		{
			//查询是否有这两个坐标系,查询当前时间,如果超过3s则报错
			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;
};

配置tf广播站与监听器代码编译规则

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})

编译并运行

//编译并运行
cd ~/catkin_ws
catkin_make
source devel/setup.bash
roscore
//新开一个终端,开启turtlesim
rosrun turtlesim turtlesim_node
//新开一个终端,发布turtle1与world位置关系
rosrun learning_tf turtle_tf_broadcaster__name:=turtle1_tf_broadcaster /turtle1
//新开一个终端,发布turtle2与world位置关系
rosrun learning_tf turtle_tf_broadcaster__name:=turtle2_tf_broadcaster /turtle
//新开一个终端,运行监听器
rosrun learning_tf turtle_tf_listener
//新开一个终端,键盘控制器
rosrun learning turtle_teleop_key

创建tf广播器与监听器代码(Python)

#广播器
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 该例程将请求/show_person服务,服务数据类型learning_service::Person

import roslib
roslib.load_manifest('learning_tf')
import rospy

import tf
import turtlesim.msg

def handle_turtle_pose(msg, turtlename):
    br = tf.TransformBroadcaster()
    br.sendTransform((msg.x, msg.y, 0),
                     tf.transformations.quaternion_from_euler(0, 0, msg.theta),
                     rospy.Time.now(),
                     turtlename,
                     "world")

if __name__ == '__main__':
    rospy.init_node('turtle_tf_broadcaster')
    turtlename = rospy.get_param('~turtle')
    rospy.Subscriber('/%s/pose' % turtlename,
                     turtlesim.msg.Pose,
                     handle_turtle_pose,
                     turtlename)
    rospy.spin()
#监听器
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 该例程将请求/show_person服务,服务数据类型learning_service::Person

import roslib
roslib.load_manifest('learning_tf')
import rospy
import math
import tf
import geometry_msgs.msg
import turtlesim.srv

if __name__ == '__main__':
    rospy.init_node('turtle_tf_listener')

    listener = tf.TransformListener()

    rospy.wait_for_service('spawn')
    spawner = rospy.ServiceProxy('spawn', turtlesim.srv.Spawn)
    spawner(4, 2, 0, 'turtle2')

    turtle_vel = rospy.Publisher('turtle2/cmd_vel', geometry_msgs.msg.Twist,queue_size=1)

    rate = rospy.Rate(10.0)
    while not rospy.is_shutdown():
        try:
            (trans,rot) = listener.lookupTransform('/turtle2', '/turtle1', rospy.Time(0))
        except (tf.LookupException, tf.ConnectivityException, tf.ExtrapolationException):
            continue

        angular = 4 * math.atan2(trans[1], trans[0])
        linear = 0.5 * math.sqrt(trans[0] ** 2 + trans[1] ** 2)
        cmd = geometry_msgs.msg.Twist()
        cmd.linear.x = linear
        cmd.angular.z = angular
        turtle_vel.publish(cmd)

        rate.sleep()

launch启动文件的使用方法

Launch文件
通过XML文件实现多节点的配置和启动(可自动启动ROS Master)
Launch文件语法

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

更多标签可参见:https://wiki.ros.org/roslaunch/XMLLaunc示例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>

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>


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>


start_tf_demo_py.launch

<launch>

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

	<node name="turtle1_tf_broadcaster" pkg="learning_tf" type="turtle_tf_broadcaster.py">
	  <param name="turtle" type="string" value="turtle1" />
	</node>
	<node name="turtle2_tf_broadcaster" pkg="learning_tf" type="turtle_tf_broadcaster.py">
	  <param name="turtle" type="string" value="turtle2" /> 
	</node>

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

</launch>


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>


创建功能包

cd ~/catkin_ws/src
catkin_create_pkg learning_launch 
cd learning_launch/
//用于存放launch文件
mkdir launch

编译并运行launch文件

cd ~/catkin_ws
catkin_make
roslaunch learning_launch simple.launch

常用可视化工具的使用

Qt工具箱

在这里插入图片描述

Rviz

Rviz是一款三维可视化工具,可以很好的兼容基于ROS软件框架的机器人平台.
*在rviz中,可以使用可扩展标记语言XML对机器人,周围事物等任何实物进行尺寸,质量,位置,材质,关节等属性的描述,并且在界面中呈现出来.
*同时,rviz还可以通过图形化的方式,实时显示机器人传感器的信息,机器人的运动状态,周围环境的变化等信息.
*总而言之,rviz通过机器人模型参数,机器人发布的传感信息等数据,为用户进行所有可检测信息的图形化显示.用户和开发者也可以在rviz的控制界面下,通过按钮,滑动条,数值等方式.控制机器人的行为.
在这里插入图片描述

启动

roscore
rosrun rviz rviz

Gazebo

Gazebo是一款功能强大的三维物理仿真平台
*具备强大的物理引擎
*高质量的图形渲染
*方便的编程与图形接口
*开源免费
其典型应用场景包括
*测试机器人算法
*机器人的设计
*现实情景下的回溯测试

在这里插入图片描述

启动

roslaunch gazebo_ros

进阶攻略

在这里插入图片描述