# 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


:::
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
```

**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