ジョイスティック(JoyStick)の使い方、つなぎ方、動作原理等を回路図も使って詳しく解説

ジョイスティック(JoyStick)

X軸、Y軸の操作ができる2軸のジョイスティック(JoyStick)の仕組みから、実際の使用方法等をサンプルプログラムを使用して詳しく紹介します。

動作確認では「RCサーボモータ」を2個使用して、カメラ等を固定して縦横に動作するパンチルト機構をジョイスティックで操作するものを実際に作ってみます。


マイコンボードには「Arduino」より機能豊富な「M5Stack」社製の「M5StickC Plus」を使用します。
「M5StickC Plus」については以下のリンクで詳しく紹介しています。

M5StickC Plusの使い方、初期設定、サンプルプログラム、M5StickCとの違い等を詳しく紹介
M5StickC PlusをArduino IDEやPlatformIOで使うための初期設定やサンプルプログラムでの動作確認の方法です。ビジュアルプログラミングのUiFlowの初期設定についても紹介します。

「RCサーボ」を使用したラジコンの作り方も、以下のリンクで詳しく紹介しています。

LEGOで作るBluetoothラジコンカー M5StickC Plus2 + ATOM Lite
M5StickC Plus2を使用してBluetoothでジョイスティック操作のLEGOラジコンの作り方を紹介。駆動はRCサーボでATOM Liteで制御します。
スポンサーリンク

1.ジョイスティックとは

「ジョイスティック」とはゲームのコントローラーや、ドローンの操作等に使用され、上下左右の移動を操作するために使用される2軸(X軸、Y軸)のコントローラーです。

1つの「ジョイスティック」で上下左右を操作でき、左右を「X軸」、上下を「Y軸」として使用することが多く、それぞれに操作した時の座標情報を取得できます。

多くの「ジョイスティック」がスティックを押し込むことで「ON/OFF」スイッチとしても機能します。

スポンサーリンク

2.外観写真

ジョイスティックの外観は以下のようになります。

・アナログ出力仕様

下写真はスティックの座標をアナログ電圧出力で取得するタイプで、いろいろなメーカーから同じようなものが販売されています。

ジョイスティック(JoyStick)アナログ仕様
ジョイスティック(JoyStick)アナログ仕様

・シリアル通信(I2C)仕様

下写真は「M5Stack」社製のジョイスティックで、スティックの操作データをシリアル通信(I2C)で取得するタイプです。
I2C通信用として「GROVE」コネクタがあり、ケーブルも付属しています。

ジョイスティック(JoyStick)I2C通信仕様
ジョイスティック(JoyStick)I2C通信仕様
ジョイスティック(JoyStick)I2C通信仕様
ジョイスティック(JoyStick)I2C通信仕様
本体裏にはLEDが使えるような記載があります。実際に基板上にLEDがあるのは確認しましたが「M5Stack」さんに問い合わせたところ「現時点ではソフトで制御できません」との回答でした。
残念ですが使える時が来るようであれば、また紹介したいと思います。
スポンサーリンク

3.動作原理と構造

「ジョイスティック」の動作原理について、内部には「X軸」「Y軸」方向に操作した時に操作量、方向に応じて変動する2つのボリューム(可変抵抗器)があります。

スティックを操作することで各軸の位置によって「0V〜ボリュームの両端電圧」までの電圧が出力され、この電圧を読み取ることでスティックの操作位置を取得することができます。

回路図に表すと以下のようになります。

電源電圧を「3.3V」とすると各軸で操作量に応じて「0〜3.3V」の電圧が出力されます。

「ON/OFF」スイッチ付のものはスティックの下に小さなスイッチが内蔵されており、スティックを押し込むことで「押しボタンスイッチ」として機能します。

ジョイスティックには「アナログ出力仕様」と「シリアル通信仕様」があり、それぞれで出力されるデータや使用方法が異なります。
実際に操作した時の出力データと構造は以下のようになります。

・アナログ出力仕様

アナログ出力仕様は下写真のように、スティックの操作量に応じてX,Y各軸で「0〜最大V(電源電圧)」の電圧を出力します。

