# ROS2 ###### tags: `Learning Notes` ## Install ROS2 on Remote PC :::info $ wget https://raw.githubusercontent.com/ROBOTIS-GIT/robotis_tools/master/install_ros2_foxy.sh $ sudo chmod 755 ./install_ros2_foxy.sh $ bash ./install_ros2_foxy.sh ::: ## Install Dependent ROS2 Package 1. Install Gazebo11 :::info $ sudo apt-get install ros-foxy-gazebo-* ::: 2. Install Cartographer :::info $ sudo apt install ros-foxy-cartographer $ sudo apt install ros-foxy-cartographer-ros ::: 3. Install Navigation2 :::info $ sudo apt install ros-foxy-navigation2 $ sudo apt install ros-foxy-nav2-bringup ::: Tutorial ## Basic command 1. Build bridge btw ros1 & ros2v :::info $ ros2 run ros1_bridge dynamic_bridge ::: 2. source ( :warning: source ROS2 in every new terminal you open ) :::info source /opt/ros/foxy/setup.bash ::: 3. run package :::info $ ros2 run <package_name> <executable_file> ::: 4. launch file :::info $ ros2 launch <package_name> <launch_file> ::: 5. create package :::info $ ros2 pkg create <package_name> --build-type ament_cmake --dependencies <package_dependecies> ::: ex. ``` ros2 pkg create my_package --build-type ament_cmake --dependencies rclcpp ``` 6. Compile :::info :cactus: Full compile $ colcon build :cactus: Single pkg compile: $ colcon build --packages-select my_package ::: 7. source your workspace (after compilation) :::info source ~/ros2_ws/install/setup.bash ::: 8. Packages list in your ROS system. :::info $ ros2 pkg list ::: ## Basic operation 1. Build bridge :::info :tangerine: Ros1-bridge: $ . /home/user/.bashrc_bridge $ ros2 run ros1_bridge dynamic_bridge :tangerine:Ros1 as talker: $ . /home/user/.bashrc_ros1 $ rosrun rospy_tutorials talker :tangerine:Ros2 as listener: $ . /home/user/.bashrc_ros2 $ ros2 run demo_nodes_cpp listener :warning: This may not work on local computer if we don't roscore Ros1 at first. Also, cpp files and rospy_tutorail should be prepared at first. ::: 2. Node Composition- Publisher :::info :cake: like ROS1 structure in ROS2 ``` // Import all the necessary ROS libraries and import the Int32 message from the std_msgs package #include "rclcpp/rclcpp.hpp" #include "std_msgs/msg/int32.hpp" using namespace std::chrono_literals; int main(int argc, char * argv[]) { rclcpp::init(argc, argv); // Initiate a Node named 'simple_publisher' auto node = rclcpp::Node::make_shared("simple_publisher"); // Create a Publisher object that will publish on the /counter topic, messages of the type Int32 // The 10 indicates the size of the queue auto publisher = node->create_publisher<std_msgs::msg::Int32>("counter", 10); // Create a variable named 'message' of type Int32 auto message = std::make_shared<std_msgs::msg::Int32>(); // Initialize the 'message' variable message->data = 0; // Set a publish rate of 2 Hz rclcpp::WallRate loop_rate(2); // Create a loop that will go until someone stops the program execution while (rclcpp::ok()) { // Publish the message within the 'message' variable publisher->publish(*message); // Increment the 'message' variable message->data++; rclcpp::spin_some(node); // Make sure the publish rate maintains at 2 Hz loop_rate.sleep(); } rclcpp::shutdown(); return 0; } ``` ::: :::info :cake: Composable method in ROS2 node ``` #include "rclcpp/rclcpp.hpp" #include "std_msgs/msg/int32.hpp" #include <chrono> using namespace std::chrono_literals; /* This example creates a subclass of Node and uses std::bind() to register a * member function as a callback from the timer. */ class SimplePublisher : public rclcpp::Node //在class的後方加一個public rclcpp:Node 為公開繼承 rclcpp::Node { public: SimplePublisher() : Node("simple_publisher"), count_(0) { publisher_ = this->create_publisher<std_msgs::msg::Int32>("counter", 10); timer_ = this->create_wall_timer( 500ms, std::bind(&SimplePublisher::timer_callback, this)); } private: void timer_callback() { auto message = std_msgs::msg::Int32(); message.data = count_; count_++; publisher_->publish(message); } rclcpp::TimerBase::SharedPtr timer_; rclcpp::Publisher<std_msgs::msg::Int32>::SharedPtr publisher_; size_t count_; }; int main(int argc, char * argv[]) { rclcpp::init(argc, argv); rclcpp::spin(std::make_shared<SimplePublisher>()); rclcpp::shutdown(); return 0; } ``` :computer: Code analysis ![](https://i.imgur.com/4y1MSg5.png) ![](https://i.imgur.com/vSXdRpW.png) ::: 3. Node Composition- Subscriber :::info :cake: Composable method in ROS2 node ``` #include "rclcpp/rclcpp.hpp" #include "std_msgs/msg/int32.hpp" using std::placeholders::_1; class SimpleSubscriber : public rclcpp::Node { public: // Initiate a Node called 'simple_subscriber' SimpleSubscriber() : Node("simple_subscriber") { // Create a Subscriber object that will listen to the /counter topic and will call the 'topic_callback' function // each time it reads something from the topic subscription_ = this->create_subscription<std_msgs::msg::Int32>( "counter", 10, std::bind(&SimpleSubscriber::topic_callback, this, _1)); } private: // Define a function called 'topic_callback' that receives a parameter named 'msg' void topic_callback(const std_msgs::msg::Int32::SharedPtr msg) { // Print the value 'data' inside the 'msg' parameter RCLCPP_INFO(this->get_logger(), "I heard: '%d'", msg->data); } rclcpp::Subscription<std_msgs::msg::Int32>::SharedPtr subscription_; }; int main(int argc, char * argv[]) { rclcpp::init(argc, argv); // Create a loop that will keep the program in execution rclcpp::spin(std::make_shared<SimpleSubscriber>()); rclcpp::shutdown(); return 0; } ``` ::: ## Multiple Machines :spiral_note_pad: https://roboticsbackend.com/ros2-multiple-machines-including-raspberry-pi/ :spiral_note_pad:https://blog.csdn.net/zwwang2014/article/details/84849820 **1. get the IP address of each machine inside the network by hostname -I** **Example:** * Machine 1: ``` $ hostname -I 192.168.0.15 ``` * Machine 2: ``` $ hostname -I 192.168.0.16 ``` **2. ping each other** * Machine 1: ``` $ ping 192.168.0.16 PING 192.168.0.16 (192.168.0.16) 56(84) bytes of data. 64 bytes from 192.168.0.16: icmp_seq=1 ttl=64 time=128 ms 64 bytes from 192.168.0.16: icmp_seq=2 ttl=64 time=136 ms ``` * Machine 2: ``` $ ping 192.168.0.15 PING 192.168.0.15 (192.168.0.15) 56(84) bytes of data. 64 bytes from 192.168.0.15: icmp_seq=1 ttl=64 time=128 ms 64 bytes from 192.168.0.15: icmp_seq=2 ttl=64 time=136 ms ``` **3. source ROS2** ``` source /opt/ros/foxy/setup.bash #all machines ``` **4. export ROS_DOMAIN_ID** ``` export ROS_DOMAIN_ID=1 ``` ![](https://i.imgur.com/W0mFh3v.png) **5. ros run** **Talker <-> Listener** * Machine 1: ``` $ ros2 run demo_nodes_cpp talker Publishing: 'Hello World: 398' Publishing: 'Hello World: 399' Publishing: 'Hello World: 400' Publishing: 'Hello World: 401' Publishing: 'Hello World: 402' Publishing: 'Hello World: 403' Publishing: 'Hello World: 404' Publishing: 'Hello World: 405' ``` * Machine 2: ``` $ ros2 run demo_nodes_cpp listener I heard: [Hello World: 401] I heard: [Hello World: 402] I heard: [Hello World: 403] I heard: [Hello World: 404] I heard: [Hello World: 405] I heard: [Hello World: 406] I heard: [Hello World: 407] I heard: [Hello World: 408] I heard: [Hello World: 409] ``` **Turtle** * Machine 1: ``` $ ros2 run turtlesim turtlesim_node ``` * Machine 2: ``` $ ros2 run turtlesim turtle_teleop_key ``` Result: {%youtube YS7iIVrWx_E %} ## ROS2 tutorial ### Robotic Tutorials https://roboticsbackend.com/category/ros2/ ### ROS2 Project (Part1- node) https://medium.com/@thehummingbird/building-a-ros2-project-part-1-a2c02d6ac3d8 ### ROS2 學習集 https://www.twblogs.net/a/5ed7a214822643d04432b026