ROSを用いたジョイスティックコントローラーの使用方法 

# 概要
題名の通り、ジョイスティックコントローラーの操作をROS内で使用するための方法を記載していきます。

## 説明すること
- 関連パッケージのインストール方法
- 関連ノードの実行方法
- コントローラー操作時のサブスクライバー作成方法

## 動作環境
- Raspberry Pi 4 (4GB)
- Ubuntu server 20.4LTS (64bit)
- ROS Noetic
- **Logicool RumblePad2 G-UF13**

使用するゲームパッドは下の写真と同型のもの。
家に転がっていたものをそのまま使用する。

PS3やPS4のコントローラーなど、PCで認識できるコントローラーなら何でも対応できると思う。
コントローラーによってキーの割り当てが異なるため、自身の環境に合わせて確認すること！！

![f160343710.1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634805/650be736-c19e-3191-92a6-4d3220fb16c7.jpeg)

#  関連パッケージのインストール
下記コマンドで関連パッケージをインストールする。
ROSのバージョンに合わせて『noetic』の部分は適宜変更すること。

```
sudo apt update
sudo apt install ros-noetic-joy
```

# 関連ノードの実行手順

1. ゲームパッドをラズパイに接続
2. ターミナルを3つ開く
3. 各ターミナルで下記コマンドを実行

```:ターミナル1
roscore
```
```:ターミナル2
rosrun joy joy_node
```
```:ターミナル3
rostopic echo /joy
```

ゲームパッドを動かすと、その情報 (トピックの中身) が表示される。
下記のような表示になればOK。

```:ターミナル3
---
header:
  seq: 2
  stamp:
    secs: 1609674647
    nsecs: 648456152
  frame_id: "/dev/input/js0"
axes: [-0.0, 0.11017663776874542, -0.0, -0.0, 0.0, 0.0]
buttons: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
---
```

下記コマンドにより、『axes は float型』『buttons は int型』であることが分かる。

```
rostopic type /joy
⇒ sensor_msgs/Joy

rosmsg show -r sensor_msgs/Joy
⇒ # Reports the state of a joysticks axes and buttons.
   Header header           # timestamp in the header is the time the data is received from the joystick
   float32[] axes          # the axes measurements from a joystick
   int32[] buttons         # the buttons measurements from a joystick
```

# サブスクライバー作成
コントローラーの操作から、何かしらの処理を行う方法について記載していく。
基本的には、**『joyノードを受け取った時のコールバック関数を実装する』**だけです。

## 1. パッケージの作成
サブスクライバーが所属するパッケージを作成する。

```
cd ~/catkin_ws/src
catkin_create_pkg joy_sub roscpp
```

パッケージ名：joy_sub 
依存ライブラリ：roscpp

## 2. subプログラム作成
joyノードを受け取るサブスクライバーのノード(プログラム)を作成する。

```cpp:~/catkin_ws/src/joy_sub/src/joy_sub_node.cpp
#include <ros/ros.h>
#include <sensor_msgs/Joy.h>

void joy_callback(const sensor_msgs::Joy &joy_msg)
{
  // 処理内容を記述
  ROS_INFO("axes[0]:%f", joy_msg.axes[0]);   // スティック0の状態を表示 (-1 ～ 1)
  ROS_INFO("Button[0]:%d", joy_msg.buttons[0]);  // ボタン0の状態を表示 (0 or 1)
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, "joy_sub_node");
  ros::NodeHandle nh;
  ros::Subscriber sub = nh.subscribe("joy", 10, joy_callback);
  ros::Rate loop_rate(10);

  while (ros::ok())
  {
    ros::spinOnce();
    loop_rate.sleep();
  }
  return 0;
}
```

重要な点は、**サブスクライバーの宣言**と**コールバック関数の内容**。
それ以外は通常のsubプログラムと同様の内容。

**サブスクライバーの宣言**
ここでjoyトピックとコールバック関数を紐付ける。

```cpp
ros::Subscriber sub = nh.subscribe("joy", 10, joy_callback);
```

**コールバック関数**
ここでjoyノードを受け取った時の初期を記述する。
今回はよく使用する**『ジョイスティックの傾き値 (0~1)』**と**『ボタンの状態 (0 or 1)』**について表示する。
対応するスティックやボタンに合わせて、配列のインデックスを調整すること。

```cpp
void joy_callback(const sensor_msgs::Joy &joy_msg)
{
  // 処理内容を記述
  ROS_INFO("axes[0]:%f", joy_msg.axes[0]);   // スティック0の状態を表示 (0 ～ 1)
  ROS_INFO("Button[0]:%d", joy_msg.buttons[0]);  // ボタン0の状態を表示 (0 or 1)
}
```

## 3. CMakeLists.txt の編集
あとは通常と同じく、CMakeLists.txt を編集しビルドしていく。

```cmake:~/catkin_ws/src/joy_sub/src/CMakeLists.txt
cmake_minimum_required(VERSION 3.0.2)
project(joy_sub)

find_package(catkin REQUIRED COMPONENTS
  roscpp
)

catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES joy_sub
#  CATKIN_DEPENDS roscpp
#  DEPENDS system_lib
)

include_directories(
# include
  ${catkin_INCLUDE_DIRS}
)

add_executable(joy_sub_node src/joy_sub_node.cpp)

target_link_libraries(joy_sub_node
  ${catkin_LIBRARIES}
)
```

## 4. launchファイルの作成
launchファイルを作成することで、1つのターミナルで実行可能。
作っても作らなくてもいいが、作った方が便利。

```xml:~/catkin_ws/src/joy_sub/launch/joy_sub.launch
<launch>
  <node name="joy_node" pkg="joy" type="joy_node" />
  <node name="joy_sub_node" pkg="joy_sub" type="joy_sub_node" output="screen" />
</launch>

```

## 5. ビルド
下記コマンドでパッケージをビルド。

```
cd ~/catkin_ws
catkin_make
```

## 6. 実行
下記コマンドで実行。

```
roslaunch joy_sub joy_sub.launch
```

コントローラーを操作すると、スティック0 と ボタン0 の状態について値が表示されるはず。
問題なく表示されればOK。

# 参考ページ
https://qiita.com/srs/items/9114bb3c27a148e0b855
https://www.robonchu.info/entry/2018/02/21/210311