FirmataとXboxOneControllerを使用してArduinoRoverを制御する
コンポーネントと消耗品
| × | 1 | ||||
![]() |
| × | 1 | |||
![]() |
| × | 1 |
アプリとオンラインサービス
> ![]() |
|
このプロジェクトについて
数ヶ月前、私は小さなローバー(Arduino Unoによって制御されている)を非常に手頃な価格で購入しました。キットは非常に完成度が高く、車のシャーシ、2つの車のホイール、2つのDCギアモーター、UNO R3、L298NデュアルHブリッジモーターコントローラー、その他のいくつかのコンポーネントです。
このローバーは、自律動作用にプログラムすることを目的としています。したがって、超音波センサーとサーボもキットに追加されています。また、素晴らしいArduinoセンサーシールド5がキットに含まれています。はい、それは本当にお買い得でした;-)
しかし、私のアイデアは、Xbox OneコントローラーとFirmataプロトコルの両方を使用して、自分自身または息子の1人がこれを駆動することでした。そして、それは非常にうまく機能します!
これが最終的な解決策のビデオです:
このプロジェクトで使用される主な部分は次のとおりです。
- ローバーキット(このデモでは、ベースプレート、ホイール、モーター、Arduino Uno、9ボルトのバッテリーホルダー、L298NデュアルHブリッジモーターコントローラーなどのパーツのサブセットのみを使用します)
- 単三電池6本用の予備の電池ホルダー
- Bluetoothモジュール(HC-06)
- Windows用のワイヤレスアダプターを備えたXboxOneコントローラー(ラップトップに接続するため)
- ラップトップ(Windows 10 + VS2015 + Bluetoothドングル付き)
- 劇的な効果のみを目的とした点滅ライト
キットの作成
キットの作成はそれほど難しくありません。建設マニュアルは中国語で書かれていましたが、すべてかなり論理的に思えます。ベースプレートは1つしかないため、その上にいくつかのコンポーネントを配置し、下部にいくつかのコンポーネントを配置する必要がありました(現在はモーターコントローラー):
<図>
この写真では、2つの異なるバッテリーホルダーが追加されています。プログラミング中に、モーターを動作させるためだけに別の電源を使用する必要があることに気付きました。
モーターの接続–コントローラーのピンレイアウト
今回のハードウェアの中心は、Arduino Unoではなく、モーターコントローラーです。
「L298は、DCブラシ付きモーターとステッピングモーター用のデュアルHブリッジドライバーです。広い動作電圧範囲をサポートし、日曜大工のプロジェクトでアクセス可能なスルーホールパッケージでチャネルごとに2Aを供給できます。」
このコントローラーは、Arduinoからの信号を使用して、2つのモーターのそれぞれの速度と方向を制御します。
<図>
L298NデュアルHブリッジモーターコントローラーのピンレイアウトは次のとおりです。
- DCモーター1のプラス+
- マイナス–DCモーター1の
- 電源入力。別のバッテリーホルダーから9ボルトを供給します
- 共通点。別のバッテリーホルダーとArduinoの両方に接続されています
- 停電 。 5ボルトを生成できます(未使用 。私のArduinoは別のバッテリーホルダーから電力を得ています)
- EnAはArduinoD10に接続されています。このポートはPWM(白)に対応しています
- IN1はArduinoD9に接続されています。 (灰色)
- IN2はArduinoD8に接続されています。 (紫)
- IN3はArduinoD7に接続されています。 (青)
- IN4はArduinoD6に接続されています。 (緑)
- EnBはArduinoD5に接続されています。このポートはPWM(黄色)に対応しています
- DCモーター2のプラス+
- マイナス–DCモーター2の
- 2と3の横にあるジャンパー 削除されません 入力電力を12ボルト(最大35ボルト)を超えないため(ジャンパーは写真にマークされていません)
注:コントローラーには独自の電源装置があります。 Arduinoにも1つあります。物事を実行し続けるために(薄くなることなく、共通の基盤を与えます 。上記の箇条書き4を参照)
モーターの接続–Arduinoのピンレイアウト
Arduinoの接続は非常に簡単です。アースと5ボルトの電源をArduinoに接続します。そして、6本の線(ENA、IN1-4、ENB)をピンD10からD5まで接続します。
<図>
ポート7と8(および他のモーターの場合は9と10)が単なる通常のGPIOポートであることを明確にする必要があります。これらはモーターの方向に使用されます。両方のポート(たとえば、7と8)がLOWの場合、モーターは何もしません(停止します)。一方がHIGHで、もう一方がLOWの場合、モーターは一方向に回転します。逆に接続されている場合(最初のモーターがLOWに設定され、もう1つがHIGHに設定されている場合)、接続されているモーターは反対方向に回転します。
しかし..これらのピンを設定するだけでは何も起こりません。可動部品はまだありません!
魔法はピン5と10から来ます。これらはPWM信号を生成できる「特別な」ピンです。 0〜255の値を設定すると、モーターが非常に低速(停止)または高速で動作することになります。
注:PWMが可能なArduino Unoの各ポートには、チルダ(〜)が付いています。
Bluetoothの接続
私が使用しているBluetoothモジュールは、RXポートとTXポート(ラインを越えて)に接続するだけでよく、Arduinoからの5ボルトの電源とアースが必要です。
ArduinoのFirmataスケッチ
Arduinoに必要なのはFirmataスケッチ「StandardFirmata」だけです。 Arduino IDEの例から取得してアップロードするだけです(アップロードを完了するには、最初にTX / RXの固定を解除する必要があるかもしれません)。
注:Bluetoothモジュールの品質が不足しているため、スケッチ内にハードコードされているボーレートを常に下げて、9600に設定しています。
紳士、エンジンを始動してください
または、接続をテストします…
では、なぜ私はFirmataを使用しているのですか?簡単だからですどれくらい簡単ですか?非常に簡単。そしてそれはプログラミングなしでさえ行うことができます。 Windows Remote Arduino Experienceアプリを起動するだけです(ストアで入手でき、Windows 10 Mobileデバイスでも動作します)。
まず、すでにペアリングされているHC-6Bluetoothモジュールに接続する必要があります。
<図>
ペアリングしたら、PWMページに移動します。デジタルピン5を有効にして、たとえば128の値を指定します。
<図>
注意:次のステップでモーターが動作します。ヘルメットをかぶり、小麦粉を外します。表示すると、その理由がわかります。
次に、デジタルページに移動します。そして、デジタルピン6のスイッチを切り替えます。
<図>
これで、すべてが接続されて実行されている場合、モーターの1つが回転します!
その場合は、他の速度を確認するか(PWM値を高くまたは低くして)、方向を変更します(デジタルピン6を0ボルトに設定し、デジタルピン7を5ボルトに設定します)。
<図>
そして、あなたはそれを持っています。あなたはそのホイールを制御することができます!
しかし、それだけではありません。同じことがピン10(PWM)とデジタルピン9およびデジタルピン8にも当てはまります。
両方の車輪が動いています。コーディングを開始します…
マッチメーカーとしてのUWPアプリ
XboxOneコントローラーとローバーの間に新しいUWPアプリが必要であることは明らかです。
XboxOneコントローラーの使用についてはすでにブログに書いています。今回は、その知識をローバーなしで組み合わせます。
UWPアプリのインターフェースを見てみましょう:
<図>
かなり退屈で、2つのボタンと1つのテキストブロックがあります。最初にFirmataを使用してArduinoに接続する以外に何もする必要はありません。そして、接続が確立されると、コントローラーボタンは、コントローラー入力を読み取り、それを有用なコマンドに変更するために、1つの巨大なループを開始する必要があります。
そして、私たちが作成したいのは、2つのハンドルを備えたこのクラシックなタンクコントロールです。必要なのは、XboxOneコントローラーの2つのサムスティックを確認することだけです。それらを前後に動かすと、対応するモーターも前後に始動します:
注:新しいUWPアプリを起動する場合は、Bluetooth機能を追加することを忘れないでください。また、Firmata用のnugetパッケージをインストールする必要があります。
まず、メインフォームグリッドにXAMLスニペット(Xamlソースコードのコードセクションを参照)を追加して、いくつかのボタンを作成します。
次に、メインフォームのコードビハインド(C#ソースコードのコードセクションを参照)を追加します。私は基本的に2つの部分に分かれています。まず、Firmataプロトコルを使用してBluetooth経由で接続します。次に、XboxOneコントローラーで入力のリッスンを開始します。
コントロールをチェックするためのループ内で、サムスティックが前方または後方を向いているか、「停止」範囲内にあるかを判断します。その後、PWMピンの値を決定します。
PWM値の書き込みが、Firmataではデジタルポートへのアナログ値の書き込みとして表されているのは興味深いことです。 Arduinoクラスには特別なPWMメソッドはありません。
同じ値がArduinoに何度も書き込まれないように、2つのメソッド「ArduinoDigitalWrite」と「ArduinoAnalogWrite」を追加しました。これにより、通信が乱雑になり、Arduinoのパフォーマンスが低下します。 (はるかにリッチなデザインでブザーを追加しました。重複するコマンドを無視しないと、ブザーのパフォーマンスは非常に悪く、聞くのがひどいものでした。)
モーターが低いPMWパルスを取得すると、モーターは直接動作を開始せず、非常に独特の音で鳴ります。これは正常な動作です。それで、2つの電源を追加する必要があることがわかりました。初めてすべてを接続したとき、コントローラーが壊れていると思いました。何も起こらなかった。モーターの1つを抜いて、もう1つが泣き始めるまで。
それがその仕組みです:
<図>
脚注:点滅するライトは劇的な効果のためだけではありません。あなたの作品が動き始めるときはいつでも、安全に注意してください。矛盾はばかげています、あなたはそうではありません!そのため、そもそもこのライトをその上に置いていました。
コード
- 通信を開始するためのXamlコントロール
- コード-UWPアプリのメインフォームの背後にある
通信を開始するためのXamlコントロールスニペット
これを新しいUWPアプリのメインフォームに貼り付けます{tbRead.Text ="ConnectionLost" +メッセージ; btnStart.IsEnabled =true;}); } private async void BluetoothConnectionFailed(string message){await Dispatcher.RunAsync(CoreDispatcherPriority.Normal、()=> {tbRead.Text ="ConnectionFailed" +メッセージ; btnStart.IsEnabled =true;}); } private async void ArduinoDeviceReady(){await Dispatcher.RunAsync(CoreDispatcherPriority.Normal、()=> {tbRead.Text ="Device Ready";}); } private void OnConnectionEstablished(){var action =Dispatcher.RunAsync(CoreDispatcherPriority.Normal、new DispatchedHandler(()=> {DisableEnableButtons(true); ArduinoDigitalWrite(_LeftForward、PinState.LOW); ArduinoDigitalWrite(_LeftBackward、PinState.LOW); ArduinoDigitalWrite (_RightBackward、PinState.LOW); ArduinoDigitalWrite(_RightForward、PinState.LOW);})); } private void DisableEnableButtons(bool enabled){//すべてのボタンを無効にします。それ以外の場合、//「A」はフォーカスされたものを押します。 btnController.IsEnabled =有効; btnStart.IsEnabled =有効; } private async void Gamepad_GamepadRemoved(object sender、Gamepad e){_ Gamepad =null; await Dispatcher.RunAsync(CoreDispatcherPriority.Normal、()=> {tbRead.Text ="コントローラーが削除されました";}); } private async void Gamepad_GamepadAdded(object sender、Gamepad e){_ Gamepad =e; await Dispatcher.RunAsync(CoreDispatcherPriority.Normal、()=> {tbRead.Text ="コントローラーが追加されました";}); } private async void btnController_Click(object sender、RoutedEventArgs e){DisableEnableButtons(false); while(true){await Task.Delay(TimeSpan.FromMilliseconds(3)); if(_Gamepad ==null){続行; } //現在の状態を取得しますvarreading =_Gamepad.GetCurrentReading(); if(Math.Abs(reading.LeftThumbstickY)<_ ActionPoint){ArduinoDigitalWrite(_LeftForward、PinState.LOW); ArduinoDigitalWrite(_LeftBackward、PinState.LOW); sldrLeftSpeed.Value =0; } else if(reading.LeftThumbstickY> =_ActionPoint){ArduinoDigitalWrite(_LeftForward、PinState.HIGH); ArduinoDigitalWrite(_LeftBackward、PinState.LOW); sldrLeftSpeed.Value =255 * Math.Abs(reading.LeftThumbstickY)* _SpeedLimit; } else if(reading.LeftThumbstickY <=-_ActionPoint){ArduinoDigitalWrite(_LeftForward、PinState.LOW); ArduinoDigitalWrite(_LeftBackward、PinState.HIGH); sldrLeftSpeed.Value =255 * Math.Abs(reading.LeftThumbstickY)* _SpeedLimit; } if(Math.Abs(reading.RightThumbstickY)<_ ActionPoint){ArduinoDigitalWrite(_RightForward、PinState.LOW); ArduinoDigitalWrite(_RightBackward、PinState.LOW); sldrRightSpeed.Value =0; } else if(reading.RightThumbstickY> =_ActionPoint){ArduinoDigitalWrite(_RightForward、PinState.HIGH); ArduinoDigitalWrite(_RightBackward、PinState.LOW); sldrRightSpeed.Value =255 * Math.Abs(reading.RightThumbstickY)* _SpeedLimit; } else if(reading.RightThumbstickY <=-_ActionPoint){ArduinoDigitalWrite(_RightForward、PinState.LOW); ArduinoDigitalWrite(_RightBackward、PinState.HIGH); sldrRightSpeed.Value =255 * Math.Abs(reading.RightThumbstickY)* _SpeedLimit; }}} private void ArduinoDigitalWrite(byte port、PinState state){//重複するコマンドを無視するvar examples =_CurrentPinStates.ContainsKey(port); if(!exists || _CurrentPinStates [port]!=state){_ CurrentPinStates [port] =state; _arduino.digitalWrite(port、state); }} private void ArduinoAnalogWrite(byte port、ushort value){//重複するコマンドを無視するvar examples =_CurrentSpeedValues.ContainsKey(port); if(!exists || _CurrentSpeedValues [port]!=value){_ CurrentSpeedValues [port] =value; _arduino.analogWrite(port、value); }}}
製造プロセス
- PythonでArduinoとRFIDを使用した出席システム
- Arduino、1Sheeld、Androidを使用したユニバーサルリモコン
- Arduinoとスマートフォンを使用したDIY電圧計
- IoTを使用してロボットアームをリモート制御する
- Arduinoを使用した周波数とデューティサイクルの測定
- arduinoを使用したソナーと処理IDEでの表示
- BoltとArduinoを使用したLEDの明るさの制御
- Arduinoを使用したシンプルでスマートなロボットアーム
- AlexaとArduinoIoTCloudを使用したテレビのフルコントロール
- ArduinoとRDA8057Mを使用したFMラジオ
- スマートフォンを使用してライトシステムを制御する