電圧を読み取るため、操作精度は処理する側のA/D変換の分解能(M5StickC Plusは12bit「0〜4095」)によって決まります。

ジョイスティック(JoyStick)の使い方
ジョイスティック(JoyStick)アナログ仕様

矢印部にX,Y軸の操作と連動するボリューム(可変抵抗器)があります。

ジョイスティック(JoyStick)アナログ仕様

矢印部にスティックを押し込んだ時に動作するタクトスイッチがあります。


・シリアル通信(I2C)仕様

シリアル通信(I2C)仕様は下写真のように、スティックの操作量に応じてX,Y各軸の座標データ「0〜255」を1バイトづつ順番に出力します。
3バイト目にはスティクを押し込んだ時に動作するスイッチの状態を「1/0(ON/OFF)」で出力します。

操作精度は操作範囲を256分割したものになります。

ジョイスティック(JoyStick)の使い方
ジョイスティック(JoyStick)I2C通信仕様

矢印部にX,Y軸の操作と連動するボリューム(可変抵抗器)があります。

ジョイスティック(JoyStick)I2C通信仕様

矢印部にスティックを押し込んだ時に動作するタクトスイッチがあります。


「ボリューム(可変抵抗器)」や「押しボタンスイッチ」については以下のリンクで詳しく紹介しています。

ボリューム(可変抵抗器)の使い方、つなぎ方、抵抗値計算等を回路図も使って詳しく解説
ボリュームというと音量調節のイメージですが、明るさや回転数等を調整するのにも使用されます。「抵抗(固定抵抗器)」が固定の抵抗値を持つのに対して「可変抵抗器」は抵抗値を調整することができます。このボリューム(可変抵抗器)について紹介します。
スイッチ(操作用)の使い方。便利なスイッチユニットについても詳しく紹介
スイッチとは「開閉器」とも呼ばれ電気の通り道をつないだり開いたりするものです。 スイッチには人が操作して動作する「操作スイッチ」と、状況によって動作する「検知スイッチ(センサー)」があります。 ここでは「操作スイッチ」について紹介します。

4.パンチルト機構について

「パンチルト機構」について紹介します。

カメラを左右に動かすことを「パン」と言い、上下に動かすことを「チルト」と言います。
これらを合わせてカメラを上下に動かすことを「パンチルト」と言います。

安価な「RCサーボ」SG90 を使用した「パンチルト」機構が下写真になります。
「パンチルト」機構のマウント部の部品だけのものや、「RCサーボ」が2個セットになったものが販売されています。

組み立ては自分でする必要があり、はめ込み部分や稼働部の精度はあまり良くないですが、動作確認程度には十分と思います。(ネジがいっぱい付いてますが、いっぱい余りますw)

RCサーボでパンチルト操作
RCサーボでパンチルト操作
RCサーボでパンチルト操作

土台の部分を固定するためにサーボの付属品を使いますが、これをかなり加工しないと組み立てられません。ニッパーやヤスリ等を使って下写真のように加工して組み立てます。

RCサーボでパンチルト操作
RCサーボでパンチルト操作
RCサーボでパンチルト操作

5.配線図と動作確認

配線図と動作について紹介します。
アナログ出力仕様とシリアル通信(I2C)仕様で若干異なります。

・安定動作用コンデンサの接続

まずは「RCサーボ」をマイコンボードで安定して動作させるためコンデンサについて紹介します。

なくても動作はしますが、安定動作のために「セラミックコンデンサ(0.1μF)」と「電解コンデンサ(100μF)」を接続します。
これがないと「RCサーボ」激しく操作した時に動かなくなる時があります。

各コンデンサの効果について
・セラミックコンデンサ
通称「パスコン」と呼ばれるもので、「バイパスコンデンサ」の略です。
マイコンボードの電源両端(できるだけ近く)に接続し、外部回路からのノイズをバイパスして逃します。
サーボモーターのブラシから発生するノイズ等がマイコンボードへ侵入することを防止してノイズによる誤動作を防止します。
電解コンデンサ
サーボモーターが動作する時や反転動作する時には大きな電流(起動電流や突入電流という)が流れます。
この電流によってマイコンボードの電圧が低下するため、マイコンボードがリセットされたり、サーボが止まったり暴走して暴れたりします。
電解コンデンサには電圧を蓄えることができ、マイコンボードの電源両端に接続することで突入電流による電圧低下を軽減することができます。
コンデンサを付けても、あまり激しく動かし続けると動作しなくなることがあります。
この場合はサーボ用の別電源を準備しましょう。

