# 네임스페이스와 리매핑 실습

#### 네임스페이스 설정 개요

네임스페이스는 ROS2에서 노드와 토픽의 이름을 체계적으로 관리하고 그룹화할 수 있는 중요한 개념이다. 이를 통해 같은 이름을 사용하는 여러 노드나 토픽을 충돌 없이 관리할 수 있다. 기본적으로, ROS2에서 네임스페이스를 설정하면 해당 네임스페이스 내의 모든 노드나 토픽에 적용되며, 전체 시스템 구조를 명확히 할 수 있는 이점이 있다.

#### 네임스페이스 예시

네임스페이스를 설정하는 가장 간단한 예시는 노드를 특정 네임스페이스 안에 배치하는 것이다. 예를 들어, 로봇의 네임스페이스를 `/robot1`, `/robot2`로 설정하면, 각각의 로봇이 동일한 노드나 토픽 이름을 사용할 때 충돌을 피할 수 있다. 아래의 코드를 참조하라.

```bash
ros2 run <패키지 이름> <노드 이름> --ros-args --namespace /robot1
```

이 명령어는 노드를 `/robot1` 네임스페이스 안에서 실행하게 하여, 해당 노드의 이름이 `/robot1/<노드 이름>`로 설정된다.

#### 네임스페이스와 토픽 이름

토픽 이름도 네임스페이스에 따라 달라진다. 예를 들어, `/robot1/cmd_vel`과 `/robot2/cmd_vel` 토픽은 서로 다른 로봇의 명령을 전달할 수 있는 독립적인 경로를 갖는다.

이를 수식으로 표현하면, 각 로봇의 토픽 경로는 다음과 같이 정의될 수 있다:

$$
\text{토픽 경로} = \text{네임스페이스} + \text{토픽 이름}
$$

따라서 로봇 1의 `cmd_vel` 토픽은:

$$
\mathbf{T}\_\text{robot1} = /\text{robot1}/\text{cmd\_vel}
$$

로봇 2의 `cmd_vel` 토픽은:

$$
\mathbf{T}\_\text{robot2} = /\text{robot2}/\text{cmd\_vel}
$$

로 표현된다.

#### 리매핑 개념

리매핑은 기존의 토픽이나 서비스 이름을 다른 이름으로 변경하는 기능이다. 이를 통해 같은 노드를 여러 상황에서 재사용하거나, 노드 간의 통신 경로를 유연하게 설정할 수 있다.

예를 들어, 노드가 기본적으로 `cmd_vel`이라는 토픽을 구독하도록 되어 있지만, 다른 네임스페이스 내의 `robot1/cmd_vel`을 구독하게 하려면 리매핑을 통해 경로를 바꿀 수 있다.

리매핑을 위한 명령어는 다음과 같다.

```bash
ros2 run <패키지 이름> <노드 이름> --ros-args --remap __node:=/robot1/cmd_vel
```

위 명령어를 사용하면, 원래의 토픽 `cmd_vel`이 `/robot1/cmd_vel`로 리매핑된다.

#### 리매핑을 활용한 실습 예제

리매핑을 사용하면 복잡한 시스템에서 동일한 코드로 여러 환경을 쉽게 설정할 수 있다. 예를 들어, 로봇 1과 로봇 2가 동일한 코드를 사용하지만 서로 다른 토픽 이름으로 통신해야 한다고 가정해 보자. 이 경우 리매핑을 통해 간단하게 해결할 수 있다.

**퍼블리셔와 서브스크라이버 리매핑**

두 개의 퍼블리셔 노드와 서브스크라이버 노드를 생성하고, 각 노드가 서로 다른 네임스페이스에서 통신하도록 리매핑할 수 있다. 다음은 퍼블리셔와 서브스크라이버를 각각 `/robot1/cmd_vel`과 `/robot2/cmd_vel`로 리매핑하는 방법을 설명한다.

먼저, 기본 퍼블리셔 코드는 다음과 같다.

