ROS到底是什么?

ROS是什么

ROS = 通信机制+开发工具+应用功能+生态系统
在这里插入图片描述

文件系统工具

rospack find [包名称] #返回路径
roscd [本地包名称[/子目录]]
roscd log
rosls [本地包名称[/子目录]]

创建ROS程序包

cd ~/catkin_ws/src
catkin_create_pkg package_name dependencies
# 程序包依赖关系
rospack depends1 roscpp #一级依赖
roscd roscpp & cat package.xml #依赖包都在package.xml 

package.xml

# 描述项标签
 <description>The beginner_tutorials package</description>
# 维护者标签
 <maintainer email="user@todo.todo">user</maintainer>
# 许可证标签
 <license>TODO</license>
# catkin中默认提供
 <buildtool_depend>catkin</buildtool_depend>
# 所有依赖包
 <build_depend>roscpp</build_depend>
 <build_depend>rospy</build_depend>
 <build_depend>std_msgs</build_depend>
# 编译和运行时的依赖包
 <exec_depend>roscpp</exec_depend>
 <exec_depend>rospy</exec_depend>
 <exec_depend>std_msgs</exec_depend>

CMakeLists.txt

理解ROS节点

节点就是package中的一个可执行文件
节点可以发布和接收一个话题
节点也可以提供或使用某种服务

roscore
rosnode list
rosnode info [node_name]
# Node === Publications === Subcriptions === Services
rosrun [package_name] [node_name]

理解ROS话题

  • 消息Messages
    话题之间的通信建立在节点之间发送的ROS消息实现,发布者和订阅者必须发送和接受相同类型的消息
rostopic bw     display bandwidth used by topic
rostopic echo   print messages to screen
rostopic hz     display publishing rate of topic
rostopic list   print information about active topics
rostopic pub    publish data to topic
rostopic type   print topic type
# 小海龟示例展示话题通信
rosrun turtlesim turtlesim_node
rosrun turtlesim turtle_teleop_key
rqtgraph # 显示通信架构
rostopic echo [topic] # 查看话题发布的数据
rostopic list
rostopic type [topic] # 查看发布在某话题上的消息类型

rosmsg show [msg_name] # 查看消息的详细情况

rostopic pub [topic] [msg_type] [args] # 前面已知发布在某话题上的消息类型了,现在手动给这个话题发一个对应类型的消息,而不用发布者node来发布

rostopic hz [topic] # 查看数据发布的频率
rostopic hz /turtle/pose # 查看给发布给/turtlr/pose消息的速率有多快

rqt_plot # 显示一个发布到某个话题上的数据变化图形
# 在界面左上角添加要绘制的话题

理解ROS服务

  • 服务允许节点发送请求(request) 并获得一个响应(response)
rosservice list         输出可用服务的信息
rosservice call         调用带参数的服务
rosservice type         输出服务类型
rosservice find         依据类型寻找服务find services by service type
rosservice uri          输出服务的ROSRPC uri
rosservice list
rosservice type [service_name] # 查看服务类型
rosservice call [service_name] [args] # 调用服务,根据服务类型确定需不需要加参数
rosservice type /spawn | rossrv show
rosservice call /spawn 2 2 0.2 "" # 在给定的位置生成一只新的乌龟

理解ROS参数

参数服务器能够存储整型、浮点、布尔、字符串、字典、列表等数据类型。
使用YAML标记语言

rosparam set            设置参数
rosparam get            获取参数
rosparam load           从文件读取参数
rosparam load [file_name] [namespace]  将yaml文件重载入新的命名空间
rosparam dump           向文件中写入参数
rosparam delete         删除参数
rosparam list           列出参数名
rosparam set background_r 150
rosservice call clear # 使修改后的参数生效
rosparam get / # 显示参数服务器上的所有内容
rosparam dump params.yaml # 将所有的参数写入params.yaml文件
rosparam load params.yaml copy # 将yaml文件重载入新的命名空间,比如说copy空间
rosparam get copy/turtlesim/background_b #

