maze_action 미로탈출 프로젝트

By qsp , Created on 1st Jun 2022

ROS2의 action server와 action client를 이용해서
실제 turtlebot3 로봇과 가상 시뮬레이션 gazebo에서 구현

ROS2 Maze Action 프로젝트

ROS2의 Action Server / Client를 이용해서 maze_action_server/client 노드를 실행하여
로봇이 미로를 탈출하는 패키지 프로젝트 입니다


Maze Action

Maze Action 프로젝트는

  • ROS2의 action을 이용해서 goal, feedback, result로 수행
  • maze_action_client 노드에서 로봇에 방향 설정 명령을 Goal로 maze_action_server로 보냄
  • maze_action_server 에서는 로봇을 움직일 수 있게 토픽을 발행하며 중간 중간 feedback을 함
  • 최적으로 result로 응답을 해서 로봇의 탈출 여부를 알 수 있게 됩니다.

로봇은 turtlebot3 burger를 사용해서 실제 미로와 비슷하게 환경을 만들어서 수행하였습니다.

[미로를 책으로 설정, 로봇 turtlebot3]


환경

우분투

ROS2

C++

Turtlebot3


필요한 패키지

터틀봇3 버거

가제보

opencv

camera pub
(turtlebot3를 직접 사용하는 경우에 라즈베리파이에 설치합니다.)


maze_action 의 패키지 설명

  1. maze
    maze_action_server, maze_action_client로 ROS2 action으로 로봇 구동
  2. maze_dolly gazebo로 customized_dolly 로봇으로 시뮬레이션
  3. maze_interfaces
    사용자 정의 ROS2 action type
  • 패키지 구성 (tree)
    maze_cation
    ├── maze
    │   ├── CMakeLists.txt
    │   ├── launch
    │   │   └── maze_server.launch.py
    │   ├── package.xml
    │   └── src
    │       ├── maze_client.cpp
    │       └── maze_server.cpp
    ├── maze_dolly
    │   ├── CMakeLists.txt
    │   ├── launch
    │   │   └── maze_dolly.launch.py
    │   ├── models
    │   │   ├── customized_dolly
    │   │   └── wall_maze
    │   └── worlds
    │       └── maze_dolly.world
    └── maze_interfaces
       ├── action
       │   └── Maze.action
       ├── CMakeLists.txt
       └── package.xml


turtlebot3 로봇 사용

  • 로보티즈의 turtlebot3 burger 사용
[출처: 로보티즈]

하드웨어 스펙 (일부)

Items Model
IMU Gyroscope 3 Axis, Accelerometer 3 Axis
MCU 32-bit ARM Cortex®-M7 with FPU
SBC Raspberry Pi 4b
LDS 360 Laser Distance Sensor LDS-02
Actuator XL430-W250
[출처: 로보티즈]

소프트웨어

ROS2 ; Foxy Fitzroy
Gazebo : ROS의 시뮬레이션 프로그램으로 실제 로봇없이 가상에서 시뮬레이션으로 구동이 가능

시뮬레이션으로 진행 할 시 gazebo 및 런치파일 실행
시뮬레이션으로 gazebo에서 실행할려고 할 때에는 maze_dolly 패키지의 런치파일로 실행합니다.


설치 방법 및 코드

깃허브에서 클론해서 설치를 합니다.
Git hub 및 README를 확인해주세요

설치 방법 및 코드를 깃허브에서 확인할 수 있습니다.

일부 code