```cpp
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"

class SimplePublisher : public rclcpp::Node
{
public:
  SimplePublisher() : Node("simple_publisher")
  {
    publisher_ = this->create_publisher<std_msgs::msg::String>("cmd_vel", 10);
    timer_ = this->create_wall_timer(
      500ms, std::bind(&SimplePublisher::publish_message, this));
  }

private:
  void publish_message()
  {
    auto message = std_msgs::msg::String();
    message.data = "Robot command";
    publisher_->publish(message);
  }

  rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
  rclcpp::TimerBase::SharedPtr timer_;
};

int main(int argc, char *argv[])
{
  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared<SimplePublisher>());
  rclcpp::shutdown();
  return 0;
}
```

이 코드는 기본적으로 `cmd_vel`이라는 토픽에 메시지를 퍼블리싱한다. 이제 이 노드를 두 개의 서로 다른 네임스페이스로 리매핑해 봅시다.

1. `/robot1/cmd_vel`로 리매핑:

   ```bash
   ros2 run <패키지 이름> simple_publisher --ros-args --remap cmd_vel:=/robot1/cmd_vel
   ```
2. `/robot2/cmd_vel`로 리매핑:

   ```bash
   ros2 run <패키지 이름> simple_publisher --ros-args --remap cmd_vel:=/robot2/cmd_vel
   ```

**리매핑 수식 표현**

리매핑을 수식으로 나타내면 다음과 같다. 기본적으로 노드가 퍼블리싱하는 토픽을 $\mathbf{T}*{\text{old}}$라고 할 때, 리매핑 후 새로운 토픽 경로 $\mathbf{T}*{\text{new}}$는 다음과 같이 정의된다.

$$
\mathbf{T}\_{\text{new}} = \text{리매핑된 경로}
$$

따라서 `/robot1/cmd_vel`로 리매핑된 토픽 경로는:

$$
\mathbf{T}\_{\text{new}} = /\text{robot1}/\text{cmd\_vel}
$$

이고, `/robot2/cmd_vel`로 리매핑된 경우는:

$$
\mathbf{T}\_{\text{new}} = /\text{robot2}/\text{cmd\_vel}
$$

#### 서브스크라이버 리매핑 실습

서브스크라이버 코드도 마찬가지로 특정 네임스페이스 내의 토픽을 구독하도록 리매핑할 수 있다. 서브스크라이버 코드는 다음과 같다.

```cpp
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"

class SimpleSubscriber : public rclcpp::Node
{
public:
  SimpleSubscriber() : Node("simple_subscriber")
  {
    subscription_ = this->create_subscription<std_msgs::msg::String>(
      "cmd_vel", 10, std::bind(&SimpleSubscriber::topic_callback, this, std::placeholders::_1));
  }

private:
  void topic_callback(const std_msgs::msg::String::SharedPtr msg) const
  {
    RCLCPP_INFO(this->get_logger(), "I heard: '%s'", msg->data.c_str());
  }

  rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_;
};

int main(int argc, char *argv[])
{
  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared<SimpleSubscriber>());
  rclcpp::shutdown();
  return 0;
}
```

이 서브스크라이버 노드도 퍼블리셔와 마찬가지로 `cmd_vel` 토픽을 구독하지만, 리매핑을 통해 다른 네임스페이스로 설정할 수 있다.

1. `/robot1/cmd_vel`로 리매핑:

   ```bash
   ros2 run <패키지 이름> simple_subscriber --ros-args --remap cmd_vel:=/robot1/cmd_vel
   ```
2. `/robot2/cmd_vel`로 리매핑:

   ```bash
   ros2 run <패키지 이름> simple_subscriber --ros-args --remap cmd_vel:=/robot2/cmd_vel
   ```

이를 통해 각각의 서브스크라이버는 다른 네임스페이스에서 퍼블리셔가 보낸 메시지를 받아볼 수 있다.

#### 리매핑과 네임스페이스 실습을 통한 시나리오 구성

