Raspberry Pi で戦車を作る(モーターシールド編)

Raspberry Pi用モータードライバボード(キット) – スイッチサイエンス
https://www.switch-science.com/catalog/1239/

今度は、モータードライバーを使ってモーターを動かします。今回使っているのは Raspberry Pi 用のモータードライバーシールドで、4,000円弱という RasPi が買えるかもしれません、というお値段で結構します。慣れれば自作できるようなんですが、手始めにひとつ買ってためしています。ちなみに、このキットは v2 が出ていて adafrutit などから購入できます。

RasPi Robot Board v2 by MonkMakes ID: 1940 – $29.95 : Adafruit Industries, Unique & fun DIY electronics and kits
http://www.adafruit.com/product/1940

動作させるためのサンプルコードは以下にあります。

simonmonk/raspirobotboard2
https://github.com/simonmonk/raspirobotboard2

9V(乾電池6個)を給電すると、RasPi に 5V 給電してくれるので、RasPi 本体への USB 給電がいらなくなるみたいです。私の場合は、両方に 5V ずつ給電しているので、今度試してみましょう。

サンプルコードを追っていくと

– ボード上の LED1,2 を光らせる
– ボード上の SW1,2 を ON/OFF できる
– モーター1,2 を回転/逆回転できる

ことが分かります。残念ながらスピード制御はできないので、戦車のようなキャタピラ式のものとか、ギア比を変えてアームを動かすとかに使えますね。PWM制御(パルス制御)のほうは、別途回路を組んで実験していきます。

両輪のギアーボックスを使うと、右左の車輪を別々に制御できるので、車体を右左に曲げることができます。普通の車のようにハンドル+後輪駆動みたいにしたい場合は、別途サーボ制御が必要になるのですが、キャタピラ式はこれで十分だったりします。まあ、普通のラジコンカーを作るのも今後の課題ですね。

ピンを調べる

さて、ON/OFF のピンは、サンプルの python スクリプトを見ると以下のようになっています。

https://github.com/simonmonk/raspirobotboard/blob/master/raspirobotboard.py

LEFT_GO_PIN = 17
LEFT_DIR_PIN = 4
RIGHT_GO_PIN = 10
RIGHT_DIR_PIN = 25
SW1_PIN = 11
SW2_PIN = 9
LED1_PIN = 7
LED2_PIN = 8
OC1_PIN = 22
OC2_PIN = 21

RasPi 専用のシールドなので、GPIO のピンは RasPi に合わせてあるわけですが、この GPIO の番号と Arduino のそれとを合わせてやれば、Arduino でも使うことができると思います。まあ、Arduino 専用のものを買ったほうが早かったり、自作したほうがいい気もしますが。

C# で使えるように書き直す

後で整理して git にアップしますが、python のコードを C# に書き直したのが次のものです。
内部的に

AlexSartori/RaspberryGPIOManager
https://github.com/AlexSartori/RaspberryGPIOManager

をちょっと改変して使っています。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RaspberryGPIOManager;
using System.Threading;

namespace RaspiRobotNet
{
    public class RaspiRobot
    {
		const int LEFT_GO_PIN = 17;
		const int LEFT_DIR_PIN = 4;
		const int RIGHT_GO_PIN = 10;
		const int RIGHT_DIR_PIN = 25;
		const int SW1_PIN = 11;
		const int SW2_PIN = 9;
		const int LED1_PIN = 7;
		const int LED2_PIN = 8;
		const int OC1_PIN = 22;
		const int OC2_PIN = 21;

		public GPIOPinDriver LED1 { get; set; }
		public GPIOPinDriver LED2 { get; set; }
		public GPIOPinDriver OC1 { get; set; }
		public GPIOPinDriver OC2 { get; set; }
		public GPIOPinDriver LEFT_GO { get; set; }
		public GPIOPinDriver LEFT_DIR { get; set; }
		public GPIOPinDriver RIGHT_GO { get; set; }
		public GPIOPinDriver RIGHT_DIR { get; set; }

		public RaspiRobot()
		{
			this.LED1 = new GPIOPinDriver(GPIOPinDriver.Pin.GPIO7, GPIOPinDriver.GPIODirection.Out, GPIOPinDriver.GPIOState.Low);
			this.LED2 = new GPIOPinDriver(GPIOPinDriver.Pin.GPIO8, GPIOPinDriver.GPIODirection.Out, GPIOPinDriver.GPIOState.Low);
			this.OC1 = new GPIOPinDriver(GPIOPinDriver.Pin.GPIO22, GPIOPinDriver.GPIODirection.Out, GPIOPinDriver.GPIOState.Low);
			this.OC2 = new GPIOPinDriver(GPIOPinDriver.Pin.GPIO21, GPIOPinDriver.GPIODirection.Out, GPIOPinDriver.GPIOState.Low);
			this.LEFT_GO = new GPIOPinDriver(GPIOPinDriver.Pin.GPIO17, GPIOPinDriver.GPIODirection.Out, GPIOPinDriver.GPIOState.Low);
			this.LEFT_DIR = new GPIOPinDriver(GPIOPinDriver.Pin.GPIO4, GPIOPinDriver.GPIODirection.Out, GPIOPinDriver.GPIOState.Low);
			this.RIGHT_GO = new GPIOPinDriver(GPIOPinDriver.Pin.GPIO10, GPIOPinDriver.GPIODirection.Out, GPIOPinDriver.GPIOState.Low);
			this.RIGHT_DIR = new GPIOPinDriver(GPIOPinDriver.Pin.GPIO25, GPIOPinDriver.GPIODirection.Out, GPIOPinDriver.GPIOState.Low);
		}

