Some Basic Usage of ROS
Installation
ROS Wiki
- http://wiki.ros.org/
- Install
- Tutorials
ROS work with Anaconda
在Anaconda虚拟python3环境中运行ROS包或用python import rospy
时会出现:
ImportError: No module named rospkg
通过conda deactivate
命令退出Anaconda环境之后,一切恢复正常。
原因:
- ROS只支持python2.7的调用,对python3不支持。
- 无法在Anaconda中导入rospy是由于环境中没有相应的包。
解决办法:
在Anaconda环境中安装相应的依赖包:
$ conda install setuptools
$ pip install -U rosdep rosinstall_generator wstool rosinstall six vcstools
结果:
(env-name) csy@UAV:~$ python
Python 3.6.12 |Anaconda, Inc.| (default, Sep 8 2020, 23:10:56)
[GCC 7.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import rospy
>>>
Basic Usage
rostopic
list
info
echo
pub
hz
rosmsg
rosmsg show std_msgs/String
Write a ROS Node with C++ or Python
#include
#include <ros/ros.h>
: includes all the headers necessary to use the most common public pieces of the ROS system.#include <std_msgs/String.h>
: includes the std_msgs/String message.- Also, other
message hearer files
which are used in thetopics
should be included in the code.
Using Python:
import rospy
from std_msgs.msg import String
ros::init()
- Initialize ROS node.
- Specify the
name of the node
, node names must be unique in the running system. - needs to see
argc
andargv
so that it can perform any ROS arguments and name remapping that were provided at the command line. - must call
ros::init()
before using any other part of the ROS system.
ros::init(argc, argv, "talker");
Using Python:
rospy.init_node('talker', anonymous=True)
ros::NodeHandle n
NodeHandle
is the main access point to communications with the ROS system.- The first
NodeHandle
constructed will fully initialize the node. - The last
NodeHandle
destructed will close down the node.
ros::Publisher
- Tell the master that we are going to publish a message.
- Let the master tell any nodes listening that we are going to publish data on that topic.
NodeHandle::advertise
: returns aros::Publisher
object.- contains a
publish()
method that lets you publish messages onto thetopic
which was created with. - when it goes out of scope, it will automatically unadvertise.
- contains a
ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
chatter_pub.publish(msg);
The second argument is the size of publishing queue. In this case if we are publishing too quickly, it will buffer up a maximum of 1000 messages before beginning to throw away old ones.
Using Python:
pub = rospy.Publisher('chatter', String, queue_size=1000)
pub.publish(msg)
ros::Subscriber
- subscribe to the
topic
with the master. - ROS will call the
callback()
function whenever a new message arrives. NodeHandle::subscribe()
renturns aros::Subscriber
object.
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
ROS_INFO("I heard: [%s]", msg->data.c_str());
}
ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
Using Python:
def callback(data):
rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.data)
rospy.Subscriber("chatter", String, callback)
ros::Rate
- allows you to specify a frequency to loop at.
- keep track of how long it has been since the last call to
Rate::sleep()
.
ros::Rate loop_rate(10);
loop_rate.sleep();
In this case, the loop run at 10Hz.
Using Python:
rate = rospy.Rate(10)
rate.sleep()
ros::Duration
Duration
is a period of time.
ros::Duration five_seconds(5.0);
ros::Duration two_hours = ros::Duration(60*60) + ros::Duration(60*60);
ros::Duration(3.0).sleep(); // sleep for 3 seconds
ros::Time
Time
is a specific moment.
ros::Time begin_time = ros::Time::now(); // get the current time
ros::Time tomorrow = ros::Time::now() + ros::Duration(24*60*60);
ros::ok()
ros::ok()
will returnfalse
if:Ctrl+C
.- kick off the network by another node with the same name.
ros::shutdown()
has been called by another part of the application.- all
ros::NodeHandle
has been destroyed.
while (ros::ok())
{
}
Using Python:
while not rospy.is_shutdown():
pass
ROS_INFO()
- replacement for
printf/cout
. - http://wiki.ros.org/rosconsole
ROS_INFO("%s", msg.data.c_str());
Using Python:
hello_str = "hello world %s" % rospy.get_time()
rospy.loginfo(hello_str)
ros::spin()
and ros::spinOnce()
订阅消息
回调处理函数,出现在ROS主函数中。- 基于ROS的消息发布、订阅机制,ROS会自动再后台
接收订阅的消息
,接收到的消息不会立即处理,必须等到回调处理函数
执行时才被调用。 - 如果程序中有消息订阅函数,则必须加上该回调处理函数,否则无法接收消息。
ros::spin()
: enter a loop, pumping callbacks via subscribe topics as fast as possible.- 调用后不再返回,主程序不会再执行此函数之后的程序。
- 一般不会出现在循环中,出现在主函数末尾。
- will not use much CPU if there is nothing for it to do.
- exit when
ctrl+C
is pressed or the node is shutdown by the master.
ros::spinOnce()
:- 调用后主程序还可以继续执行之后的程序。
- 可以出现在循环中。
- 需要注意
消息池
和调用频率
的协调性,避免消息丢失或延迟:- 消息池 \(\ge\) 消息接收频率 / 调用频率。
Using Python:
rospy.spin()
ros::Timer
- 在某一频率下执行一次回调操作。
- 可用于固定频率
消息
的发布,不受ros::spin()
的影响。 - 在
订阅
或服务
中的回调函数队列中使用。
ros::Timer timer = n.createTimer(ros::Duration(0.1), timerCallback, bool oneshot = false);
void timerCallback(const ros::TimerEvent& event)
{
}
ros::Duration(0.1)
: 每0.1秒执行一次。oneshot
: 表示是否只执行一次。
Using Python:
rospy.Timer(rospy.Duration(0.1), my_callback, oneshot=False)
def my_callback(event):
print('Timer called at ' + str(event.current_real))