※ 以下で行っていることは、PLEN:bit の基本的な使い方とは外れていると思いますので、そのあたり理解した上でお読みください。
micro:bit と、PLEN:bitの通信方法が分かったので、同じ感じで外部から信号を入れれば、他の機器からでもコントロール可能なはず!M5Stackからとか!
でも、micro:bitの端子は、ソケットに全部隠れちゃうので、ここに直接ピンをつなぐのは難しそう。
PLEN:bit の前面にのSDA/SCL等のホールにソケット付ければ行けそうではありますが、買ったばっかりなので、本体を改造するのは気が引ける…。
何かいい手は無いかと、いろいろ探してみると、micro:bit 風のユニバーサル基板を発見しました!
Micro:bit風なユニバ基板 [UP52x42BIT]
http://www.aitendo.com/product/17284
これ使えば、PLEN:bit本体に手を入れずに、外部からの信号入力できそうです!
1個120円ですが、こちらのサイトの通販最低価格は1000円なのでお気を付けを。
大きさ同じ!(実際は、微妙に横幅が長い。ほんのちょっとだけ。)
ほんのわずかですが横サイズが長いみたいで、micro:bit よりもキツキツな感じでした。少々グイッと押し込む感じで差し込みました。問題なしです!
通信処理のソースによれば、目玉LEDはデジタル16番ピン、サーボはI2Cのアドレス0x6Aでした。
ということで、M5Stackと接続。M5Stack GPIO2番ピンと、micro:bit 16番ピン、SDA / SCL をそれぞれ、あとGNDの4本を接続。
まずはお試しな感じなので、テストワイヤで接続しました。
M5Stack側のプログラムを Ardino で作成します。
目玉LEDの制御はデジタルのON/OFF。
const int LED_PIN = 2; pinMode(LED_PIN,OUTPUT); digitalWrite( LED_PIN, HIGH ); //消灯 digitalWrite( LED_PIN, LOW ); //点灯
これだけ。
後は、I2C経由のサーボコントロールです。サーボコントローラのアドレス0x6Aへの書き込み処理を作成。データは、アドレスと値を連続で書けばOK。
void write8(int addr, int val){
Wire.beginTransmission(0x6A);
Wire.write(addr);
Wire.write(val);
}
元ソースと同じ内容で初期化処理を作成。
void secretIncantation() {
write8(0xFE, 0x85);//PRE_SCALE
write8(0xFA, 0x00);//ALL_LED_ON_L
write8(0xFB, 0x00);//ALL_LED_ON_H
write8(0xFC, 0x66);//ALL_LED_OFF_L
write8(0xFD, 0x00);//ALL_LED_OFF_H
write8(0x00, 0x01);
servoInitialSet();
}
servoInitialSet は、8個のサーボの初期値を設定。初期値は元ソースを参考に。
void servoInitialSet() {
int servoSetInit[] = {1000, 630, 300, 600, 240, 600, 1000, 720};
for(int i = 0;i < 8;i++){
servoWrite(i, servoSetInit[i] / 10);
}
}
servoWriteは、サーボを指定角度に動かす関数です。
void servoWrite(int num, int degrees) {
int servoNum = 0x08;
bool highByte = false;
int pwmVal = degrees * 100 * 226 / 10000;
pwmVal = pwmVal + 0x66;
if (pwmVal > 0xFF) {
highByte = true;
}
write8(servoNum + num * 4, pwmVal);
if (highByte) {
write8(servoNum + num * 4 + 1, 0x01);
} else {
write8(servoNum + num * 4 + 1, 0x00);
}
}
サーボのアドレスは、0x08 + サーボ番号 * 4。
サーボに与える値は、角度 * 100 * 226 / 10000 で 計算します。0~180 → 0~406( 0x00~0x196) という感じです。
値が計算できたら、下2桁を サーボアドレスに書き込み、上1桁(今回の場合は0か1だけですね)を(サーボアドレス+1)のアドレスに書き込み。
これで、サーボ動かすのに必要な関数は揃いました。
左手の前後動作用のサーボ(サーボ番号0番)を動かしてみます。前方(0度)と元の位置(100度)に回転。
servoWrite(0,0); servoWrite(0,100);
これを、A/Bボタン押したタイミングで動作、ついでにLEDも光るようにしてみました。あと、M5StackのLCDにも状況を表示。
プログラム全体は以下の通り。
#include <M5Stack.h>
const int LED_PIN = 2;
void setup(){
M5.begin();
Wire.begin();
pinMode(LED_PIN,OUTPUT);
digitalWrite( LED_PIN, HIGH );
M5.Lcd.fillScreen(TFT_BLACK);
M5.Lcd.setTextColor(TFT_WHITE);
M5.Lcd.setTextSize(4);
M5.Lcd.setCursor(0, 0);
M5.Lcd.println("PLEN:M5Stack");
delay( 1000 );
secretIncantation();
}
void loop(){
M5.update();
if (M5.BtnA.wasReleased()){
M5.Lcd.fillScreen(TFT_BLACK);
M5.Lcd.setTextColor(TFT_WHITE);
M5.Lcd.setTextSize(4);
M5.Lcd.setCursor(0, 0);
M5.Lcd.println("PLEN:M5Stack");
M5.Lcd.setCursor(0, 100);
M5.Lcd.println("UP!");
digitalWrite( LED_PIN, LOW );
servoWrite(0,0);
delay(1000);
digitalWrite( LED_PIN, HIGH );
}
if (M5.BtnB.wasReleased()){
M5.Lcd.fillScreen(TFT_BLACK);
M5.Lcd.setTextColor(TFT_WHITE);
M5.Lcd.setTextSize(4);
M5.Lcd.setCursor(0, 0);
M5.Lcd.println("PLEN:M5Stack");
M5.Lcd.setCursor(0, 100);
M5.Lcd.println("DOWN!");
digitalWrite( LED_PIN, LOW );
servoWrite(0,100);
delay(1000);
digitalWrite( LED_PIN, HIGH );
}
if (M5.BtnC.wasReleased()){
servoInitialSet();
}
delay(10);
}
void write8(int addr, int val){
Wire.beginTransmission(0x6A);
Wire.write(addr);
Wire.write(val);
//0: 成功
//1: 送信バッファ溢れ
//2: アドレス送信時にNACKを受信
//3: データ送信時にNACKを受信
//4: その他エラー
Serial.println(Wire.endTransmission());
}
void secretIncantation() {
Serial.println("secretIncantation");
write8(0xFE, 0x85);//PRE_SCALE
write8(0xFA, 0x00);//ALL_LED_ON_L
write8(0xFB, 0x00);//ALL_LED_ON_H
write8(0xFC, 0x66);//ALL_LED_OFF_L
write8(0xFD, 0x00);//ALL_LED_OFF_H
write8(0x00, 0x01);
servoInitialSet();
}
void servoWrite(int num, int degrees) {
Serial.printf("ServoWrite:%d,%d\n",num,degrees);
int servoNum = 0x08;
bool highByte = false;
int pwmVal = degrees * 100 * 226 / 10000;
pwmVal = pwmVal + 0x66;
if (pwmVal > 0xFF) {
highByte = true;
}
write8(servoNum + num * 4, pwmVal);
if (highByte) {
write8(servoNum + num * 4 + 1, 0x01);
} else {
write8(servoNum + num * 4 + 1, 0x00);
}
}
void servoInitialSet() {
int servoSetInit[] = {1000, 630, 300, 600, 240, 600, 1000, 720};
for(int i = 0;i < 8;i++){
servoWrite(i, servoSetInit[i] / 10);
}
}
LCD表示あたりが冗長ですが、まあ、お試しなのでこれで…。
I2C接続してPLEN:bit本体のサーボコントローラを制御 & デジタル入力で目玉LEDを制御! pic.twitter.com/vqygE1m8la
— Nochi (@shikarunochi) 2019年5月28日
動いたー。