・アナログ出力仕様

アナログ出力仕様のジョイスティックを接続した写真は以下のようになります。

ジョイスティック(JoyStick)アナログ仕様

配線図

配線図は以下のようになります。
ブレッドボードやL型(直角)ピンヘッダー、ジャンパー線、GROVEコネクタ付配線を使用して接続します。

ジョイスティック(JoyStick)の使い方
ジョイスティックには「+5V」と書いてあっても「M5StickC Plus」の入力端子電圧仕様は3.3Vのため、ジョイスティックの電源には「3.3V」を接続しましょう。

動作確認

ジョイスティックを操作すると液晶画面に各軸のA/D変換値「X:, Y:」の「0〜4095」と動作角度「Xr:, Yr:」の「0〜180°」が表示されます。
スティックを押し込むと「Press:」が0から1になります。

ジョイスティックの動作確認
ジョイスティックの動作確認
ジョイスティックの動作確認
ジョイスティックの動作確認
今回使用した「アナログ出力仕様」では、スティックの最大動作範囲の半分ぐらい動かしたところで最大出力電圧に達したため、細かい角度調整をするのが難しいですが、この場合は斜めに操作した時でもX,Y軸共に最大出力電圧まで取得することができることになります。
※上写真はスティックをテープで固定して撮影しています。実際は指を離すとスティックは中央に戻ります。

・シリアル出力(I2C)仕様

シリアル出力(I2C)仕様のジョイスティックを接続した写真は以下のようになります。

ジョイスティック(JoyStick)I2C通信仕様

配線図

配線図は以下のようになります。
ブレッドボードやL型(直角)ピンヘッダー、GROVEコネクタ付配線を使用して接続します。

ジョイスティック(JoyStick)の使い方

動作確認

ジョイスティックを操作すると液晶画面に各軸の座標データ「X:, Y:」の「0〜255」と動作角度「Xr:, Yr:」の「0〜180°」が表示されます。
スティックを押し込むと「Press:」が0から1になります。

ジョイスティックの動作確認
ジョイスティックの動作確認
ジョイスティックの動作確認
ジョイスティックの動作確認
今回使用した「シリアル通信仕様」では、スティックの中央から最大動作範囲まで直線的に座標データを取得できましたが、この場合は斜めいっぱいに操作してもX,Y軸共に中途半端な値までしか取得できないことになります。
また、ちょっと精度が悪いのか最大まで操作しても最大値の「255」にはなりません。
※このジョイスティックはスティックを少し倒した時は指を離すと中央に戻りますが、最大まで倒すとその位置で保持されるため自分で戻す必要があります。
ものによって変わるとは思いますが、今回使ったものの比較では斜めで最大角度まで動作させたい場合は「アナログ出力仕様」上下左右に細かな調整をしたい場合は「シリアル通信仕様」と使い分けるのが良さそうです。

6.サンプルプログラム(コピペ)

プログラムは以下に準備しましたので「コピペ」して書き込んでください。
アナログ出力仕様はこの下、シリアル通信(I2C)仕様はさらに下にあります。
※コピーは下コード(黒枠)内の右上角にある小さなアイコンのクリックでもできます。

・アナログ出力仕様

