# 가제보 설치

가제보(Gazebo)는 자율주행 로봇 개발 시 필수적인 시뮬레이션 환경으로, 로봇의 물리적 움직임과 센서 데이터를 가상 환경에서 테스트하고 평가할 수 있게 해 준다. ROS2 Humble에서 가제보를 설치하는 과정과 주요 설정 방법에 대해 자세히 설명하겠다.

#### 가제보의 개요와 필요성

가제보는 고성능 물리 엔진을 사용해 로봇의 물리적 상호작용을 시뮬레이션하고, 다양한 센서 데이터를 생성하여 자율주행 알고리즘을 테스트하는 환경을 제공한다. 특히, 실제 로봇 환경에서 바로 테스트하기 어려운 경우, 가제보를 활용한 시뮬레이션이 필수적이다. 이를 통해 비용을 절감하고 로봇의 안정성을 높일 수 있다.

#### 가제보 설치 준비

가제보를 설치하기 위해 필요한 주요 사전 작업과 환경 설정을 알아보겠다.

Gazebo를 설치하기 위해서는 Ubuntu 시스템에서 필요한 패키지를 설치하고, ROS2와 호환되는 환경을 설정해야 한다. 아래에 Gazebo 설치 방법을 단계별로 설명하겠다.

#### 시스템 패키지 업데이트

먼저, 시스템의 패키지 목록을 업데이트하고 업그레이드한다.

```bash
sudo apt update
sudo apt upgrade
```

#### Gazebo 저장소 추가

Gazebo의 최신 버전을 설치하려면 Gazebo의 공식 저장소를 추가해야 한다. 이는 `Fortress` 또는 `Garden`과 같은 최신 버전으로 설치할 때 유용하다.

```bash
sudo apt install -y wget
wget https://packages.osrfoundation.org/gazebo.key -O - | sudo apt-key add -
sudo sh -c 'echo "deb http://packages.osrfoundation.org/gazebo/ubuntu-stable $(lsb_release -sc) main" > /etc/apt/sources.list.d/gazebo-stable.list'
```

#### 패키지 업데이트

새로 추가된 저장소의 패키지 목록을 반영하기 위해 다시 업데이트를 진행한다.

```bash
sudo apt update
```

#### Gazebo 설치

ROS2 Rolling 또는 Humble에서 호환되는 Gazebo 버전을 설치한다. 아래는 Fortress와 Garden 버전을 설치하는 예제이다.

* **Gazebo Fortress 설치**

  ```bash
  sudo apt install gz-fortress # 22.04
  ```
* **Gazebo Harmonic 설치**

  ```bash
  sudo apt install gz-harmonic # 24.04
  ```

#### 설치 확인

설치가 완료되면 다음 명령어를 사용해 Gazebo가 올바르게 설치되었는지 확인할 수 있다.

```bash
gz --versions
```

#### 가제보와 ROS2 통합 설정

ROS2 Humble과 가제보를 통합하기 위해서는 ROS2의 가제보 플러그인과 설정 파일을 통해 시뮬레이션 환경을 연결해야 한다.

**환경 변수 설정**

ROS2와 가제보가 상호작용하기 위해 환경 변수를 설정해야 한다. ROS2가 설치된 경로를 지정하여 가제보와의 연동을 보장한다.

```bash
source /opt/ros/humble/setup.bash # for 22.04
source /opt/ros/jazzy/setup.bash # for 24.04
```

이제 가제보 환경과 관련된 ROS2 패키지를 사용할 준비가 완료되었다.

#### 가제보 플러그인 설정

가제보와 ROS2의 상호작용을 위해 플러그인을 설정해야 한다. 플러그인은 ROS2와 가제보 간 데이터 통신을 가능하게 하며, 예를 들어 로봇의 이동과 센서 데이터를 ROS2 노드로 전달한다.

**주요 가제보 ROS2 플러그인**

1. **gazebo\_ros**: 가제보와 ROS2의 기본적인 통신을 제공한다.
2. **gazebo\_ros\_control**: ROS2의 제어 패키지와 연동하여 모터 및 액추에이터 제어를 지원한다.
3. **gazebo\_ros\_pkgs**: 다양한 센서와 데이터 토픽을 처리하며, 가제보 상의 각종 데이터를 ROS2 환경에서 활용할 수 있게 한다.

