准备好的空的工作空间
.
├── build
├── devel
└── src
├── beginner_tutorials
│ ├── include
│ ├── src
│ ├── package.xml
│ └── CMakeLists.txt
└── CMakeLists.txt -> /opt/ros/melodic/share/catkin/cmake/toplevel.cmake
#如果你运行了catkin_make,那么build和devel内将会生存许多文件,此处我隐藏了
#此处的beginner_tutorials即为ros包,其下文件在你建立时就自动生成了
$ catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
重点在于此处
beginner_tutorials
├── include
├── src
├── package.xml
└── CMakeLists.txt
说明
1、全文代码来自:http://wiki.ros.org/cn/ROS/Tutorials
2、先跑成功代码,再理解代码
3、大家可以使用类似vscode的ide开发,文件目录看起来将会清晰很多
4、版本ubuntu18.04.1+ROS Melodic
msg创建和直接使用(如果涉及的话,自行修改Num.msg)
1、在~/catkin_ws/src/beginner_tutorials/下:
2、
创建文件夹 $ mkdir msg
写入:$ echo “int64 num” > msg/Num.msg
3、修改CMakeLists.txt (使用notepadqq打开并调整语言为cmake方便查看)
- 在find_packag函数添加message_generation #利用find_packag函数增加对message_generation的依赖
第10行
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
- 找到add_message_files()代码块,去掉注释符号#,用你的Num.msg文件替代Message*.msg: #设置运行依赖
第51行
add_message_files(
FILES
Num.msg
)
- 找到generate_messages()代码块,去掉注释符号#: #确保CMake知道在什么时候重新配置我们的project
第72行
generate_messages(
DEPENDENCIES
std_msgs
)
4、修改package.xml (使用notepadqq打开并调整语言为yml方便查看)
在下列代码后
<buildtool_depend>catkin</buildtool_depend>
<build_depend>roscpp</build_depend>
<build_depend>rospy</build_depend>
<build_depend>std_msgs</build_depend>
<build_export_depend>roscpp</build_export_depend>
<build_export_depend>rospy</build_export_depend>
<build_export_depend>std_msgs</build_export_depend>
<exec_depend>roscpp</exec_depend>
<exec_depend>rospy</exec_depend>
<exec_depend>std_msgs</exec_depend>
添加
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
#构建时需要"message_generation",运行时需要"message_runtime"。
5、在~/catkin_ws/下:$ catkin_make #重新编译
6、测试运行:$ rosmsg show beginner_tutorials/Num
返回:int64 num
cpp版
1、在~/catkin_ws/src/beginner_tutorials/src/下新建文件talker.cpp
2、写入:
#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
/**
* 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");
/**
* 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);
ros::Rate loop_rate(10);
/**
* 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())
{
/**
* This is a message object. You stuff it with data, and then publish it.
*/
std_msgs::String msg;
std::stringstream ss;
ss << "hello world " << count;
msg.data = ss.str();
ROS_INFO("%s", msg.data.c_str());
/**
* 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);
ros::spinOnce();
loop_rate.sleep();
++count;
}
return 0;
}
3、在~/catkin_ws/src/beginner_tutorials/src/下新建文件listener.cpp
4、写入:
#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());
}
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, "listener");
/**
* 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 subscribe() call is how you tell ROS that you want to receive messages
* on a given topic. This invokes a call to the ROS
* master node, which keeps a registry of who is publishing and who
* is subscribing. Messages are passed to a callback function, here
* called chatterCallback. subscribe() returns a Subscriber object that you
* must hold on to until you want to unsubscribe. When all copies of the Subscriber
* object go out of scope, this callback will automatically be unsubscribed from
* this topic.
*
* The second parameter to the subscribe() function is the size of the message
* queue. If messages are arriving faster than they are being processed, this
* is the number of messages that will be buffered up before beginning to throw
* away the oldest ones.
*/
ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
/**
* ros::spin() will enter a loop, pumping callbacks. With this version, all
* callbacks will be called from within this thread (the main one). ros::spin()
* will exit when Ctrl-C is pressed, or the node is shutdown by the master.
*/
ros::spin();
return 0;
}
5、在 ~/catkin_ws/src/beginner_tutorials/CMakeLists.txt 文件末尾加入几条语句:
## 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)
6、回到~/catkin_ws/下:
$ catkin_make
#会生成两个可执行文件(exe/二进制), talker 和 listener, 默认存储到~/catkin_ws/devel/lib/ 中.
7、运行测试
开一个终端:$ roscore
再开一个终端:$ rosrun beginner_tutorials talker
返回:
[ INFO] [1581865490.444930807]: hello world 0
[ INFO] [1581865490.545128438]: hello world 1
[ INFO] [1581865490.645065811]: hello world 2
[ INFO] [1581865490.745070716]: hello world 3
[ INFO] [1581865490.845138578]: hello world 4
[ INFO] [1581865490.945071648]: hello world 5
[ INFO] [1581865491.045091994]: hello world 6
[ INFO] [1581865491.145070603]: hello world 7
[ INFO] [1581865491.245145005]: hello world 8
[ INFO] [1581865491.345067172]: hello world 9
[ INFO] [1581865491.445034335]: hello world 10
……
再开一个终端:$ rosrun beginner_tutorials listener
返回:(不从hello world 1开始是因为你开启listener手速不够快)
[ INFO] [1581865578.794471324]: I heard: [hello world 3]
[ INFO] [1581865578.894540946]: I heard: [hello world 4]
[ INFO] [1581865578.994505421]: I heard: [hello world 5]
[ INFO] [1581865579.094627608]: I heard: [hello world 6]
[ INFO] [1581865579.194470014]: I heard: [hello world 7]
[ INFO] [1581865579.294641536]: I heard: [hello world 8]
[ INFO] [1581865579.394334407]: I heard: [hello world 9]
[ INFO] [1581865579.494577127]: I heard: [hello world 10]
……
要是运行失败,可以尝试在开启的终端内先运行source ~/catkin_ws1/devel/setup.bash(无返回)
先稍微理解一下node和topic
运行:$ rqt_graph
node_name1:/talker
node_name2:/listener
topic:/chatter
ros的话题命令,查看所有操作:$ rostopic -h
命令 | 返回 |
---|---|
$ rostopic list | topic_name列表/话题列表 |
$ rostopic echo [topic_name] | topic_msg/话题内的消息 |
$ rostopic type [topic_name] | msg_type/消息的数据类型 |
$ rostopic pub [-1] <topic_name> <msg_type> [-r 1] – [args] [args] | 向topic发布消息 |
$ rosmsg show [msg_type] #查看具体的数据类型
可以键入:$ rostopic type [topic_name]|rosmsg show #直接查看具体的数据类型
ros的节点命令,查看所有操作:$ rosnode -h
命令 | 返回 |
---|---|
$ rosnode list | node_name列表/正在运行的节点列表 |
$ rosnode info [node_name] | 节点信息 |
$ rosrun [package_name] [node_name] [__name:=new_name] #运行node
python版
可以把程序放在一起问题不大,我还是放在src下
1、在~/catkin_ws/src/beginner_tutorials/src/下新建文件talker.py
2、
修改权限为可执行:$ chmod +x talker.py
写入:
#!/usr/bin/env python
# license removed for brevity
import rospy
from std_msgs.msg import String
def talker():
pub = rospy.Publisher('chatter', String, queue_size=10)
rospy.init_node('talker', anonymous=True)
rate = rospy.Rate(10) # 10hz
while not rospy.is_shutdown():
hello_str = "hello world %s" % rospy.get_time()
rospy.loginfo(hello_str)
pub.publish(hello_str)
rate.sleep()
if __name__ == '__main__':
try:
talker()
except rospy.ROSInterruptException:
pass
1、在~/catkin_ws/src/beginner_tutorials/src/下新建文件listener.py
2、
修改权限为可执行:$ chmod +x listener.py
写入:
#!/usr/bin/env python
import rospy
from std_msgs.msg import String
def callback(data):
rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.data)
def listener():
# In ROS, nodes are uniquely named. If two nodes with the same
# name are launched, the previous one is kicked off. The
# anonymous=True flag means that rospy will choose a unique
# name for our 'listener' node so that multiple listeners can
# run simultaneously.
rospy.init_node('listener', anonymous=True)
rospy.Subscriber("chatter", String, callback)
# spin() simply keeps python from exiting until this node is stopped
rospy.spin()
if __name__ == '__main__':
listener()
6、回到~/catkin_ws/下:
$ catkin_make
#python为解释型语言不生成可执行文件,本身的py文件权限改成可执行就行了
7、运行测试
开一个终端:$ roscore
再开一个终端:$ rosrun beginner_tutorials talker.py
返回:
[INFO] [1581868522.071705]: hello world 1581868522.07
[INFO] [1581868522.171934]: hello world 1581868522.17
[INFO] [1581868522.272094]: hello world 1581868522.27
[INFO] [1581868522.372026]: hello world 1581868522.37
[INFO] [1581868522.471961]: hello world 1581868522.47
[INFO] [1581868522.572049]: hello world 1581868522.57
[INFO] [1581868522.671977]: hello world 1581868522.67
[INFO] [1581868522.771972]: hello world 1581868522.77
[INFO] [1581868522.871970]: hello world 1581868522.87
[INFO] [1581868522.971982]: hello world 1581868522.97
[INFO] [1581868523.071908]: hello world 1581868523.07
[INFO] [1581868523.171972]: hello world 1581868523.17
……
再开一个终端:$ rosrun beginner_tutorials listener.py
返回:(不从hello world 1开始是因为你开启listener手速不够快)
[INFO] [1581868522.075153]: /listener_28996_1581868519984I heard hello world 1581868522.07
[INFO] [1581868522.174737]: /listener_28996_1581868519984I heard hello world 1581868522.17
[INFO] [1581868522.275262]: /listener_28996_1581868519984I heard hello world 1581868522.27
[INFO] [1581868522.375315]: /listener_28996_1581868519984I heard hello world 1581868522.37
[INFO] [1581868522.475189]: /listener_28996_1581868519984I heard hello world 1581868522.47
[INFO] [1581868522.575409]: /listener_28996_1581868519984I heard hello world 1581868522.57
[INFO] [1581868522.675172]: /listener_28996_1581868519984I heard hello world 1581868522.67
[INFO] [1581868522.775182]: /listener_28996_1581868519984I heard hello world 1581868522.77
[INFO] [1581868522.875275]: /listener_28996_1581868519984I heard hello world 1581868522.87
[INFO] [1581868522.975219]: /listener_28996_1581868519984I heard hello world 1581868522.97
[INFO] [1581868523.075204]: /listener_28996_1581868519984I heard hello world 1581868523.07
[INFO] [1581868523.175072]: /listener_28996_1581868519984I heard hello world 1581868523.17
……
要是运行失败,可以尝试在开启的终端内先运行source ~/catkin_ws1/devel/setup.bash(无返回)
再稍微理解一下node和topic
关闭所有节点,重新开始:
$ roscore
$ rosrun beginner_tutorials talker.py
$ rosrun beginner_tutorials listener #cpp
$ rosrun beginner_tutorials listener.py #python
运行:$ rqt_graph
node_name1:/talker_29082_1581868746325
node_name2:/listener #cpp
node_name3:/listener_29105_1581868754753 #python
topic:/chatter
至此,你的工作空间变成如下:
.
├── build
├── devel
│ ├── cmake.lock
│ ├── env.sh
│ ├── lib
│ │ ├── beginner_tutorials
│ │ │ ├── listener
│ │ │ └── talker
│ │ └── pkgconfig
│ │ └── beginner_tutorials.pc
│ ├── local_setup.bash
│ ├── local_setup.sh
│ ├── local_setup.zsh
│ ├── setup.bash
│ ├── setup.sh
│ ├── _setup_util.py
│ ├── setup.zsh
│ └── share
└── src
├── beginner_tutorials
│ ├── CMakeLists.txt
│ ├── include
│ │ └── beginner_tutorials
│ ├── package.xml
│ └── src
│ ├── listener.cpp
│ ├── listener.py
│ ├── talker.cpp
│ └── talker.py
└── CMakeLists.txt -> /opt/ros/melodic/share/catkin/cmake/toplevel.cmake
#build和devel内有很多文件,此处我隐藏了,可以看到~/catkin_ws/devel/lib/下
#有talker.cpp和listener.cpp编译生成的可执行文件talker和listener