#include <M5StickCPlus.h>     // ヘッダーファイル
// 変数宣言
float x_data;   // ジョイスティックX軸
float y_data;   // ジョイスティックY軸
int press;      // ジョイスティック押し込みボタン
float setting[16][5]; // チャンネル[0〜15]ごとの[周波数, bit数, 0゜パルス時間ms, 最大角度パルス時間ms, 最大動作角度]格納配列
float x_angle;        // X軸角度指示値
float y_angle;        // Y軸角度指示値
float duty_angle;     // X軸角度初期値
float duty_y_angle;   // Y軸角度初期値
float read_x_angle;   // X軸角度現在値
float read_y_angle;   // Y軸角度現在値
int cnt = 0;  // カウント用
/******************* PWM出力、サーボ仕様設定関数 *******************/
void servo_set(int pin, int channel, float freq, float bit_num, float time_min, float time_max, float angle_max) {
  // サーボ設定値をチャンネルごとの配列に格納
  setting[channel][0] = freq;       // 周波数
  setting[channel][1] = bit_num;    // bit数
  setting[channel][2] = time_min;   // 0゜パルス時間ms
  setting[channel][3] = time_max;   // 最大角度パルス時間ms
  setting[channel][4] = angle_max;  // 最大動作角度
  // PWM設定
  pinMode(pin, OUTPUT);               // PWM用ピンを出力設定
  ledcSetup(channel, freq, bit_num);  // PWM設定(チャンネル, 周波数, ビット数)
  ledcAttachPin(pin, channel);        // PWMチャンネル割り当て(ピン番号, チャンネル)
}
/******************* サーボ動作実行関数 *******************/
float servo(int channel, float angle) {
  float resolution;   // 分解能
  float period;       // 周期ms
  float duty_min;     // 0゜Duty計算値
  float duty_max;     // 最大角度Duty計算値
  float duty_active;  // 動作範囲のDuty計算値
  int duty_value;     // PWM出力Duty値(High状態)※整数型として小数点以下切り捨て
  float read_angle;   // PWM出力Duty値からの角度換算

  // サーボ定数算出
  resolution = pow(2, setting[channel][1]);                 // 分解能(2のbit数乗)
  period = 1000 / setting[channel][0];                      // 周期(1000ms / 周波数) 
  duty_min = (resolution / period) * (setting[channel][2]); // 0゜Duty計算値((分解能/周期)*0゜パルス時間μs)
  duty_max = (resolution / period) * (setting[channel][3]); // 最大角度Duty計算値((分解能/周期)*最大角度パルス時間μs)
  duty_active = duty_max - duty_min;                        // 動作範囲のDuty計算値
  duty_value = (angle * (duty_active / setting[channel][4])) + duty_min;  // 角度指定値(浮動小数点数) → PWM出力Duty値(整数)換算

  if (duty_value <= duty_min) { // PWM出力Duty値が0゜Duty計算値以下なら
    duty_value = duty_min + 1;  // PWM出力Duty値+1
  }
  // PWM出力実行
  ledcWrite(channel, duty_value); // 指定したチャンネルにDuty値を指定してPWM出力実行
  read_angle = (ledcRead(channel) - duty_min) * setting[channel][4] / duty_active;  // PWM出力Duty値を取得して角度に換算
  return read_angle;  // 角度を返す
}
// 初期設定 ----------------------------------------------------------
void setup(){
  M5.begin();  // 本体初期化
  // アナログ入力設定
  pinMode(32, ANALOG);  //アナログ入力
  pinMode(33, ANALOG);  //アナログ入力
  // G36とG25は同時使用不可。使っていない方は以下のようにフローティング入力にする
  gpio_pulldown_dis(GPIO_NUM_36);
  gpio_pullup_dis(GPIO_NUM_36);
  // 入力設定
  pinMode(0, INPUT_PULLUP); //入力設定(プルアップ)

  // PWM出力、サーボ仕様設定(サーボごとに使用する端子、チャンネル等を設定)
  // PWM出力のチャンネルは 0,1/ 2,3/ 4,5/ 6,7/ 8,9/ 10,11 /12,13 /14,15でペア ※周波数と分解能はペアで同じにする必要があります。
  // (出力端子, チャンネル, 周波数, bit数, 0゜パルス時間ms, 最大角度動作時間ms, 最大動作角度)
  servo_set(26, 1, 50, 12, 0.5, 2.4, 180); // チャンネル1(X軸):PWM出力、サーボ仕様設定関数呼び出し
  servo_set(25, 2, 50, 12, 0.5, 2.4, 180); // チャンネル2(Y軸):PWM出力、サーボ仕様設定関数呼び出し

  // LCD表示設定
  M5.Lcd.setTextFont(4);  // フォント設定
  M5.Lcd.fillScreen(BLACK);  M5.Lcd.setTextColor(WHITE, BLACK); // 背景、文字色
}
// メイン処理 --------------------------------------------------------
void loop() {
  M5.update();  // ボタン状態更新
  // A/D変換、角度換算処理
  x_data = analogRead(32);                     // アナログ電圧をデジタル値に変換して取得(0〜4095)
  x_angle = 180 - (x_data * (180.0 / 4095.0)); //角度へ換算(動作反転)
  y_data = analogRead(33);                     // アナログ電圧をデジタル値に変換して取得(0〜4095)
  y_angle = y_data * (180.0 / 4095.0);         //角度へ換算

  // サーボ動作指定(戻り値として角度を取得)
  read_x_angle = servo(1, x_angle); // チャンネル1:サーボ動作実行関数呼び出し(チャンネル, 角度値)
  read_y_angle = servo(2, y_angle); // チャンネル2:サーボ動作実行関数呼び出し(チャンネル, 角度値)
  // スティック押し込みボタン検出
  if (digitalRead(0)) { // スティックが押されたら
    press = 0;          // pressを1
  } else {              // 押されてなければ
    press = 1;          // pressを2
  }
  // 液晶表示
  if (cnt == 30) {  // カウント30ごとに液晶表示更新
    M5.Lcd.setCursor(0, 0);                     // 座標指定
    M5.Lcd.println(" JoyStick");                // 項目表示
    M5.Lcd.printf("X : %3.0f      \n", x_data); // X軸アナログ値
    M5.Lcd.printf("Y : %3.0f      \n", y_data); // Y軸アナログ値
    M5.Lcd.printf("Press : %d   \n\n", press);  // 押し込みボタン状態表示
    M5.Lcd.printf("Xr : %3.1f'     \n", read_x_angle); // x軸角度
    M5.Lcd.printf("Yr : %3.1f'     \n", read_y_angle); // y軸角度
    cnt = 0;  // カウントリセット
  }
  cnt++;      // カウント +1
  delay(10);  // 遅延時間
}

