前回から随分間があきましたが、今回のガラクタは「ESP8266 + DRV8830 + タミヤダブルギアボックス で スマホリモコンカー」ということで、
前回の「牛乳パック四脚」 に続いて 100円ロボット系で行ってみたいと思います。ただし、スマホからコントロールできる仕組みとしたいので、その部分はどうしても高級?な仕組みとなってしまうわけですが、それでもできるだけ安価に実現するということで、まずスマホからコントロールできるようにするためにESP8266を使います。Arduinoよりも安価でしかも無線LANでつながってしまうIoTの申し子ともいうべきモジュールです。今回は手持ちのスイッチサイエンスさんのESPDeveloperという2千円以上するものを使いましたが、ESP8266なら700円くらいから選択肢があると思います。そして、モータドライバにはDRV8830を使います。I2C接続で使いやすく、秋月電子で170円くらいで入手できます。あとは左右差動式にするためにタミヤの楽しい工作シリーズのダブルギアボックスを使います。ここまでで2~3千円くらいでしょうか。
さて、残りのパーツは100円ロボットらしさを出すため?に例によってamazonの段ボール箱の残骸を使いますが、今回はタイヤの部分にもう一つ、ペットボトルの底の部分を切り取って使ってみました。ちなみにこのペットボトルは我が家のハウスワイン?として常飲されているペットボトル入り赤ワインのもので、ペットボトルのごみの日の前になると大量にたまっていて入手には困りません。
まずはペットボトルの底をカッターで切り落とします。
このペットボトルの底を車輪として使おうと思ったのですが、切り口側がポヨンポヨンでいまいち強度がありません。そこで、段ボールで同径の円盤を切り出して、ペット底の内側にはめ込んで強度を出すことにします。
次に、みんな大好き「タミヤの楽しい工作シリーズ」の「ダブルギアボックス」を組み立てます。
次に電装系ですが、今回はブレッドボード上に構成しました。
ESP8266側の3.3Vとモータ駆動側を5V(4.8V)にして、間にI2Cレベルコンバータを入れて構成しましたが、はじめ、途中のジャンパの接触が悪く、うまく動作しなかったため、ロジアナでI2Cのラインを追いかけて調べる羽目になりました。
ジャンパの接触不良に気づくまで結構時間がかかったんですが、どうにか動くようになりました。
で、秋月電子で買った単三×4本のバッテリボックス(100円くらいかな?)にエネループを4本入れて、4.8Vを電源として供給、本体ベース(シャーシ?)はやっぱりアマゾンの段ボール、一応ヘリをまげて強度を上げています。また、下写真ではわかりませんが、後部底面に部品棚に転がっていたタミヤの楽しい工作シリーズのボールキャスタを両面テープで張り付けています。
そして、今回、スマホからのリモートコントロールには、
尾道さん(ROBOMICさん)が公開してくれているRCWController というのを使わせてもらいました。いや~、尾道さんにはROBO ZEROで遊んでいた頃から、いつも、お世話になっております。m(__)m 。
iPhone の RCWController で 動かしてみた様子です。
VIDEO
ちょっと、ペットボトルのタイヤがスリップ気味ですが、なんとか動かせました。
参考までにプログラムを載せておきます。ハードの資料載せてないから意味ないとは思いますが・・・
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Wire.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
const char ssid[] = "ESP8266";
const char pass[] = "password";
#define DEBUG Serial
#define ON_BOARD_LED 14
#define DRV8830_A1_A0_0_0 0b1100000
#define DRV8830_A1_A0_0_open 0b1100001
#define DRV8830_A1_A0_0_1 0b1100010
#define DRV8830_A1_A0_open_0 0b1100011
#define DRV8830_A1_A0_open_open 0b1100100
#define DRV8830_A1_A0_open_1 0b1100101
#define DRV8830_A1_A0_1_0 0b1100110
#define DRV8830_A1_A0_1_open 0b1100111
#define DRV8830_A1_A0_1_1 0b110100
const int motorL = DRV8830_A1_A0_open_open;
const int motorR = DRV8830_A1_A0_open_1;
const int PACKET_SIZE = 256;
WiFiUDP udp;
unsigned int localPort = 10000;
char packetBuffer[PACKET_SIZE];
int status = WL_IDLE_STATUS;
int prev_X = 128, prev_Y = 128;
bool isChange = false;
int ledState = LOW;
int speedL = 0, speedR = 0;
bool isDebugOut = false;
int DRV8830_setSpeed(int DRV8830_Address, int speed)
{
byte direction;
byte power;
if (speed == 0)
{
direction = 0x00;
}
else if (speed < 0)
{
direction = 0b10;
speed = -1 * speed;
}
else
{
direction = 0b01;
}
power = (byte)(speed & 0xff);
if (power > 0x3f)
{
power = 0x3f;
}
speed = power;
power = (power << 2) | direction;
Wire.beginTransmission(DRV8830_Address);
Wire.write(0x00);
Wire.write(power);
Wire.endTransmission();
if (direction = 0b10)
{
speed = -1 * speed;
}
return(speed);
}
void DRV8830_brake(int DRV8830_Addres)
{
Wire.beginTransmission(DRV8830_Addres);
Wire.write(0x00);
Wire.write(0x03);
Wire.endTransmission();
}
int DRV8830_getSpeed(int DRV8830_Addres)
{
int speed = 0;
byte data;
Wire.beginTransmission(DRV8830_Addres);
Wire.write(0x00);
Wire.endTransmission();
Wire.requestFrom((int)DRV8830_Addres, 1);
while (Wire.available() == 0);
data = Wire.read();
if ((data & 0x03) == 0b10)
{
speed = -1 * (data >> 2);
}
else
{
speed = data >> 2;
}
return speed;
}
void setup()
{
DEBUG.begin(115200);
while (!DEBUG)
{
;
}
DEBUG.println("program start..");
Wire.begin();
DRV8830_setSpeed(motorL, 0);
DRV8830_setSpeed(motorR, 0);
WiFi.softAP(ssid, pass);
IPAddress myIP = WiFi.softAPIP();
DEBUG.print("AP IP address: ");
DEBUG.println(myIP);
DEBUG.println("Starting UDP");
udp.begin(localPort);
DEBUG.print("Local port: ");
DEBUG.println(udp.localPort());
}
void loop()
{
int rlen, val_X = 0, val_Y = 128;
while (true)
{
rlen = udp.parsePacket();
if (rlen < 10) {
delay(1);
continue;
}
udp.read(packetBuffer, (rlen > PACKET_SIZE) ? PACKET_SIZE : rlen);
val_X = packetBuffer[2];
if (val_X != prev_X)
{
prev_X = val_X;
isChange = true;
isDebugOut = true;
}
val_Y = packetBuffer[3];
if (val_Y != prev_Y)
{
prev_Y = val_Y;
isChange = true;
isDebugOut = true;
}
if (isChange) {
int speed = (val_Y - 128);
int direction = (val_X - 128);
speedL = speed + direction;
speedR = speed - direction;
DRV8830_setSpeed(motorL, speedL);
DRV8830_setSpeed(motorR, speedR);
isChange = false;
}
delay(1);
if (isDebugOut) {
DEBUG.print(val_X);
DEBUG.print(" , ");
DEBUG.print(val_Y);
DEBUG.print(" : ");
DEBUG.print(speedL);
DEBUG.print(" , ");
DEBUG.println(speedR);
isDebugOut = false;
}
}
}