Post on 11-Apr-2017
Goと電子工作とロボットたけいひでゆき @HideyukiTakei
Jun. 21, 2015 / Go Conference
自己紹介
• H/W: 回路設計、マイコン、外装設計、中国 • SW: フロントエンドJS、Android、AWS • かわいいロボットが好き
自己紹介
アジェンダ• いま趣味で作っているロボットのご紹介 • Goでメジャーな電子工作のツールGobot • Arduino と Firmata • 意外と面倒なシリアル通信でのデータやりとり • RPCの必要性とgRPC • 動くデモ! • コードの説明
趣味のロボットづくり
• 盆栽ロボットを作りたい • 亀+植物 • かわいく動かしたい • ゆくゆくは野に放ちたい • 野良ロボット
ServoMotor RS304MD Front-Right
ServoMotor RS304MD Front-Left
ServoMotor RS304MD Back-Right
ServoMotor RS304MD Back-Left
ServoMotor RS304MD Yaw
ServoMotor RS304MD Tail
USART
Eye LED * 2Solar Cell
I2C
AVR ATXMEGA32D4 PWM
Pressure Sensor
Temperature & Humidity Sensor
9 Axis Sensors (3Acc, 3Gyro,
GPS LS20031 3.0-4.2V
Energy Harvesting
構成
USART
だいたい試作はできた
• eagle: プリント基板設計ソフトウェア
• elecrow, fusion pcb: プリント基板製造サービス
• Inventor: 3DCAD
• Shapeways: 3Dプリントサービス
• AVR & GCC: 8bitマイコン(C言語で開発)
試作でよく使うもの
• ロボットを外部からコントロールしたい
• せっかくなのでGoを使おう
なにで制御しよう
Goで電子回路の定番?
いろいろ対応
Gobot & RaspberryPiGoのコード with Gobot
Raspbian
GPIO, I2C
• RaspberryPi上でGoのコードが動く • 直接GPIOやI2Cを叩くことができる!
Gobot & Arduino
Goのコード with Gobot Firmata
USB-Serial
• PCからArduinoを操作する • Arduino上にプログラムを転送しない
ArudinoとFirmata
都度ファームウェアを USB経由で書き込む
• Arduinoの場合 • 書き込んだ後はケーブル外してOK • 電源断してもファームウェアは保存されてる
ArudinoとFirmata外部から制御するためのファームウェアを あらかじめ書き込む
• Firmataの場合 • 主体はPC • PCがないと動かない • プログラムはArduinoに保存されない
FirmataのGood/Bad• Good • 通信とかコマンドとかメッセージとか 意識する必要がない
• 様々な言語から叩ける • Bad • 基本的にはプリミティブな命令しかないので、リアルタイム性が高いものには 不向き
• 単独では動かない
カスタムプロトコルの道• UART?BLE?Bluetooth? • だいたいはUARTでOKか
• マイコン側/PC側のプログラムも必要 • UARTが1つ埋まる • printfデバッグがしにくくなる
• プロトコル決めないと •めんどくさい
そこでRPC• マイコン側の関数をコールする • 複雑な操作を1つの関数にまとめる • 16x16のLEDマトリックスに「あ」と描く • コマンドサーボ複数個の同時位置指定
• 通信経路はUART • BluetoothのSPPやUSB-Serialが使える
• なにか良いRPCないか…
ロボット PC
そこで!gRPC!• シリアライズは Protocol Buffers • IDLでメッセージやRPCの構造を定義 • protocでソースコードも生成される
• 正確にはgRPC-USBSerialゲートウェイ • よし、このゲートウェイをGoで書こう! • データ形式はAVRまでProtocol Bufferで!
AVR (マイコン) gRPCサーバ(Go)
Serial
gRPC クライアント
USB
歩行デモ
5(Go)個のサーボモータを
制御しながら
5(Go)歩 あるきます
歩行のデモ
盆栽を3月頃に調達しました
が
5月に枯れてしまいました…
元気だった頃の盆栽
ロボット
Protocol BuffersをAVRで
• nanopb • http://koti.kapsi.fi/jpa/nanopb/
• 組み込み向けProtocolBufferのC実装 • 最低限の機能のみ実装 • 2-10 kB ROM, <1 kB RAMがターゲット • 今回のマイコンは32kB ROM、4kB RAM
AVR (マイコン) gRPCサーバ(Go)
Serial
gRPC クライアント
USB moveServos
moveServos
PC
robot.proto(IDL)syntax = "proto3";
package robot;
service Soth { rpc moveServos (MoveServosRequest) returns (MoveServosResponse) {} }
message MoveServosRequest { int32 servo_front_right_position = 1; int32 servo_front_left_position = 2; int32 servo_back_right_position = 3; int32 servo_back_left_position = 4; int32 servo_yaw_position = 5; }
message MoveServosResponse { }
ロボット PC
IDLのコンパイル$ protoc --go_out=. robot.proto $ prptpc --nanopb_out=. robot.proto
これで、goとcのコードが出てくる
AVR (マイコン) gRPCサーバ(Go)
Serial
gRPC クライアント
USB
robot.pb.go
moveServos
moveServos
robot.pb.h robot.pb.c
gRPCサーバtype server struct{ s *serial.Port m sync.Mutex }
func (srv *server) MoveServos(ctx context.Context, in *pb.MoveServosRequest) (*pb.MoveServosResponse, error) { srv.m.Lock() defer srv.m.Unlock() writeRobotSerial(srv.s, in) return &pb.MoveServosResponse{}, nil }
シリアル通信ライブラリは github.com/tarm/serial
gRPCサーバfunc main() { c := &serial.Config{ Name: “/dev/tty.usbserial-DJ004Q2V”, Baud: 115200} serial, err := serial.OpenPort(c)
if err != nil { log.Fatal(err) }
lis, err := net.Listen("tcp", port) if err != nil { log.Fatalf("failed to listen: %v", err) } s := grpc.NewServer() pb.RegisterSothServer(s, &server{s: serial}) s.Serve(lis) }
シリアル通信用初期化
gRPCサーバ起動
gRPCクライアントc := pb.NewSothClient(conn)
r, err := c.MoveServos(context.Background(), &pb.MoveServosRequest{ ServoFrontRightPosition: 700, ServoFrontLeftPosition: 900, ServoBackRightPosition: 900, ServoBackLeftPosition: 700, ServoYawPosition: 900 })
Goで楽しいロボットを創りましょう!
codelunch.fmというポッドキャストにも 出演しました。聴いてみてください!
宣伝
Android、Ruby/Node.jsが 得意なエンジニア大募集! (もちろんGoも)