・シリアル通信(I2C)仕様

#include <M5StickCPlus.h>     // ヘッダーファイル
// 変数宣言
float x_data;   // ジョイスティックX軸
float y_data;   // ジョイスティックY軸
int press;      // ジョイスティック押し込みボタン
float setting[16][5]; // チャンネル[0〜15]ごとの[周波数, bit数, 0゜パルス時間ms, 最大角度パルス時間ms, 最大動作角度]格納配列
float x_angle;        // X軸角度指示値
float y_angle;        // Y軸角度指示値
float duty_angle;     // X軸角度初期値
float duty_y_angle;   // Y軸角度初期値
float read_x_angle;   // X軸角度現在値
float read_y_angle;   // Y軸角度現在値
int cnt = 0;    // カウント用
/******************* PWM出力、サーボ仕様設定関数 *******************/
void servo_set(int pin, int channel, float freq, float bit_num, float time_min, float time_max, float angle_max) {
  // サーボ設定値をチャンネルごとの配列に格納
  setting[channel][0] = freq;       // 周波数
  setting[channel][1] = bit_num;    // bit数
  setting[channel][2] = time_min;   // 0゜パルス時間ms
  setting[channel][3] = time_max;   // 最大角度パルス時間ms
  setting[channel][4] = angle_max;  // 最大動作角度
  // PWM設定
  pinMode(pin, OUTPUT);               // PWM用ピンを出力設定
  ledcSetup(channel, freq, bit_num);  // PWM設定(チャンネル, 周波数, ビット数)
  ledcAttachPin(pin, channel);        // PWMチャンネル割り当て(ピン番号, チャンネル)
}
/********************** サーボ動作実行関数 **********************/
float servo(int channel, float angle) {
  float resolution;   // 分解能
  float period;       // 周期ms
  float duty_min;     // 0゜Duty計算値
  float duty_max;     // 最大角度Duty計算値
  float duty_active;  // 動作範囲のDuty計算値
  int duty_value;     // PWM出力Duty値(High状態)※整数型として小数点以下切り捨て
  float read_angle;   // PWM出力Duty値からの角度換算

  // サーボ定数算出
  resolution = pow(2, setting[channel][1]);                 // 分解能(2のbit数乗)
  period = 1000 / setting[channel][0];                      // 周期(1000ms / 周波数) 
  duty_min = (resolution / period) * (setting[channel][2]); // 0゜Duty計算値((分解能/周期)*0゜パルス時間μs)
  duty_max = (resolution / period) * (setting[channel][3]); // 最大角度Duty計算値((分解能/周期)*最大角度パルス時間μs)
  duty_active = duty_max - duty_min;                        // 動作範囲のDuty計算値
  duty_value = (angle * (duty_active / setting[channel][4])) + duty_min;  // 角度指定値(浮動小数点数) → PWM出力Duty値(整数)換算

  if (duty_value <= duty_min) { // PWM出力Duty値が0゜Duty計算値以下なら
    duty_value = duty_min + 1;  // PWM出力Duty値+1
  }
  // PWM出力実行
  ledcWrite(channel, duty_value); // 指定したチャンネルにDuty値を指定してPWM出力実行
  read_angle = (ledcRead(channel) - duty_min) * setting[channel][4] / duty_active;  // PWM出力Duty値を取得して角度に換算
  return read_angle;  // 角度を返す
}
// 初期設定 ----------------------------------------------------------
void setup(){
  M5.begin();         // 本体初期化
  Wire.begin(32, 33); // Grove端子をI2C設定(SDA, SCL)

  // PWM出力、サーボ仕様設定(サーボごとに使用する端子、チャンネル等を設定)
  // PWM出力のチャンネルは 0,1/ 2,3/ 4,5/ 6,7/ 8,9/ 10,11 /12,13 /14,15でペア ※周波数と分解能はペアで同じにする必要があります。
  // (出力端子, チャンネル, 周波数, bit数, 0゜パルス時間ms, 最大角度動作時間ms, 最大動作角度)
  servo_set(26, 1, 50, 12, 0.5, 2.4, 180); // チャンネル1(X軸):PWM出力、サーボ仕様設定関数呼び出し
  servo_set(25, 2, 50, 12, 0.5, 2.4, 180); // チャンネル2(Y軸):PWM出力、サーボ仕様設定関数呼び出し

  // LCD表示設定
  M5.Axp.ScreenBreath(9); // 液晶画面明るさレベル(標準12)
  M5.Lcd.setTextFont(4);  // フォント設定
  M5.Lcd.fillScreen(BLACK);  M5.Lcd.setTextColor(WHITE, BLACK); // 背景、文字色
}
// メイン処理 --------------------------------------------------------
void loop() {
  // ジョイスティックI2Cデータ取得
  Wire.requestFrom(0x52, 3);  // I2Cデータ取得(アドレス、バイト数)
  while (Wire.available()) {  // 受信データがあれば
    x_data = Wire.read();     // X軸アナログ値取得(0〜255)
    y_data = Wire.read();     // Y軸アナログ値取得(0〜255)
    press = Wire.read();      // 押し込み時ボタン状態取得(true/false)
  }
  //  ジョイスティック座標-角度換算
  x_angle = map(x_data, 0, 255, 0, 180);  // X軸 - 角度換算
  y_angle = map(y_data, 0, 255, 0, 180);  // Y軸 - 角度換算

  // サーボ動作指定(戻り値として角度を取得)
  read_x_angle = servo(1, x_angle); // チャンネル1:サーボ動作実行関数呼び出し(チャンネル, 角度値)
  read_y_angle = servo(2, y_angle); // チャンネル2:サーボ動作実行関数呼び出し(チャンネル, 角度値)
  // 液晶表示
  if (cnt == 30) {  // カウント30ごとに液晶表示更新
    M5.Lcd.setCursor(0, 0);                     // 座標指定
    M5.Lcd.println(" JoyStick");                // 項目表示
    M5.Lcd.printf("X : %3.0f      \n", x_data); // X軸アナログ値
    M5.Lcd.printf("Y : %3.0f      \n", y_data); // Y軸アナログ値
    M5.Lcd.printf("Press : %d   \n\n", press);  // 押し込みボタン状態
    M5.Lcd.printf("Xr : %3.0f'     \n", read_x_angle); // x軸角度
    M5.Lcd.printf("Yr : %3.0f'     \n", read_y_angle); // y軸角度
    cnt = 0;  // カウント0リセット
  }
  cnt++;      // カウント +1
  delay(10);  // 遅延時間
}