리매핑과 네임스페이스를 실습할 때, 두 개 이상의 로봇을 관리하는 환경을 구성하는 것이 대표적인 예시이다. 이번 실습에서는 두 개의 로봇이 각각 독립적인 네임스페이스에서 작동하고, 같은 코드를 사용하더라도 서로의 통신에 영향을 미치지 않도록 설정할 수 있는 방법을 소개하겠다.

**시나리오: 두 로봇 간 독립적인 통신 설정**

로봇 1과 로봇 2가 각각 독립적으로 움직이며, 동일한 노드를 사용하지만 다른 네임스페이스를 통해 통신을 구분해야 하는 경우이다. 이 시나리오에서 우리는 두 로봇이 서로 다른 퍼블리셔와 서브스크라이버를 통해 명령을 주고받도록 하겠다.

**퍼블리셔 노드 설정 (로봇 1)**

```bash
ros2 run <패키지 이름> simple_publisher --ros-args --remap cmd_vel:=/robot1/cmd_vel
```

**퍼블리셔 노드 설정 (로봇 2)**

```bash
ros2 run <패키지 이름> simple_publisher --ros-args --remap cmd_vel:=/robot2/cmd_vel
```

**서브스크라이버 노드 설정 (로봇 1)**

```bash
ros2 run <패키지 이름> simple_subscriber --ros-args --remap cmd_vel:=/robot1/cmd_vel
```

**서브스크라이버 노드 설정 (로봇 2)**

```bash
ros2 run <패키지 이름> simple_subscriber --ros-args --remap cmd_vel:=/robot2/cmd_vel
```

이렇게 설정하면, 두 로봇은 동일한 퍼블리셔와 서브스크라이버 코드를 사용하면서도 서로의 명령어를 받아들이지 않고 독립적으로 작동하게 된다. `robot1` 네임스페이스에 속한 노드와 `robot2` 네임스페이스에 속한 노드는 서로 영향을 미치지 않으며, 각각의 퍼블리셔는 자신에게 할당된 네임스페이스 내에서만 메시지를 보낸다.

**시나리오 수식 표현**

각 로봇의 퍼블리셔와 서브스크라이버 간의 토픽 흐름을 수식으로 표현하면 다음과 같다.

로봇 1에서 퍼블리셔가 보낸 메시지는 다음 경로를 따른다.

$$
\mathbf{T}\_\text{publish, robot1} = /\text{robot1}/\text{cmd\_vel}
$$

서브스크라이버는 같은 경로에서 메시지를 수신한다.

$$
\mathbf{T}\_\text{subscribe, robot1} = /\text{robot1}/\text{cmd\_vel}
$$

로봇 2에서도 퍼블리셔와 서브스크라이버 간의 메시지 경로는 동일한 구조를 따르지만, 네임스페이스가 다르다.

$$
\mathbf{T}\_\text{publish, robot2} = /\text{robot2}/\text{cmd\_vel}
$$

$$
\mathbf{T}\_\text{subscribe, robot2} = /\text{robot2}/\text{cmd\_vel}
$$

따라서, 각 로봇은 다른 네임스페이스로 리매핑된 토픽을 사용하여 독립적인 명령어 흐름을 유지할 수 있다.

#### 네임스페이스 및 리매핑 실습 결과 분석

이제 두 로봇 간의 통신 경로가 설정되었으며, 네임스페이스와 리매핑을 통해 서로의 통신 경로가 독립적으로 유지됨을 확인할 수 있다. 이를 통해 복잡한 로봇 시스템에서도 동일한 노드와 토픽 이름을 충돌 없이 사용할 수 있게 된다.

**네임스페이스와 리매핑 활용의 장점**

1. **확장성**: 동일한 코드 베이스로 여러 로봇을 동시에 제어할 수 있어 코드 재사용성과 유지보수성이 높아진다.
2. **독립성**: 각각의 로봇이 자신만의 네임스페이스에서 통신을 하므로, 다른 로봇과의 충돌을 방지할 수 있다.
3. **유연성**: 리매핑을 통해 기존 시스템에서 특정 노드나 토픽의 이름을 쉽게 변경할 수 있어 상황에 맞게 시스템을 조정할 수 있다.