使用rqt_console和roslaunch

  • rqt_console属于ROS日志框架(logging framework)的一部分,用来显示节点的输出信息。
  • rqt_logger_level允许我们修改节点运行时输出信息的日志等级(logger levels)(包括 DEBUG、WARN、INFO和ERROR)。
  • 使用roslaunch来启动多个turtlesim节点
    • launch文件中添加两个相同的小海龟节点,只不过用命令空间namespace来区分。同时用remap启动模仿节点。
<?xml version="1.0"?>
<launch>

  <!-- 创建了两个节点分别以命名空间‘namespace’标签区分 -->
  <group ns="turtlesim1">
    <node pkg="turtlesim" name="sim" type="turtlesim_node"/>
  </group>

  <group ns="turtlesim2">
    <node pkg="turtlesim" name="sim" type="turtlesim_node"/>
  </group>
  <!-- 将所有话题的输入和输出分别重命名为turtlesim1和turtlesim2,这样使turtlesim2模仿turtlesim1 -->
  <node pkg="turtlesim" name="mimic" type="mimic">
    <remap from="input" to="turtlesim1/turtle1"/>
    <remap from="output" to="turtlesim2/turtle1"/>
  </node>

</launch>

使用rosed编辑ROS中的文件

rosed [package_name] [filename]
rosed roscpp Logger.msg

创建ROS消息msg

  • 消息(msg): msg文件就是一个描述ROS中所使用消息类型的简单文本。它们会被用来生成不同语言的源代码。
    消息类型包含两部分:**消息所在的package** 和 **消息名称**

msg文件夹下的文件就是**message type**

msg文件存放在package的msg目录下,srv文件则存放在srv目录下。

msg文件实际上就是每行声明一个数据类型和变量名。可以使用的数据类型如下:

  • int8, int16, int32, int64 (plus uint*)
  • float32, float64
  • string
  • time, duration
  • other msg files
  • variable-length array[] and fixed-length array[C]

在ROS中有一个特殊的数据类型:Header,它含有时间戳和坐标系信息。在msg文件的第一行经常可以看到Header header的声明.

 Header header
 string child_frame_id
 geometry_msgs/PoseWithCovariance pose
 geometry_msgs/TwistWithCovariance twist

package.xml

  • 接下来,还有关键的一步:我们要确保msg文件被转换成为C++,Python和其他语言的源代码:

查看package.xml, 确保它包含一下两条语句:

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

在构建的时候,我们只需要"message_generation"。然而,在运行的时候,我们只需要"message_runtime"。

CMakeLists

构建依赖

在 CMakeLists.txt文件中,利用find_packag函数,增加对message_generation的依赖,这样就可以生成消息了。 你可以直接在COMPONENTS的列表里增加message_generation,就像这样:

# Do not just add this line to your CMakeLists.txt, modify the existing line
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs message_generation)
运行依赖
catkin_package(
  ...
  CATKIN_DEPENDS message_runtime ...
  ...)
添加msg文件

找到如下代码块:

# add_message_files(
#   FILES
#   Message1.msg
#   Message2.msg
# )

去掉注释符号#,用你的.msg文件替代Message*.msg,就像下边这样:

add_message_files(
  FILES
  Num.msg
)

手动添加.msg文件后,我们要确保CMake知道在什么时候重新配置我们的project。 确保添加了如下代码:

generate_messages()

使用rosmsg

$ rosmsg show [message type]
$ rosmsg show beginner_tutorials/Num

创建服务srv

  • 服务(srv): 一个srv文件描述一项服务。它包含两个部分:请求和响应。

srv文件分为请求和响应两部分,由’—'分隔。下面是srv的一个样例:

int64 A
int64 B
---
int64 Sum

其中 A 和 B 是请求, 而Sum 是响应。

$ roscd beginner_tutorials
$ mkdir srv
$ roscp rospy_tutorials AddTwoInts.srv srv/AddTwoInts.srv #善用roscp命令

CMakeLists

构建依赖
# Do not just add this line to your CMakeLists.txt, modify the existing line
find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation)

是的,messagemsgsrv都有用

添加srv文件
`**删掉#,去除对下边语句的注释:**`

# add_service_files(
#   FILES
#   Service1.srv
#   Service2.srv
# )

用你自己的srv文件名替换掉那些Service*.srv文件:

add_service_files(
  FILES
  AddTwoInts.srv
)