7.サンプルプログラムの詳細

サンプルプログラムについて詳しく紹介します。

・サーボの制御

「RCサーボ」の制御については以前も紹介しましたが、PWM制御とサーボの設定を行う「servo_set()」関数、サーボ動作を実行する「servo()」関数を準備して制御しています。

 15行目 〜 26行目が「servo_set()」関数です。
ここで、チャンネルごとに各サーボの仕様に合わせたPWM制御の初期設定を行っています。

 28行目 〜 52行目が「servo()」関数です。
ここで、指定されたサーボのチャンネルと動作角度からPWM制御の「Duty比」を算出してPWM制御でサーボの動作を実行します。
さらに、戻り値として角度を返すようにしているため、メイン処理内で指定した変数に角度の値を格納して使用できます。

「PWM制御」についてと「RCサーボ」の制御方法については以下のリンクで詳しく紹介しています。

PWM制御とは?Arduino(ESP32)コマンドで使い方を詳しく紹介
PWM制御の基本動作からArduinoコマンドを使ったプログラミング方法、サンプルプログラムを使用して音(ブザー)と光(LED)で動作確認しながら使い方を詳しく紹介します。
RCサーボモータとは、使い方と簡単制御方法(Arduinoコマンド、ライブラリ不要)の紹介
ラジコンの駆動部等に使用されるRCサーボについての簡単な制御方法をサンプルプログラムで詳しく紹介します。ATOM LITE使用(M5Stack社製ESP32系マイコンボード)