설치한 `gazebo_ros_pkgs`가 ROS2 노드에서 올바르게 작동하도록 하기 위해서 다음과 같은 기본 파일을 준비한다.

```xml
<!-- example_world.sdf -->
<sdf version="1.6">
  <world name="default">
    <include>
      <uri>model://ground_plane</uri>
    </include>
    <include>
      <uri>model://sun</uri>
    </include>
    <plugin name="gazebo_ros" filename="libgazebo_ros_api_plugin.so"/>
  </world>
</sdf>
```

위 파일은 가제보 시뮬레이션에 기본 지면과 태양을 포함하며, ROS2와 연동될 수 있도록 `gazebo_ros` 플러그인을 추가한다.

#### 가제보 환경 테스트

설정이 완료되면 간단한 가제보 환경을 실행하여 ROS2와의 연동이 올바르게 작동하는지 확인한다. `ros2 launch` 명령어를 통해 가제보 환경을 시작할 수 있다.

**기본 가제보 월드 실행**

ROS2를 사용해 미리 구성된 기본 월드를 실행해 본다.

```bash
ros2 launch gazebo_ros gazebo.launch.py
```

이 명령어를 통해 가제보 환경이 실행되며, 가제보 GUI가 나타난다. 여기에서 시뮬레이션 월드가 제대로 로드되었는지, ROS2 노드와의 통신이 원활한지 확인할 수 있다.

#### ROS2 메시지와 가제보 토픽 연동

가제보에서 생성된 토픽을 ROS2에서 직접 사용할 수 있도록 설정할 수 있다. 이를 통해 센서 데이터나 로봇 상태 정보를 ROS2 노드에서 실시간으로 처리할 수 있다.

**가제보와 ROS2의 기본 토픽 설정 예제**

가제보는 각종 센서 및 로봇 상태를 가제보 내의 토픽을 통해 제공한다. 예를 들어, 레이저 스캐너 데이터를 ROS2에서 직접 가져와 처리하는 경우, 다음과 같이 토픽 설정을 수행할 수 있다.

```xml
<!-- laser_plugin.sdf -->
<plugin name="gazebo_ros_laser" filename="libgazebo_ros_ray_sensor.so">
  <ros>
    <namespace>/robot</namespace>
    <argument>__name:=laser</argument>
  </ros>
  <frameName>laser_frame</frameName>
  <topicName>/scan</topicName>
</plugin>
```

위 설정은 가제보 레이저 플러그인에서 `/scan`이라는 토픽을 생성하며, 이를 ROS2 환경에서 활용할 수 있게 한다. ROS2 노드에서는 `/robot/scan` 토픽을 구독하여 가제보에서 생성된 레이저 데이터를 수신할 수 있다.

#### 가제보 시뮬레이션 설정 확장

기본적인 가제보 환경 설정을 마친 후에는 로봇 모델과 월드를 추가하여 자율주행 로봇의 특정 시나리오를 시뮬레이션할 수 있다. 이를 통해 다양한 환경에서 로봇의 성능을 테스트하고 개선할 수 있다.

**로봇 모델 추가**

가제보에서 로봇을 시뮬레이션하려면 로봇의 물리적, 센서적 속성 등을 정의한 모델 파일이 필요하다. 일반적으로 URDF (Unified Robot Description Format) 또는 SDF (Simulation Description Format) 형식으로 작성된다.

**URDF 파일 예시**

URDF 파일은 로봇의 링크와 조인트 정보를 XML 형식으로 정의한다. 다음은 간단한 로봇 URDF 파일의 예이다.

```xml
<!-- my_robot.urdf -->
<robot name="my_robot">
  <link name="base_link">
    <inertial>
      <mass value="1.0"/>
      <origin xyz="0 0 0"/>
    </inertial>
    <visual>
      <geometry>
        <box size="0.5 0.5 0.2"/>
      </geometry>
    </visual>
    <collision>
      <geometry>
        <box size="0.5 0.5 0.2"/>
      </geometry>
    </collision>
  </link>
</robot>
```