使用rossrv

$ rossrv show <service type>
$ rossrv show beginner_tutorials/AddTwoInts

msg和srv都需要的步骤

# generate_messages(
#   DEPENDENCIES
# #  std_msgs  # Or other packages containing msgs
# )

去掉注释并附加上所有你消息文件所依赖的那些含有.msg文件的package(这个例子是依赖std_msgs,不要添加roscpp,rospy),结果如下:

generate_messages(
  DEPENDENCIES
  std_msgs
)

由于增加了新的消息,所以我们需要重新编译我们的package:

# In your catkin workspace
$ cd ../..
$ catkin_make
$ cd -

所有在msg路径下的.msg文件都将转换为ROS所支持语言的源代码。生成的C++头文件将会放置在~/catkin_ws/devel/include/beginner_tutorials/。 Python脚本语言会在 ~/catkin_ws/devel/lib/python2.7/dist-packages/beginner_tutorials/msg 目录下创建。 lisp文件会出现在 ~/catkin_ws/devel/share/common-lisp/ros/beginner_tutorials/msg/ 路径下.

编写发布器和订阅器节点(C++)

发布器节点

步骤:
初始化 ROS 系统

  • 在 ROS 网络内广播我们将要在 chatter 话题上发布 std_msgs/String 类型的消息
  • 以每秒 10 次的频率在 chatter 上发布消息

package_name/src/talker.cpp

#include "ros/ros.h" //引用了 ROS 系统中大部分常用的头文件
#include "std_msgs/String.h" //引用了 std_msgs/String 消息, 它存放在 std_msgs package 里,是由 String.msg 文件自动生成的头文件
#include <sstream> //stringstream头文件

/**
 * This tutorial demonstrates simple sending of messages over the ROS system.
 */
int main(int argc, char **argv)
{
  /*
    The ros::init() function needs to see argc and argv so that it can perform
    any ROS arguments and name remapping that were provided at the command line. For programmatic
    remappings you can use a different version of init() which takes remappings
    directly, but for most command-line programs, passing argc and argv is the easiest
    way to do it.  The third argument to init() is the name of the node.
   
    You must call one of the versions of ros::init() before using any other
    part of the ROS system.
   */

  ros::init(argc, argv, "talker"); //名称必须是一个 base name ,也就是说,名称内不能包含 / 等符号


  /**
    NodeHandle is the main access point to communications with the ROS system.
    The first NodeHandle constructed will fully initialize this node, and the last
    NodeHandle destructed will close down the node.
   */

  ros::NodeHandle n; //为这个进程的节点创建一个句柄

  /**
    The advertise() function is how you tell ROS that you want to
    publish on a given topic name. This invokes a call to the ROS
    master node, which keeps a registry of who is publishing and who
    is subscribing. After this advertise() call is made, the master
    node will notify anyone who is trying to subscribe to this topic name,
    and they will in turn negotiate a peer-to-peer connection with this
    node.  advertise() returns a Publisher object which allows you to
    publish messages on that topic through a call to publish().  Once
    all copies of the returned Publisher object are destroyed, the topic
    will be automatically unadvertised.
   
    The second parameter to advertise() is the size of the message queue
    used for publishing messages.  If messages are published more quickly
    than we can send them, the number here specifies how many messages to
    buffer up before throwing some away.
   */

  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
  //告诉 master 我们将要在 chatter(话题名) 上发布 std_msgs/String 消息类型的消息.这样 master 就会告诉所有订阅了 chatter 话题的节点,将要有数据发布。第二个参数是发布序列的大小。如果我们发布的消息的频率太高,缓冲区中的消息在大于 1000 个的时候就会开始丢弃先前发布的消息。
// NodeHandle::advertise() 返回一个 ros::Publisher 对象,它有两个作用: 1) 它有一个 publish() 成员函数可以让你在topic上发布消息; 2) 如果消息类型不对,它会拒绝发布。

  ros::Rate loop_rate(10);
  //ros::Rate 对象可以允许你指定自循环的频率。它会追踪记录自上一次调用 Rate::sleep() 后时间的流逝,并休眠直到一个频率周期的时间。在这个例子中,我们让它以 10Hz 的频率运行。
  
  /**
   * A count of how many messages we have sent. This is used to create
   * a unique string for each message.
   */

  int count = 0;
  while (ros::ok())
  /* roscpp 会默认生成一个 SIGINT 句柄,它负责处理 Ctrl-C 键盘操作——使得 ros::ok() 返回 false。
	如果下列条件之一发生,ros::ok() 返回false:
	SIGINT 被触发 (Ctrl-C)
	被另一同名节点踢出 ROS 网络
	ros::shutdown() 被程序的另一部分调用
	节点中的所有 ros::NodeHandles 都已经被销毁
	一旦 ros::ok() 返回 false, 所有的 ROS 调用都会失效。*/
  {
    /**
      This is a message object. You stuff it with data, and then publish it.
     */
    std_msgs::String msg;//定义一个string类型消息
    std::stringstream ss; //定义一个stringstream类型数据流
    ss << "hello world " << count;//将count与"hello world"相加, 输入到ss中
    msg.data = ss.str(); //将ss中的消息转化为string类型 并赋给msg
  //
    ROS_INFO("%s", msg.data.c_str());
   //ROS_INFO 和其他类似的函数可以用来代替 printf/cout 等函数。
   
    /**
      The publish() function is how you send messages. The parameter
      is the message object. The type of this object must agree with the type
      given as a template parameter to the advertise<>() call, as was done
      in the constructor above.
     */
    chatter_pub.publish(msg); //发布msg消息
    // 我们向所有订阅 chatter 话题的节点发送消息。
    ros::spinOnce();
	//在我们的例子中,可以不要这句,因为我们不接受回调
    loop_rate.sleep();
    //调用 ros::Rate 对象来休眠一段时间以使得发布频率为 10Hz。
    ++count;
  }
  return 0;
}