・ジョイスティックの制御(アナログ出力仕様)

アナログ出力仕様のサンプルプログラムの 56行目 〜 63行目でジョイスティックからのアナログ出力を接続するためのアナログ入力端子の設定と、スティックを押し込んだ時のON/OFFスイッチを接続する入力端子の設定を行なっています。

 78行目 〜 82行目でジョイスティックからのアナログ電圧をデジタル値に変換して取得(0〜4095)しサーボの動作角度に換算しています。

 85行目 〜 86行目で、使用するサーボの「チャンネル」と「動作角度」を指定して「servo_set()」関数を呼び出し、サーボの動作を実行します。

 88行目 〜 92行目ではスティックを押し込んだ時のボタンのON/OFF状態を取得しています。


・ジョイスティックの制御(シリアル通信(I2C)仕様)

シリアル通信(I2C)仕様のサンプルプログラムの 56行目でGROVEコネクタの端子「32(SDA), 33(SCL)」をシリアル通信用端子として設定します。

 71行目〜77行目でジョイスティックとの通信を行なっています。
シリアル通信(I2C)でX軸、Y軸の座標をそれぞれ「0〜255」で取得し、スティックを押し込んだ時のスイッチの「ON/OFF」状態を「 1 / 0 」で取得します。

シリアル通信部を以下に抜粋し詳しく紹介します。

  // ジョイスティックI2Cデータ取得
  Wire.requestFrom(0x52, 3);  // I2Cデータ取得(アドレス、バイト数)
  while (Wire.available()) {  // 受信データがあれば
    x_data = Wire.read();     // X軸アナログ値取得(0〜255)
    y_data = Wire.read();     // Y軸アナログ値取得(0〜255)
    press = Wire.read();      // 押し込み時ボタン状態取得(true/false)
  }

Wire.requestFrom(0x52, 3)」で通信アドレス「0x52」に「3バイト」のデータ取得をリクエストするとジョイステックからデータが送られてきます。
「while文」の中で「Wire.available()」を実行して、受信データがある間「Wire.read()」を実行してデータを各「変数」に格納します。

受信データは 1バイト目が「X軸」、2バイト目が「Y軸」、3バイト目が「スイッチの状態」です。

 79, 80行目で「map関数」を使用してX,Y軸の座標データ「0〜255」をサーボの動作角度「0〜180(° )」に換算し各「変数」に格納しています。

