on
ROS2 Learning Note
Install ROS2 on Ubuntu
\$ sudo apt update
\$ sudo apt upgrade
\$ sudo apt install build-essential gcc make perl dkms
VirtualBox VM=>Device =>Insert Guest Additional CD Image
Then click run, after installation finished, restart the VM
If error like VBoxGuestAdditions.iso' (VERR_PDM_MEDIA_LOCKED)
Shut down all your VMs. And I don't mean "Saved State" or "Paused", but completely shut them down. If you already have them in "Saved State" or "Paused", then resume the VM and from within the guest OS shutdown the guest OS.
Then go to the menu File » Virtual Media Manager » Optical Disks » find the VBoxGuestAdditions.iso » select it and from the toolbar click (if enabled) the "Release" button, and then the "Remove" button.
follow the guide https://docs.ros.org/en/foxy/Installation.html
after install the ROS2, cd to /opt/ros/foxy
$ source setup.bash
Every time open a terminal, need to do source, like below
$ source /opt/ros/foxy/setup.bash
In order to avoiding that, we can do:
$ gedit ~/.bashrc
Add “source /opt/ros/foxy/setup.bash” at the bottom of .bashrc
install ROS2 compiler “colcon”
$sudo apt install python3-colcon-common-extensions
Add “source /usr/share/colcon_argcomplete/hook/colcon-argcomplete.bash” at the bottom of .bashrc
================================================================================
Create ROS2 workspace

Add "source ~/ros2_ws/install/setup.bash" at the bottom of ~/.bashrc
//create a Python package
sz@sz-VirtualBox:~/ros2_ws/src$ ros2 pkg create my_py_pkg --build-type ament_python --dependencies rclpy
// use colcon to compile all package in the workspace folder
sz@sz-VirtualBox:~/ros2_ws$ colcon build
// use colcon to compile the Python package
sz@sz-VirtualBox:~/ros2_ws$ colcon build --packages-select my_py_pkg
//create a C++ package
sz@sz-VirtualBox:~/ros2_ws/src$ ros2 pkg create my_cpp_pkg --build-type ament_cmake --dependencies rclcpp
// use colcon to compile the C++ package
sz@sz-VirtualBox:~/ros2_ws$ colcon build --packages-select my_cpp_pkg

