Followed the videos on the YouTube channel ROS Tutorials - ROS Noetic For Beginners
and Bilibili channel (in Chinese) 【古月居】古月·ROS入门21讲 | 一学就会的ROS机器人入门教程-哔哩哔哩】.
Our package is named as robot_motion_ctrl
.
cd to the catkin_ws
, source the /devel/setup.bash
:
$ cd ros_tutorial/catkin_ws/
$ source devel/setup.bash
launch the ros master
$ roscore
run a turtlrsim node to visualize the turtle
$ rosrun turtlesim turtlesim_node
run a keyboard control node
$ rosrun turtlesim turtle_teleop_key
- run a turtlesim node:
$ rosrun turtlesim turtlesim_node
- run a publisher to give the msg
/turtle1/cmd_vel
to the turtle:
$ rosrun robot_motion_ctrl pub_draw_circle.py
- run a turtlrsim node:
$ rosrun turtlesim turtlesim_node
- run the subscriber to get the msg
/turtle1/pose
:
$ rosrun robot_motion_ctrl sub_pose.py
- make the turtle to move using either keyboard cmd:
$ rosrun turtlesim turtle_teleop_key
or draw a circle:
$ rosrun robot_motion_ctrl pub_draw_circle.py
make the turtle to cruise within an area, and change the pen color using ros service when crossing the middle.
- run a turtlrsim node:
$ rosrun turtlesim turtlesim_node
- run the ros node, which publishes velocity command to the turtle, and subscribes pose information from the turtle. In the meanwhile change the pen color using ros service according to the turtle's current pose.
$ rosrun robot_motion_ctrl turtle_ctrl.py
$ rqt_graph
$ rostopic list
$ rosnode info /turtlesim
you will get information about what this node publishes and subscribes.
by default (hit the tab-key twice to fill automatically):
$ rostopic pub /turtle1/cmd_vel geometry_msgs/Twist "linear:
x: 0.0
y: 0.0
z: 0.0
angular:
x: 0.0
y: 0.0
z: 0.0"
publish the message frequently (e.g at 10 Hz): add -r 10
after pub
$ rostopic pub -r 10 /turtle1/cmd_vel geometry_msgs/Twist "linear:
x: 1.0
y: 0.0
z: 0.0
angular:
x: 0.0
y: 0.0
z: 0.0"
$ rosmsg show geometry_msgs/Twist
$ rosservice list
$ rosservice call /spawn "x: 2.0
y: 2.0
theta: 0.0
name:'turtle2'"
get a message in the terminal: name: "turtle2"
, means that the new turtle is created successfully.
record a rosbag:
$ rosbag record -a -O cmd_record
the command stream would be saved as cmd_record.bag
.
play a rosbag:
launch the ros-master and launch a turtlesim node, then:
$ rosbag play cmd_record.bag
the turtle will start to move from the current position according to what was recorded.
Follow the Ubuntu install of ROS Noetic on the ROS wiki if you are using Ubuntu. For other OS you can also find the corresponding installation guide on ROS wiki.
Tips: there is also a convienent way that can install ROS with a one-line command.
First create a project folder to contain all the data as well as the code you would need.
Under the Project folder, create a folder as ROS workspace, e.g. catkin_ws
, and then under catkin_ws
create a blank folder src
to contain the executable code scripts.
create and initialize a workspace
$ mkdir -p~/catkin_ws/src
$ cd ~/catkin_ws/src
$ catkin_init_workspace
the command $ catkin_init_workspace
would create a cmake symlink of our workspace to the root ROS-cmake in our OS.
compile the workspace
$ cd ~/catkin_ws/
$ catkin build
Hint: There's another command to compile the ROS workspace:
$ catkin_make
ATTENTION
catkin_make
and catkin build
are of different mechanism. Make sure build a workspace with ONLY one of them all the way, rather than combine them at the same time.
Check out the differences between $ catkin build
and $ catkin_make
, see this.
set the env-variable
$ source devel/setup.bash
check the env-variable
$ echo $ROS_PACKAGE_PATH
This would return ALL the registered ROS package paths.
cd to catkin_ws/src/
and run
$ catkin_create_pkg robot_motion_ctrl rospy turtlesim
The syntax is
$ catkin_create_pkg <pkg_name> [depend1] [depend2] [depend3] [depend...]
to create a ROS package named robot_motion_ctrl
, with the dependencies of rospy
and a ROS built-in tutorial project turtlesim
.
Each ROS packages can be seen as a sub-APP of the whole APP, which covers certain functionalities.
The ros package would contain two special files: CMakeLists.txt
and package.xml
, which determine that this folder has the ROS-package property.
Besides, the package folder would also contain an src
folder.
Tips:
- There COULD NOT be packages of the same name under one workspace.
- In different workspaces there COULD be packages of the same name.
cd back to catkin_ws
, run $ catkin build
to generalize files for ROS communications.
In this Tutorial we will get familiar with the topic
mechanism. We will learn to write the node in both Python and C++.
Here we created the package named learning_topic
instead of robot_motion_ctrl
above.
Under the package folder /learning_topic
we have the folder /scripts
containing the .py scripts and the folder /src
containing .cpp scripts.
Write the node:
$ cd catkin_ws/src/learning_topic/src/
$ touch velocity_publisher.cpp
$ code .
And write your code using VSCode.
Generate the .exe file:
With the finished .cpp file, we need to make it as an executable file and link the required libs.
Go to catkin_ws/src/learning_topic
and edit the CMakeLists.txt
, add these two lines under the tag ### Build ###
:
add_executable(velocity_publisher src/velocity_publisher.cpp)
-> creates an executable file out of the .cpp script, saved in ~/catkin_ws/devel/lib/<pkg_name>/
.
target_link_libraries(velocity_publisher ${catkin_LIBRARIES})
-> links the required libs.
Compile and run the Publisher:
$ cd ~/catkin_ws
$ catkin_make
$ source devel/setup.bash
$ roscore # in Sub-Terminal A
$ rosrun turtlesim_node # in Sub-Terminal B
$ rosrun learning_topic velocity_publisher # in Sub-Terminal C
Tips:
Every time we have modified the .cpp scripts we need to rerun catkin_make
to update the .exe file.
For Python we don't need rerun the catkin_make
after modifying the scripts, because the exe file is exactlly the .py file, which was converted by the command
$ chmod +x node.py
Write the node:
$ cd catkin_ws/src/learning_topic/scripts/
$ touch velocity_publisher.py
$ code .
And write your code using VSCode.
ALWAYS write
#!/use/bin/env python3
at the very begining of the .py script to make sure that it could be compiled by ROS successfully.
Generate the .exe file:
$ cd catkin_ws/src/learning_topic/scripts/
$ chmod +x velocity_publisher.py
Compile and run the Publisher:
$ cd ~/catkin_ws
$ catkin_make
$ source devel/setup.bash
$ roscore # in Sub-Terminal A
$ rosrun turtlesim_node # in Sub-Terminal B
$ rosrun learning_topic velocity_publisher.py # in Sub-Terminal C
For the Python scripts we DO NOT need to rebuild after modifying the code.
Previously we have got familiar with the pre-defined ROS message types like turtlesim::Pose
, geometry_msgs::Twist
.
Now we try to define a new message type learning_topic::Person
basing on our demand to publish the information of a person.
# Person.msg
string name
uint8 sex
uint8 age
uint8 unknown = 0
uint8 male = 1
uint8 female = 2
- <build_depend>message_generation</build_depend>
- <exec_depend>message_runtime</exec_depend>
- In bracket find_package()
find_package(... message_generation) - Under ## Declare ROS messages, services and actions ##
add_message_files(FILES Person.msg)
generate_messages(DEPENDENCIES std_msgs) - In bracket catkin_package()
catkin_package(CATKIN_DEPENDS... message_runtime)
This would generate Person.h
in /devel/include/<pkg_name=learning_topic>/
Add
- add_executable(person_publisher src/person_publisher.cpp
- target_link_libraries(person_publisher ${catkin_LIBRARIES})
- add_dependencies(person_publisher ${PROJECT_NAME}_generate_messages_cpp)
below ## Build ## tag, and also for person_subscriber
$ cd ~/catkin_ws
$ catkin_make
$ source devel/setup.bash
$ roscore # in sub-window A
$ rosrun learning_topic person_subscriber # in sub-window B
$ rosrun learning_topic person_publisher # in sub-window C
In this Tutorial we will get familiar with the service
mechanism. We will learn to write the node in both Python and C++. We create a new package named learning_service
.
With the service mechanism we will try to
- add another turtle into the turtlesim:
- Request a srv named
/spawn
, of typeturtlesim::Spawn
$ cd ~/catkin_ws
$ catkin_create_pkg learning_service roscpp rospy std_msgs geometry_msgs turtlesim
The basic pipeline for a ROS-Client is:
- Initialize a ROS node;
- Create a Client object;
ros::service::waitForService("/spawn"); // LOOP BLOCKING
ros::ServiceClient add_turtle = node.serviceClient<turtlesim::Spawn>("/spawn");
- Request to call a service;
- Wait for the result of the Server's response.
Before catkin_make:
- C++
Don't forget to add the lines below into theCMakeLists.txt
to generate exe file.
add_executable(turtle_spawn src/turtle_spawn.cpp)
target_link_libraries(turtle_spawn ${catkin_LIBRARIES})
- Python
Don't forget to set the property of .py script as exe.
$ chmod +x turtle_spawn.py
$ cd ~/catkin_ws
$ catkin_make
$ source devel/setup.bash
$ roscore
$ rosrun turtlesim turtlesim_node
$ rosrun learning_service turtle_spawn # exe from .cpp
$ rosrun learning_service turtle_spawn.py # exe from .py
With the service mechanism we will try to
- switch the turtle to move or stay:
- Request a srv named
/turtle_command
, of typestd_srvs::Trigger
The basic pipeline for defining a ROS-Server is:
- Initialize a ROS node;
- Create a Server object;
- Wait for a service request. Get into the Callback() when getting request;
- Implement the server functions in the Callback(), return the Response data.
We skip the common steps mentioned before.
Just don't forget to add the lines in CMakeKists.txt for C++, and to chmod for Python before compiling and running.
$ cd ~/catkin_ws
$ catkin_make
$ source devel/setup.bash
$ roscore
$ rosrun turtlesim turtlesim_node
$ rosrun learning_service turtle_command_server
$ rosservice call /turtle_command "{}" # "{}" can be completed automatically by hitting TAB twice
# "{}" means this service does not need a request.
In the Chapter 8) we have used a pre-defined Service type std_srvs::Trigger
.
Now We try to define a service type learning_service::Person
basing on our demands.
# Person.srv
string name
uint8 sex
uint8 age
uint8 unknown = 0
uint8 male = 1
uint8 female = 2
---
string result
Where above the ---
is the Request and below ---
is the Response.
# .srv
Req
---
Res
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
- find_package(... message_generation)
- add_service_files(FILES Person.srv)
generate_messages(DEPENDENCIES std_msgs) - catkin_package(CATKIN_DEPENDS... message_runtime)
This would generate Person.h
, PersonRequest.h
and PersonResponse.h
in /devel/include/<pkg_name=learning_service>/
see pipelines in 7.2) for Client and in 8) for Server.
add_executable
set the to-be-compiled .cppcfile and the to-be-generated .exe filetarget_link_libraries
set the link libsadd_dependencies
add the dependencies
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
$ rosrun learning_service person_server
$ rosrun learning_service person_client
Run the Server first:
The Server waits for the Client's request.
Run the Client first:
The Client would hang om, waiting for the Server to be launched.