座標データを、角度に換算するには「Aruduino」コマンドの「map関数」が便利なのでここで紹介しておきます。

「map関数」の使い方
map
( 変換対象, 変換対象の最小値, 変換対象の最大値, 変換後の最小値, 変換後の最大値 ) ; 

変換対象:変換対象の変数等を指定(サンプルプログラムでは「x_data」又は「y_data」)
変換対象の最小値:変換対象の最小値を指定(サンプルプログラムでは0)
変換対象の最大値:変換対象の最大値を指定(サンプルプログラムでは255)
変換後の最小値:変換後の最小値を指定(サンプルプログラムでは0)
変換後の最大値:変換後の最大値を指定(サンプルプログラムでは180)

最後に 83, 84行目で、使用するサーボの「チャンネル」と「動作角度」を指定して「servo_set()」関数を呼び出し、サーボの動作を実行します。

7.準備するもの

今回使用した部品は以下になります。

「M5StickC Plus」は入出力端子は少ないですが液晶表示付で、2個のボタンやブザー、振動センサ、Wi-Fi、Bluetooth通信等機能が豊富でいろいろなアイデアを試すには最適です。


パンチルト機構は「RCサーボSG90」を2個お持ちの方はカメラマウントのみで購入できます。

「RCサーボ」をお持ちでない方はサーボ付きもあります。
このセットのサーボは「SG90R」で「SG90」のトルクアップ品です。


ジョイスティックは種類が豊富で迷いますが、今回使用したものは以下になります。

アナログ出力仕様

シリアル通信(I2C)仕様


コンデンサは安心の日本製(村田製作所、ニチコン、ケミコン等)がおすすめ


その他、配線に便利なブレッドボードやL型(直角)ピンヘッダー、ジャンパー線、GROVEコネクタ付配線です。

8.まとめ

パンチルト機構を使用して、「ジョイスティック」について詳しく紹介しました。

パンチルトとは、カメラを左右に動かすことを「パン」上下に動かすことを「チルト」と言うことに由来し、これらを合わせてカメラを上下左右に動かすことを「パンチルト」と言います。

「ジョイスティック」はパンチルトのような上下左右に動作するものをコントロールするのに最適で、ゲームのコントローラ部等にも使用されます。

「ジョイスティック」の動作原理は、内部に「X軸」「Y軸」方向に操作した時にそれぞれの操作量、方向に応じて変動する2つのボリューム(可変抵抗器)があり、「アナログ出力仕様」は「0V〜ボリュームの両端電圧」までの電圧が出力され、「シリアル通信仕様」は「0〜255」等の座標データを「1バイト」等のデータで出力します。
これらの出力を読み取ることでスティックの操作位置を取得することができます。

スティック部を押し込むと「ON/OFFスイッチ」として機能するものが多いです。

今回使用した「M5StickC Plus」等、「M5Stack」社製のマイコンボードにはWi-FiやBluetooth機能が搭載されているため「ジョイスティック」で遠隔操作するものも手軽に製作することができます。

次回はBluetooth通信を使用して、「ジョイスティック」で操作できるラジコンの作り方を紹介します。

LEGOで作るBluetoothラジコンカー M5StickC Plus2 + ATOM Lite
M5StickC Plus2を使用してBluetoothでジョイスティック操作のLEGOラジコンの作り方を紹介。駆動はRCサーボでATOM Liteで制御します。
LEGOで作るBluetooth遠隔操作ラジコン(Arduinoコマンド、ESP32系マイコンATOM使用)
M5StickC PlusとATOMを使用してBluetooth通信とジョイスティックで操作するラジコンカーをLEGOブロックで作ります。LEGOなので組み合わせは自由!自分好みのラジコンを作りましょう♪

3Dプリンターを使用して、今回使用した基板タイプの「ジョイスティック」用ケースの作り方も紹介しています。

ダヴィンチmini w+ 3Dプリンタの使い方③ 3DCAD編
フリーの3DCAD「Fusion360」を使用して基板を収める簡単なケースのモデリング方法から、印刷用データへ変換、実際に印刷して確認するところまで紹介します。

コメント

タイトルとURLをコピーしました