TAMIYAの定番RCカーであるランチボックスには、ECSやサーボやモーターなど含まれています。Raspberry Piでリモート操作をしようという記事の第2回です。前回はサーボを動かしました。今回はUSBゲームコントローラとRaspberry Piにてランチボックスのモータを動かしてみましょう。
各種資料
TAMIYA1/12RC XB(完成モデル) ランチボックス (ITEM 57749)
https://d7z22c0gz59ng.cloudfront.net/cms/japan/download/rcmanual/58347.pdf
〇バッテリー:7.2Vニカドバッテリー
https://www.tamiya.com/japan/products/55085/index.html
〇ESC:TBLE-04S
https://d7z22c0gz59ng.cloudfront.net/cms/japan/download/rcmanual/45069.pdf
〇サーボ:TSU-01
https://www.tamiya.com/japan/products/10318/index.html
〇モーター:540
https://www.tamiya.com/japan/products/54358/index.html
〇受信機 (TRU-08)
https://d7z22c0gz59ng.cloudfront.net/cms/japan/download/rcmanual/45053.pdf
各種資料からプログラムの仕様を策定
ESCはTBLE-04Sです。標準的なESCやサーボは20ms(50Hz)です。たぶん同じでしょう。多くのジョイスティックでは、軸の値は-32767 から 32767 の範囲になります。大抵は-1 から 1 の範囲に正規化します。
axis_value = event.state / 32767
ジョイスティックを最も上に倒したとき(前進): axis_value = -1
ジョイスティックを中央に戻したとき(ニュートラル): axis_value = 0
ジョイスティックを最も下に倒したとき(後退): axis_value = 1
最小パルス幅:
axis_value = -1 のとき:
pulse_width = 1.5 + (-1 * 0.1) = 1.4ms
最大前進 の状態です。
ニュートラル:
axis_value = 0 のとき:
pulse_width = 1.5 + (0 * 0.1) = 1.5ms
モーターは 停止 します。
最大パルス幅:
axis_value = 1 のとき:
pulse_width = 1.5 + (1 * 0.1) = 1.6ms
最大後退 の状態です。
そのような感じで、1.5msがESCのニュートラル(停止)状態になります。またフルスピードで動作するとぶっ飛んでゆきますので、パルス幅を1.4msから1.6msに制限することで、モーターの速度を全体の 20% 程度 に抑えゆっくりスタートできるようになります。
パルス幅をフレーム幅(20ms)で割ることで、デューティサイクルを求めます。これにより0から1の範囲でデューティサイクルを設定できます。デューティサイクルとは、一定周期で連続するパルス波において、パルスがオンになる時間とオフになる時間の比率のことです。
def set_esc_speed(pulse_width_ms):
pulse_width_s = pulse_width_ms / 1000 # パルス幅を秒単位に変換
frame_width_s = 1 / 50 # フレーム幅(秒)= 20ms
duty_cycle = pulse_width_s / frame_width_s # デューティサイクルの計算
esc.value = duty_cycle # ESCにデューティサイクルを設定
以上でジョイスティックで前進後退を制御するプログラムを作成します。
sudo nano joystick_motertest.py
from inputs import get_gamepad
from gpiozero import PWMOutputDevice
from gpiozero.pins.pigpio import PiGPIOFactory
import time
# GPIOの設定(PiGPIOFactoryを使って精密制御)
factory = PiGPIOFactory()
esc = PWMOutputDevice(12, pin_factory=factory, frequency=50) # 50HzのPWM信号
def set_esc_speed(pulse_width_ms):
# パルス幅をミリ秒からデューティサイクルの値に変換(フレーム幅は20ms)
pulse_width_s = pulse_width_ms / 1000 # パルス幅を秒単位に変換
frame_width_s = 1 / 50 # フレーム幅(秒)
duty_cycle = pulse_width_s / frame_width_s # デューティサイクルの計算
esc.value = duty_cycle # ESCにデューティサイクルを設定
def main():
print("ジョイスティックを監視中...")
while True:
events = get_gamepad()
for event in events:
print(event.ev_type, event.code, event.state)
if event.code == "ABS_Y":
# ジョイスティックのY軸が動いた場合
axis_value = event.state / 32767 # -1 から 1 の範囲に正規化
# パルス幅を1.4msから1.6msにマッピング(前進または後退の速度を制限)
pulse_width = 1.5 + (axis_value * 0.1) # パルス幅をミリ秒単位で計算
set_esc_speed(pulse_width) # ESCにパルス幅を設定
print(f"ESCパルス幅を {pulse_width:.2f} msに設定")
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\nプログラムを終了します...")
GPIO 12からPWM信号を発信
今回テストなのでGPIO 12から信号を出します。ラズパイ4のGround、GPIO12をESCの黒と白に接続します。黒はGround、白はPWMです。下記図参考です。3Vと5Vは使いません。RC側のバッテリー側から使います。
①がGND、②がGPIO12(PWM)です。
ESC側の3ピン(黒、赤、白)に接続します。黒はGround、白はPWMです。黒に先の①ピンから、白に先の②GPIO12番です。
ESC側から3ピン(黒、赤、白)がこんな感じに出ています。黒はGround、赤は電力、白はPWMです。赤の部分は、RCカーのバッテリーから取りたいので、2.4Ghzユニットに赤いピンを繋ぎます。
電力は受信機(TRU-08)から取得
このTRU-08の2番の真ん中のピンを赤に接続します。受信機(TRU-08)の3ピンの真ん中のピンは、サーボやESCに電力を提供している電源ピンです。
通常のRCカーでは受信機がサーボやESCに電源を供給します。受信機はバッテリーから電力を受け取り、その電力をサーボやESCに配分します。
受信機の3ピンコネクタは一般的に以下のようになっています。
外側: GND(グランド)
中央: +電源(通常は5V程度)
内側: 信号線(PWMなど)
Raspberry Piの電圧3.3Vや5Vピンの電流は相当低いです。Raspberry Piから電力を共有するとまともに動かないか、何かのタイミングで壊れる可能性もあります。なので受信機からの電源を使います。
説明だと分かりにくいですが、全体的にはこんな配線です。GNDとPWMはRaspberry Piからです。Raspberry PiからESCやサーボに制御信号(PWM)を送信する場合、送信側(Raspberry Pi)と受信側(ESCやサーボ)のグランド(GND)が共通である必要があります。グランドが共通でないと、信号が正しく伝達されない可能性があります。共通というのはRaspberry Piから信号を送ったらGNDもRaspberry Piのものを使うという意味です。
ゲームパットでモーターが動いた!!