코드는 c++로 작성하였습니다.

  • maze 패키지의 maze_server.cpp 의 일부 코드

    void execute(const std::shared_ptr<GoalHandleMaze> goal_handle) {
      rclcpp::WallRate loop_rate(5);  
      const auto goal = goal_handle->get_goal();  //
      auto feedback = std::make_shared<maze_interfaces::action::Maze::Feedback>();
      auto result = std::make_shared<maze_interfaces::action::Maze::Result>();
    
      // client로 부터 받은 goal에서 turning_sequence 만큼 반복
      for (int val : goal->turning_sequence) {
          RCLCPP_INFO(this->get_logger(), "Current Input: %d", val);
          RCLCPP_INFO(this->get_logger(), "Turning %s ", direction_str_vec[val].c_str()); 
    
          // 사용자에게 보여주기 위한 vector 스트링, 일치하는 문자열 프린트
          feedback->feedback_msg = "Now.. turning " + direction_str_vec[val]; //client쪽에서 사용
          RCLCPP_INFO(this->get_logger(), feedback->feedback_msg);  
    
          // 사용자 입력과(turning_sequence), direction_flt_vec(벡터: 방향값 수치)와 같은 배열의 value값을 turn_robot 메소드를 호출
          turn_robot(direction_flt_vec[val]);
    
          // feedback 보냄
          goal_handle->publish_feedback(feedback);
    
          // cmd_vel로 제어하는 메소드 호출
          moving_robot();
      }
      // 이미지 처리를 위해서 
      auto image_subscriber = std::make_shared<ImageSubscriber>();
    
      // ... 
      // 생략 
      // ...
    
      // image_subscriber에서 처리한 result 값 결정해서 보내주기
      if (!is_green) {
          RCLCPP_ERROR(get_logger(), "====== Failed ======");
          result->success = false;
          goal_handle->abort(result);
    
      } else {
          RCLCPP_INFO(get_logger(), "====== Succeed ======");
          result->success = true;
          goal_handle->succeed(result);
      }
    }


  • maze 패키지의 maze_client.cpp 의 일부 코드

       void send_goal() {
          using namespace std::placeholders;
    
          auto goal_msg = maze_interfaces::action::Maze::Goal(); 
    
          // 유저에게 입력받은 배열을 받아와서 action msg에 넣어주기
          goal_msg.turning_sequence = this->get_turning_list();  
    
          auto send_goal_options = rclcpp_action::Client<maze_interfaces::action::Maze>::SendGoalOptions();
    
          send_goal_options.goal_response_callback = std::bind(&MazeActionClient::goal_response_callback, this, _1);
          send_goal_options.feedback_callback = std::bind(&MazeActionClient::feedback_callback, this, _1, _2);
          send_goal_options.result_callback = std::bind(&MazeActionClient::result_callback, this, _1);
    
          // async_send_goal() 
          auto goal_handle_future = this->action_client->async_send_goal(goal_msg, send_goal_options);
      }
    
      void feedback_callback(rclcpp_action::ClientGoalHandle<maze_interfaces::action::Maze>::SharedPtr, 
                              const std::shared_ptr<const maze_interfaces::action::Maze::Feedback> feedback) {
          // 서버에서 처리된 feedback을 출력
          RCLCPP_INFO(this->get_logger(), "Received feedback: %s", feedback->feedback_msg.c_str());
      }
    
      void result_callback(const rclcpp_action::ClientGoalHandle<maze_interfaces::action::Maze>::WrappedResult & result) {
    
          // 최종 result 여부 
          this->goal_done_ = true;
    
          // ... 
          // 생략 
          // ...
    
          // 최종적 결과로 비교
          if (result.result->success != false) {
              RCLCPP_WARN(this->get_logger(), "Congrats! Actions have been accompished!!");
          } 
      }


maze-action_server_node 실행 / launch file과 gazebo 실행

  1. 터틀봇3로 수행시
    그리고 maze_action_server 노드 실행
    cd ~/colcon_ws
    . install/setup.sh
    ros2 run maze maze_action_server_node

OR

  1. 가제보로 실행할 시 gazebo 런치파일 실행
    ros2 launch maze_dolly maze_dolly.launch.py

새로 다른 터미널을 열어준 후에 maze_action_server를 실행시키기 위해 런치 파일 실행

ros2 launch maze maze_server.launch.py


세 번째, maze_action_client_node 실행하기

  1. 액션 클라이언트 노드 실행 (공통)
    또 새로운 터미널을 열어줍니다. source setup.sh을 해줘서 overlay 상태를 만들자
    source install/setup.sh

이번에는 maze_action_client 노드 실행함

ros2 run maze maze_action_client_node


노드 실행한 모습

[maze_action_server, maze_action_client 노드 실행]


action_server_node 실행 후 topic

  • turtlebot3 전용으로 실행했을 경우

    /cmd_vel
    /odom
    /parameter_events
    /rosout
    /scan
  • gazebo 실행 했을 경우

    /dolly/cmd_vel
    /dolly/laser_scan
    /dolly/odom
    /parameter_events
    /rosout


카메라 화면 보기

rqt_image_view 노드 실행으로 보기. 아래의 노드를 실행

ros2 run rqt_image_view rqt_image_view 

이미지가 안 나오면 topic 부분을 다시 선택해준다 (또는 토픽 옆 새로고침 아이콘)
/camera0/image_raw



maze_action_client 에서 명령 시퀸스 입력하기

로봇을 미로에서 빠져나올 수 있게 녹색 공이 있는 출구를 향해서 방향을 입력합니다.

[방향 및 숫자 안내]
  1. 로봇이 녹색 공까지 잘 도달할 수 있도록 갈 방향을 입력해준다. (위 사진을 참고)
    (Action Client 에서 입력한 값을 Action Server로 goal 요청합니다)
  2. 최종적으로 q 키를 눌러서 입력을 마치게 되면 로봇이 움직이기 시작한다
    (Action Server에서 cmd_vel로 퍼블리싱을 합니다.)
  3. 로봇은 입력된 방향으로 회전을 한 후에 벽이 가까워질 때까지 직진을 합니다.
    (로봇의 odometry 와 laser scan을 이용합니다.)
  4. 마지막으로 녹색 공까지 잘 도달하였다면 성공 메세지 전달
    (Image subscription을 통해서 녹색 확인)
[gazebo- maze_dolly 패키지]


동영상

터틀봇3

turtlebot3 미로 탈출 성공 영상


turtlebot3 미로 탈출 실패 영상


가제보

Gazebo를 이용한 maze_dolly 패키지의 성공 영상


Gazebo를 이용한 maze_dolly 패키지의 실패 영상


reference