订阅器节点

步骤:

  • 初始化ROS系统
  • 订阅 chatter 话题
  • 进入自循环,等待消息的到达
  • 当消息到达,调用 chatterCallback() 函数

package_name/src/listener.cpp

#include "ros/ros.h"
#include "std_msgs/String.h"

/**
 * This tutorial demonstrates simple receipt of messages over the ROS system.
 */

void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
  ROS_INFO("I heard: [%s]", msg->data.c_str());
}
// 这是一个回调函数,当接收到 chatter 话题的时候就会被调用。消息是以 boost shared_ptr 指针的形式传输,这就意味着你可以存储它而又不需要复制数据。

int main(int argc, char **argv)
{
  ros::init(argc, argv, "listener");
  ros::NodeHandle n;
  ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback); 
  //告诉 master 我们要订阅 chatter 话题上的消息。当有消息发布到这个话题时,ROS 就会调用 chatterCallback() 函数。第二个参数是队列大小,以防我们处理消息的速度不够快,当缓存达到 1000 条消息后,再有新的消息到来就将开始丢弃先前接收的消息。
  ros::spin();//ros::spin() 进入自循环,可以尽可能快的调用消息回调函数。
  return 0;
}

编译节点

CMakelists

末尾添加:

## Build talker and listener
include_directories(include ${catkin_INCLUDE_DIRS})

add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
#为可执行文件添加对生成的消息文件的依赖,以确保自定义消息的头文件在被使用之前已经被生成
add_dependencies(talker beginner_tutorials_generate_messages_cpp)

add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
#为可执行文件添加对生成的消息文件的依赖,以确保自定义消息的头文件在被使用之前已经被生成
add_dependencies(listener beginner_tutorials_generate_messages_cpp)

编写发布器和订阅器节点(python)

编写发布器节点

注意在CMakeLists.txt文件中添加一下语句:

catkin_install_python(PROGRAMS scripts/talker.py
  DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

package_name/scripts/

   1 #!/usr/bin/env python
   2 # license removed for brevity
   3 import rospy
   4 from std_msgs.msg import String
   5 
   6 def talker():
   # 节点正在向chatter这个topic上发布string类型的消息
   7     pub = rospy.Publisher('chatter', String, queue_size=10)
   # 通过用anonymous=True即在node名字的末尾添加随机数保证node有一个唯一的名字。
   8     rospy.init_node('talker', anonymous=True)
   9     rate = rospy.Rate(10) # 10hz
  10     while not rospy.is_shutdown():
  11         hello_str = "hello world %s" % rospy.get_time()
  # 这个循环还调用rospy.loginfo(str),它执行三种任务:将消息打印到屏幕,将其写入节点的日志文件,并将其写入到rosout。
  12         rospy.loginfo(hello_str)
  13         pub.publish(hello_str)
  14         rate.sleep()
  15 
  16 if __name__ == '__main__':
  17     try:
  18         talker()
  19     except rospy.ROSInterruptException:
  20         pass

订阅器

在CMakeLists.txt文件中编辑catkin_install_python()

catkin_install_python(PROGRAMS scripts/talker.py scripts/listener.py
  DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
切换行号显示
   1 #!/usr/bin/env python
   2 import rospy
   3 from std_msgs.msg import String
   4 
   5 def callback(data):
   6     rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.data)
   7     
   8 def listener():
   9 
  10     # In ROS, nodes are uniquely named. If two nodes with the same
  11     # name are launched, the previous one is kicked off. The
  12     # anonymous=True flag means that rospy will choose a unique
  13     # name for our 'listener' node so that multiple listeners can
  14     # run simultaneously.
  15     rospy.init_node('listener', anonymous=True)
  16 
  17     rospy.Subscriber("chatter", String, callback)
  18 
  19     # spin() simply keeps python from exiting until this node is stopped
  20     rospy.spin()
  21 
  22 if __name__ == '__main__':
  23     listener()

需要注意py文件执行权限

chmod --help # -R: Recursive表示对目录下的所有文件和子目录进行权限变更,可递归遍历子目录。 --verbose/-v : 无论修改是否成功,输出每个文件的信息
chmod o+x talker.py
chmod o+x listener.py

编写服务器和客户端(C++)

编写Server节点

#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h" //编译系统自动根据之前创建的srv文件生成的对应srv文件的头文件

//提供两个int值求和的服务,int值从request里面获取,而返回数据装入response内
bool add(beginner_tutorials::AddTwoInts::Request &req,
		 beginner_tutorials::AddTwoInts::Reponse &res)
{
	res.sum = req.a + req.b;
	ROS_INFO("request: x=%ls,y=%ls", (long int)req.a, (long int)req.b);
	ROS_INF("sending back reponse: [%ld]", (long int)res.sum);
	return true;
}
int main(int argc, char** argv){
	ros::init(argc, argv, "add_two_ints_server");
	ros::NodeHandle n;

	ros::ServiceServer service = n.advertiseService("add_two_ints", add);
	ROS_INFO("Ready to add two ints.");
	ros::spin();

	return 0;
}

编写Client节点

#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h"
#include <cstdlib>

int main(int argc, char **argv)
{
  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;
  ros::ServiceClient client = n.serviceClient<beginner_tutorials::AddTwoInts>("add_two_ints");
  beginner_tutorials::AddTwoInts srv;
  srv.request.a = atoll(argv[1]);
  srv.request.b = atoll(argv[2]);
  if (client.call(srv))
  {
    ROS_INFO("Sum: %ld", (long int)srv.response.sum);
  }
  else
  {
    ROS_ERROR("Failed to call service add_two_ints");
    return 1;
  }

  return 0;
}

CMakeLists.txt

add_executable(add_two_ints_server src/add_two_ints_server.cpp)
target_link_libraries(add_two_ints_server ${catkin_LIBRARIES})
add_dependencies(add_two_ints_server beginner_tutorials_gencpp)

add_executable(add_two_ints_client src/add_two_ints_client.cpp)
target_link_libraries(add_two_ints_client ${catkin_LIBRARIES})
add_dependencies(add_two_ints_client beginner_tutorials_gencpp)

编写服务器和客户端(Python)

编写服务器

#!/usr/bin/env python

from __future__ import print_function

from beginner_tutorials.srv import AddTwoInts,AddTwoIntsResponse
import rospy

def handle_add_two_ints(req):
    print("Returning [%s + %s = %s]"%(req.a, req.b, (req.a + req.b)))
    return AddTwoIntsResponse(req.a + req.b)

def add_two_ints_server():
    rospy.init_node('add_two_ints_server')
    s = rospy.Service('add_two_ints', AddTwoInts, handle_add_two_ints)
    print("Ready to add two ints.")
    rospy.spin()

if __name__ == "__main__":
    add_two_ints_server()

编写客户端

#!/usr/bin/env python

from __future__ import print_function

import sys
import rospy
from beginner_tutorials.srv import *

def add_two_ints_client(x, y):
    rospy.wait_for_service('add_two_ints')
    try:
        add_two_ints = rospy.ServiceProxy('add_two_ints', AddTwoInts)
        resp1 = add_two_ints(x, y)
        return resp1.sum
    except rospy.ServiceException as e:
        print("Service call failed: %s"%e)

def usage():
    return "%s [x y]"%sys.argv[0]

if __name__ == "__main__":
    if len(sys.argv) == 3:
        x = int(sys.argv[1])
        y = int(sys.argv[2])
    else:
        print(usage())
        sys.exit(1)
    print("Requesting %s+%s"%(x, y))
    print("%s + %s = %s"%(x, y, add_two_ints_client(x, y)))

CMakeLists.txt

catkin_install_python(PROGRAMS scripts/add_two_ints_server.py scripts/add_two_ints_client.py
  DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

注意python脚本执行权限

chmod +x scripts/add_two_ints_server.py
chmod +x scripts/add_two_ints_client.py

录制和回放数据

mkdir ~/bagfiles
cd ~/bagfiles
rostopic list -v # 只有消息已经发布了才能被录制
rosbag record -a # 录制全部话题
rosbag info <your bagfile>
rosbag play <your bagfile>
rosbag record -O subset /turtle1/command_velocity /turtle1/pose # 录制特定话题,-O后面是数据保存的文件名称,以及两个要录制的话题

roswtf工具

# roswtf 可以检查你的ROS系统并尝试发现问题
# 安装检查(不运行roscore)
$ roscd
$ roswtf
# 运行时检查(运行roscore)
$ roscd
$ roswtf
# 错误报告
$ ROS_PACKAGE_PATH=bad:$ROS_PACKAGE_PATH roswtf

rqt用法

所有的rqt相关的用法,只能

rqt_console
rqt_plot

不能用rosrun rqt_plot rqt_plot

多package

如果使用ros指令比如roscd等发现package_name不唯一,会呈现一个列表供选择。

ROS的通信机制

遇到一个系统,不妨rqtgraph 从上帝视角看一看计算图
在这里插入图片描述

核心概念

在这里插入图片描述

  • 分布式通信体现在节点,各个节点可以存在于不同的计算机

  • 话题:我们要注意其 名称type。此外,话题可以是多对多,但一般pubisher只有一个,subscriber可以有多个。不然有多个节点发布一个速度指令,那机器人到底听谁的?

  • 服务:client发出请求,server会给我们回复.节点关系是一对多(一个server

  • 服务相对于话题:在第三步通过RPC返回TCP/IP的地址和端口号,而不是RPC地址信息.(参考古月居图书P18)

通信机制

  • 话题
  • 服务
  • 动作
    在这里插入图片描述
  • 比如机器人抓一个杯子(goal),抓没抓到,需要一直有一个反馈.突然不让抓了cancel
  • action底层是5个话题
    • goal
    • cancel
    • status
    • feedback:周期回发
    • result

ROS开发工具

命令行&编译器

在这里插入图片描述

Launch启动文件

通过XML文件实现多节点的配置和启动(可自动启动ROS Master),不用rosrun每一个节点

TF坐标变换库

  • 广播TF变换
  • 监听TF变换

Qt工具箱

Rviz

  • 三维可视化工具

Gazebo

  • 三维物理仿真平台

Rviz&Gazebo

  1. Rviz:有数据,渲染出来
  2. Gazebo:没有数据,仿真出来,创造出来
  3. 所以用Gazebo一般配合Rviz显示,单用Rviz时可不用Gazebo。

应用功能

导航框架

SLAM

MoveIt

  • 运动规划,默认用OMLP

SMACH任务级状态机

生态系统

  • 发行版
  • 软件源
  • ROS Wiki
  • 邮件列表
  • ROS Answer:咨询问题的平台
  • 博客(Blog)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值