		public void SetMotors( int left_go, int left_dir, int right_go, int right_dir )
		{
			this.SetMotors(left_go != 0, left_dir != 0, right_go != 0, right_dir != 0);
		}
		public void SetMotors( bool left_go, bool left_dir, bool right_go, bool right_dir )
		{
			this.LEFT_GO.State = left_go  ? GPIOPinDriver.GPIOState.High : GPIOPinDriver.GPIOState.Low;
			this.LEFT_DIR.State = left_dir ? GPIOPinDriver.GPIOState.High : GPIOPinDriver.GPIOState.Low;
			this.RIGHT_GO.State = right_go ? GPIOPinDriver.GPIOState.High : GPIOPinDriver.GPIOState.Low;
			this.RIGHT_DIR.State = right_dir ? GPIOPinDriver.GPIOState.High : GPIOPinDriver.GPIOState.Low;
		}

		public void Stop()
		{
			this.SetMotors(false, false, false, false);
		}
		public void Forward(float sec = 0.0f)
		{
			this.SetMotors(true, false, true, false);
			if (sec > 0.0f)
			{
				Thread.Sleep((int)(sec * 1000.0));
				this.Stop();
			}
		}
		public void Left(float sec = 0.0f)
		{
			this.SetMotors(true, false, true, true);
			if (sec > 0.0f)
			{
				Thread.Sleep((int)(sec * 1000.0));
				this.Stop();
			}
		}
		public void Right(float sec = 0.0f)
		{
			this.SetMotors(true, true, true, false);
			if (sec > 0.0f)
			{
				Thread.Sleep((int)(sec * 1000.0));
				this.Stop();
			}
		}
		public void Reverse(float sec = 0.0f)
		{
			this.SetMotors(true, true, true, true);
			if (sec > 0.0f)
			{
				Thread.Sleep((int)(sec * 1000.0));
				this.Stop();
			}
		}
		public void Back(float sec = 0.0f)
		{
			this.Reverse(sec);
		}

		public void SetLED1( bool sw ) {
			this.LED1.State = sw ? GPIOPinDriver.GPIOState.High : GPIOPinDriver.GPIOState.Low;
		}
		public void SetLED2(bool sw)
		{
			this.LED2.State = sw ? GPIOPinDriver.GPIOState.High : GPIOPinDriver.GPIOState.Low;
		}
		public void SetOC1(bool sw)
		{
			this.OC1.State = sw ? GPIOPinDriver.GPIOState.High : GPIOPinDriver.GPIOState.Low;
		}
		public void SetOC2(bool sw)
		{
			this.OC2.State = sw ? GPIOPinDriver.GPIOState.High : GPIOPinDriver.GPIOState.Low;
		}
	}
}

でもって、F# でテストコードを書いてみます。

open System
open RaspiRobotNet
open RaspberryGPIOManager

[<EntryPoint>]
let main argv = 
    printfn "Hello RaspiRobotNet"

    let robot = new RaspiRobot()
    let mutable loop = true
    while loop do
      let key = Console.ReadKey()
      match key.KeyChar with
      | 'e' | 'q' -> loop <- false
      | 'f' -> robot.Forward(1.0f)
      | 'b' -> robot.Back(1.0f)
      | 'r' -> robot.Right(1.0f)
      | 'l' -> robot.Left(1.0f)
      | 's' -> robot.Stop()
      | '1' -> robot.SetLED1( robot.LED1.State = GPIOPinDriver.GPIOState.Low )
      | '2' -> robot.SetLED2( robot.LED2.State = GPIOPinDriver.GPIOState.Low )
      | '3' -> robot.SetOC1( robot.OC1.State = GPIOPinDriver.GPIOState.Low )
      | '4' -> robot.SetOC2( robot.OC2.State = GPIOPinDriver.GPIOState.Low )
      | _ -> ()
    0 // 整数の終了コードを返します

Tera Term で接続して、WiFi 経由で制御ができます。
F# のインストールは、以下を参考にしてください。

Raspberry Pi 2 に F# をインストールする | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/6870

これで、モータードライバーの制御は作れたので、これをゲームコントローラーで制御できるようにしていきます。

カテゴリー: C#, F#, RaspberryPi パーマリンク