위 URDF 파일은 `my_robot`이라는 이름의 로봇을 정의하며, 단일 링크 `base_link`와 상자의 크기와 질량 정보를 포함하고 있다. 이를 가제보에 로드하면 시뮬레이션 상에서 해당 로봇이 나타난다.

**가제보에서 URDF 파일 로드**

가제보에서 URDF 파일을 로드하려면 다음과 같은 C++ 코드로 로봇 모델을 스폰(spawn)할 수 있다.

```cpp
#include <gazebo_msgs/srv/spawn_entity.hpp>
#include <rclcpp/rclcpp.hpp>

auto node = rclcpp::Node::make_shared("spawn_robot");
auto client = node->create_client<gazebo_msgs::srv::SpawnEntity>("/spawn_entity");
auto request = std::make_shared<gazebo_msgs::srv::SpawnEntity::Request>();

request->name = "my_robot";
request->xml = read_urdf("path/to/my_robot.urdf");
request->robot_namespace = "/my_robot";
request->reference_frame = "world";

if (client->wait_for_service()) {
    client->async_send_request(request);
}
```

위 코드는 `/spawn_entity` 서비스에 요청을 보내 가제보에 로봇을 스폰한다. `read_urdf()` 함수는 URDF 파일을 문자열로 읽어 오는 사용자 정의 함수이다. 로봇을 스폰한 후, ROS2 노드에서 해당 로봇의 토픽 및 액션을 제어할 수 있다.

#### 월드 환경 설정

시뮬레이션을 위한 월드 환경은 다양한 물리적 객체와 지형을 포함할 수 있다. 가제보에서는 SDF 파일을 사용하여 지형, 장애물 등을 설정할 수 있다.

**월드 파일 예시**

간단한 월드를 정의하는 SDF 파일 예시는 다음과 같다.

```xml
<!-- simple_world.sdf -->
<sdf version="1.6">
  <world name="simple_world">
    <include>
      <uri>model://ground_plane</uri>
    </include>
    <include>
      <uri>model://sun</uri>
    </include>
    <model name="box_obstacle">
      <static>true</static>
      <link name="link">
        <collision name="collision">
          <geometry>
            <box>
              <size>1 1 1</size>
            </box>
          </geometry>
        </collision>
        <visual name="visual">
          <geometry>
            <box>
              <size>1 1 1</size>
            </box>
          </geometry>
        </visual>
      </link>
    </model>
  </world>
</sdf>
```

위 `simple_world.sdf` 파일은 기본적인 지면과 태양, 그리고 하나의 박스 형태 장애물을 포함한다. 이 파일을 로드하면 가제보에서 설정한 박스 장애물을 볼 수 있으며, 이를 통해 자율주행 알고리즘의 장애물 회피 성능을 테스트할 수 있다.

#### 가제보 월드와 ROS2의 연동

가제보 월드에서 발생하는 다양한 이벤트와 데이터를 ROS2에서 수신하고 처리할 수 있다. 예를 들어, 로봇의 위치 데이터, 속도 데이터, 장애물 인식 데이터를 ROS2 토픽으로 구독하고 분석할 수 있다.

**위치 데이터 수신 예제**

가제보에서 제공하는 위치 데이터를 ROS2 노드에서 구독하려면 다음과 같이 토픽 구독 코드를 작성할 수 있다.

```cpp
#include <geometry_msgs/msg/pose_stamped.hpp>
#include <rclcpp/rclcpp.hpp>

class PoseSubscriber : public rclcpp::Node {
public:
    PoseSubscriber() : Node("pose_subscriber") {
        subscription_ = this->create_subscription<geometry_msgs::msg::PoseStamped>(
            "/robot/pose", 10,
            [this](geometry_msgs::msg::PoseStamped::SharedPtr msg) {
                RCLCPP_INFO(this->get_logger(), "Robot Position: x = %f, y = %f", msg->pose.position.x, msg->pose.position.y);
            });
    }

private:
    rclcpp::Subscription<geometry_msgs::msg::PoseStamped>::SharedPtr subscription_;
};

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

위 코드는 `/robot/pose` 토픽을 구독하여 로봇의 위치 데이터를 수신하고 콘솔에 출력한다. 이 데이터는 ROS2 노드에서 가제보 시뮬레이션의 로봇 상태를 모니터링하는 데 유용하다.