================================================================================
Create ROS Node by Python
// Create my_first_node.py
sz@sz-VirtualBox:~/ros2_ws/src/my_py_pkg/my_py_pkg$ touch my_first_node.py
------------------------------------------
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
class MyNode(Node):
def __init__(self):
super().__init__("py_test")
self.counter_ = 0
self.get_logger().info("Hello ROS2")
self.create_timer(0.5, self.timer_callback)
def timer_callback(self):
self.counter_ += 1
self.get_logger().info(f"Hello {self.counter_}")
def main(args=None):
rclpy.init(args=args)
node = MyNode()
rclpy.spin(node)
rclpy.shutdown()
if __name__ == "__main__":
main()
------------------------------------------
// Change the file permissions
sz@sz-VirtualBox:~/ros2_ws/src/my_py_pkg/my_py_pkg$ chmod +x my_first_node.py
Execution Node Method#1 open the .py file
sz@sz-VirtualBox:~/ros2_ws/src/my_py_pkg/my_py_pkg$ ./my_first_node.py
// return below result
[INFO] [1617747746.924412563] [py_test]: Hello ROS2
Execution Node Method#2 configure the setup.py in SRC folder
------------------------------------------
entry_points={
'console_scripts': [
"py_node = my_py_pkg.my_first_node:main"
],
},
------------------------------------------
// colcon build
sz@sz-VirtualBox:~$ cd ros2_ws/
// run colcon build at the workspace directory "ros2_ws"
sz@sz-VirtualBox:~/ros2_ws$ colcon build --packages-select my_py_pkg
Starting >>> my_py_pkg
Finished <<< my_py_pkg [0.90s]
Summary: 1 package finished [1.20s]
// before execute the node, don't forget to source the workspace
sz@sz-VirtualBox:~/ros2_ws$ source ~/.bashrc
sz@sz-VirtualBox:~/ros2_ws$ cd install/my_py_pkg/lib/my_py_pkg/
sz@sz-VirtualBox:~/ros2_ws/install/my_py_pkg/lib/my_py_pkg$ ls
py_node
sz@sz-VirtualBox:~/ros2_ws/install/my_py_pkg/lib/my_py_pkg$ ./py_node
// return below result
[INFO] [1617751777.299029594] [py_test]: Hello ROS2
Execution Node Method#3 ROS command
configure the setup.py and colcon build pkg as the Method#2
sz@sz-VirtualBox:~/ros2_ws$ colcon build --packages-select my_py_pkg
sz@sz-VirtualBox:~$ source .bashrc
// don't forget to source, "py_node" is the name defined in setup.py
sz@sz-VirtualBox:~$ ros2 run my_py_pkg py_node
// return below result
[INFO] [1617752823.005040235] [py_test]: Hello ROS2
================================================================================
Create ROS Node by C++
// Create my_first_node.cpp
sz@sz-VirtualBox:~/ros2_ws/src/my_cpp_pkg/src$ touch my_first_node.cpp
------------------------------------------
// need to edit c_cpp_properties.json first include the path
#include "rclcpp/rclcpp.hpp"
// MyNode is child class of rclcpp::Node
class MyNode: public rclcpp::Node {
public:
int counter_ = 0;
// MyNode() is class constructor, inherite from parent Node.Node()
// constructor will be automatically called when an object of a class is created.
//To create a constructor, use the same name as the class, followed by parentheses ()
MyNode():Node("cpp_test") {
// "this" is the class pointer
RCLCPP_INFO(this->get_logger(), "Hello Cpp Node");
// std::bind took 1st parameter a function i.e. &MyFunc, then its arguments as _1 & _2 as his own arguments.
// below std::bind returns a function object
// original func timer_callback() has no arguments, no _1 , _2, etc.
// bind_func_OBJ is just calling class MyNode member function timer_callback()
auto bind_func_OBJ = std::bind(&MyNode::timer_callback, this);
// ‘\n’ single quotes are needed. When embedded into text double-quoted, single quotes aren’t needed.
// Prefer ‘\n’ over std::endl when outputting text to the console
std::cout << "std::bind(&MyNode::timer_callback, this)= " << &bind_func_OBJ << '\n';
timer_ = this->create_wall_timer(std::chrono::milliseconds(500), bind_func_OBJ);
}
private:
rclcpp::TimerBase::SharedPtr timer_;
void timer_callback() {
counter_ += 1;
// "Hello %d", counter_ is similar to printf
RCLCPP_INFO(this->get_logger(), "Hello %d", counter_);
}
};
int main(int argc, char **argv) {
rclcpp::init(argc, argv);
//make_shared created the Node class instance and node shared_ptr at one time
//node is shared_ptr, "std::" equal to "using namespace std;"
auto node = std::make_shared<MyNode>();
// spin() need to input the Node class shared_ptr
rclcpp::spin(node);
rclcpp::shutdown();
return 0;
}
------------------------------------------
// Add below code to CMakeList.txt
------------------------------------------
add_executable(cpp_node src/my_first_node.cpp)
ament_target_dependencies(cpp_node rclcpp)
install(TARGETS
cpp_node
DESTINATION lib/${PROJECT_NAME}
)
------------------------------------------
// Build the executable "cpp_node"
sz@sz-VirtualBox:~/ros2_ws$ colcon build --packages-select my_cpp_pkg
// Run the "cpp_node"
sz@sz-VirtualBox:~$ source .bashrc
sz@sz-VirtualBox:~/ros2_ws$ ros2 run my_cpp_pkg cpp_node
================================================================================
ROS2 CommandLineTools and Turtlesim
ros2 CLI can be executed at the home directory.
// rename node (only on the fly) from "py_node" to "abc" when run it
$ ros2 run my_py_pkg py_node --ros-args --remap __node:=abc
// within workspace directory, only for python, colcon build --symlink,
// automatially build the node executable
// must make pkg executable first, chmod +x some.py
$ colcon build --packages-select my_py_pkg --symlink-install
$ rqt // open ROS Qt GUI toolkit
$ rqt_graph
$ ros2 run turtlesim turtlesim_node
$ ros2 run turtlesim turtle_teleop_key
$ ros2 topic info /robot_news
$ ros2 topic hz /robot_news
$ ros2 topic bw /robot_news
// chech the existed msg type
$ ros2 interface show example_interfaces/msg/String
// check the topic list
$ ros2 topic list
// after run publisher now, check the publisher msg
$ ros2 topic echo /robot_news
// -r rate 2 hertz
$ ros2 topic pub -r 2 /robot_news example_interfaces/msg/String "{data: 'Hello from terminal~'}"
// change node name and change topic name
$ ros2 run my_py_pkg robot_news_station --ros-args -r __node:=my_station -r robot_news:=my_news
================================================================================
End