LEGOによる玉ころがし(ピタゴラ的)のGBC用のコントローラを自作してみました。こういったLEGO装置を作るにはモータの制御を細かくしたいのですが、既存のモノはなかなかないので作ってみました。
詳しくはProtoPediaにアップしています。詳しくはProtoPediaにて。。
ものづくり伝道師のブログ
LEGOによる玉ころがし(ピタゴラ的)のGBC用のコントローラを自作してみました。こういったLEGO装置を作るにはモータの制御を細かくしたいのですが、既存のモノはなかなかないので作ってみました。
詳しくはProtoPediaにアップしています。詳しくはProtoPediaにて。。
LEGO GBCは、レゴのボールを如何に運ぶかに命を懸けるものでこういったところでいくつか紹介されている。ありとあらゆるブロックを使っていろいろな仕掛けをつくるのが醍醐味ではあるのだが、ここではあえて使用するブロックの縛りをつけて、教育向けのLEGO SPIKE PRIMEというセットの部品のみ、つまり、このセットを持っている人であれば組めるものを作ってみた。
仕事柄あちこちでこういったものを人に見せる機会があることから、以前からこのセットのみでGBCを組んでやっていて、動画もアップしていて一定の人には見ていただいている。
V1の動画
ところが、いろんなところで実演していると、見てお分かりの通り、土台が無いので結構狂いが生じてトラブルに見舞われることが多かったので、作り直してV2としてみた。また、作り方のマニュアルが欲しいとか、プログラムを見せて欲しいなどの要望もチラホラあったので、これについても公開することにした。
今回のV2は基本的にはV1と同じなのだが、リフトの部分の角度を調整して、狂いが出ないようにしてある。レゴはポッチと呼ばれるブロックの大きさの単位でしか組めないこともあり、ナナメをきっちりつくるのにチョッとした計算が必要となってくる。簡単に言えば、三平方の定理で3辺が整数となる組み合わせでないと直角が出ないことになるので、おのずとパターンは限られてくる。3対4対5の三角形が直角になることはよく知られているが、これと同じ原理で13対19対23も多少の誤差はあるが直角になる。また、ブロックではなくプレートと呼ばれる板状のブロックもあり、これは厚みが1/3となっていて、これを使えば、12.65対18対22といったパターンも使える(12.65は12ポッチとプレート2枚で表現できるため)。 今回のものは角度を考えて、8対10対12の組み合わせでリフトを組んでいる。
GBCで使用するボールは、GBC規格によるとLEGO純正のサッカーボールやバスケットボールが使われることになっているが、このボールの日本での入手性がかなり厳しく、大量に手に入れることが困難であるため、非常に残念ではあるがアマゾンとかを探して非純正のボールを使うことになる。今回もカラーのボール100個を4〜5000円くらいで手に入れたモノを使用している(残念ながら2024/8時点では円安の影響か8000円を超えている)。
100均やビーズショップで14mmの穴なしビーズがあれば代用可であるが、穴ありでも背に腹は代えられないので、少々引っかかろうが使えないことはない。大事なのは大きさで、よくあるビー玉は16mm前後のモノが多く、1ポッチ8mmであるので確実に引っかかる。GBCでは、基本的に2ポッチの隙間を転がすことが多いため、日本で最も入手性のよいビー玉が使えないのはイタい。ただ、ビー玉をはじめとするガラス玉は純正のボールよりもかなり重いので、挙動がかなり変わる。また、これまた日本では非常に入手性のよいパチンコ玉は小さく重いのでかなり不適で残念!
今回製作したGBC LOOPは、GBC規格を意識して作られているが、プラスアルファ要素としてボールの色を見わけて転がるレーンを切り替える機能を盛り込んである。
本体は、ホッパ、ソータ、リフトの3つの部分から成り立っている。
ホッパはGBC規格に開口の高さや大きさを合わせてある。GBC規格では、1度に30個を送り込むバッチ処理ができることを想定しているが、このホッパでは厳しいと思われる。せいぜい20個くらいにしておくのが吉。ソータへ続くスロープには1個ずつ送り出す機構を用意し、ついでにボールの色をチェックしている。
チェックした色に基づいてレーンをスライドさせている。SPIKEセットには白のブロックがないので、黄色のブロックで白色ボールのレーンとしている。レーンチェンジのプログラムでは、相対角度による制御を行っている。12歯ギアでラックギアを動かしているが、端から端まで動かすには1回転以上の回転が必要となるので、絶対位置による制御はできない。詳しくは後述のプログラムを参考のこと。
また、初期位置が重要で、モータ絶対角度0度のときに白(黄)レーンとなるようにレーンをセットする必要がある。プログラム開始時に絶対位置を0度に戻す処理が入っているが、赤レーンが選択された状態では絶対0度でリセットできないので、プログラム開始時に赤レーンになっているとトラブルとなる。青や緑ではリセット可能なので、とにかく赤でプログラムを止めないことが大事だろう。
リフトはGBCの醍醐味ではあるが、SPIKEプライムの1セットで製作する必要から単純な押し上げスロープになっている。当初、ギアによる回転をさせていたのだが、トラブったときに無理矢理に回転し続けるため、ブロックへのダメージが大きかったのでプーリによる方式に変更した。これなら、トラブっても空回りするだけなのでブロックへのダメージはほぼゼロである。その分非力なので、チョッとでも引っかかると押し上げられない事態となることもある。
リフトからホッパへ続くブリッジ部分は余ったパーツを使用してつくってあるので、多少強引な感じになっているのは否めない。作り方マニュアルには掲載されていないホースの使い方は写真を参考のこと。作り方マニュアルを作成したCAD(LEGO Studio)では、このホースや、輪ゴムの表現ができないので、写真を参考にするのがよいだろう。
日本語版プログラム |
English Version |
海外の人からの問い合わせが結構あるというか、日本国内からの問い合わせはほぼ無いので、英語バージョンを載せておく。実は、こういった説明文は自動翻訳で結構いろんな言語に翻訳して見ている人がいるみたいなんだけど、画像になっているものは翻訳できないらしく、とりあえず英語ならどうにかなるんじゃないかということで英語版を載せておく。
以下に、組立マニュアルのPDFを置いておくので参考のこと。無償で個人的に使ってもらう分には構わないが、時々、こういうのを勝手に売ったり、商売に使う人がいるので、そういうことだけはやめてもらいたい。
組み立てマニュアル |
以下に紹介動画を貼っておく。組み立てマニュアルでは分からない部分などを確認いただけたらと思う。
V2(今回)の動画
これを見て、自分も作ってみたいと思う人が増えて、世の中にいろいろな作品が出てくることを願っている。GBCをやるには、何よりもリフトを作ることから始めないと何にもできないので、まずは作ってみてボールを位置エネルギーから解放してあげることが大切!上に上げてしまえば、あとは落ちるだけなので、創意工夫をして楽しく転がしてね!
リアルRPGシステムとは?
ロールプレイングゲーム中では不思議な現象に出会うことも多いでしょう。でも、これは所詮は画面の中の話。元々誰かが作ったプログラムなんだから、そんなんできて当たり前!と思っていたんじゃつまらない!リアルな世界でもRPGに見られる現象を再現してみようということで、RPGに見られるよくある様々なアイテムを、ギミックをも含めてリアルで実現してみようというプロジェクトを始めることにしました。
まずは第1弾!(つづきはあるのか???)
ゲーム画面は「ドラゴンクエストXI(スクエアエニックス)」と「ゼルダの伝説TOK(任天堂)」より |
アイテム#1「宝箱」
どんなRPGでも必ず出てくる宝箱。これってさー、結構いろいろなイベントをクリアして条件揃わないと開かないモノもあったりして、そこんとこってどうやって判別して開けてるのかファンタジーw ということで、リモートで開閉する宝箱を作ってみた。
アイテム#2 魔法のリング
せっかく宝箱を作ったんだから、それを開けるための何かを用意しないといけません!先日、10数年ぶりに大阪の日本橋の共立さんに行く機会があったので、なにげに店内を散策していると・・・
これはっ!!10年くらい前から欲しかったNFCの指輪ではないか!昔はめっちゃ高くて手に入りにくかった覚えしかなかったんだが、数百円とはいい時代になったもんだということで、3種類の大きさすべてをゲット!
これをリーダーで読んでUID判別して宝箱にBLEで送ればいいだけじゃんということで、魔法のリング読み取りシステムはサクッと作る。
認識したかがわからないと困るので、AtomS3の裏にスピーカーを直差し。とりあえず、3種類の指輪の区別はピピピの回数でということに。
ここで問題なのが、どうやって読み取らせるか???RFID2ユニットに指輪を近づけたらいいじゃん!なんて考えているのは素人で、あくまでもリアルRPGシステムなので、ここは何か意味のあるモノにかざすみたいなのが欲しい。ということで、RPGではおなじみ?の石版(らしきもの?)をフォトショで作成。これが一番手間がかかったかも・・・
ということで、動作状況を動画で撮ったのでどうぞ!
ついでに「M5Stack Japan Creativity Contest 2023」に締め切り間際の滑り込み応募しました。
ゼミ生にセンサ情報を収集するのにラズパイでIoT化させていて学生がハマっていたので、実際に動作させる方法を調べた結果を備忘録として残しておく。 今回のターゲットはこのボード(Grove Base Hat for Raspberry Pi for Zero)
(追記2023/10/24) なお、ラズパイOSのバージョンは11(bullseye)以降で、古いOSは当てはまらないので注意
(追記2023/11/10) 現在売られているのはボード上のチップ(MM32)とアドレス(0x08)が変更されているバージョンなので注意が必要
LEGO MindStorms は、プロトタイピングや教育用にも非常によいツールであり、20年以上前のRIS時代から利用しているが、2022年6月にやっと日本でも発売になったRobot Inventorキットでは、以前にも増してセンサーやモーターのコネクタが独自形状で、自作のセンサーやアクチュエータを接続することは、かなりハードルが高いものになっている。
このキットではPythonやビジュアルプログラミングツールで動作をプログラミングできるのだが、これによって、プログラムを実行するHubと呼ばれるメインユニット同士のHub間通信ができるようになっており、BLEによるシグナル名とデータの組み合わせによる無線通信が可能になっている。
これをESP32などのBluetooth内蔵マイコンで送受信できれば、いろいろ夢が広がりそうということで、いろいろ探してみたところ、以下のサイトで解析した結果が公開されていた。LEGO MINDSTORMS Robot Inventor's Hub to Hub Communication Hacks
実のところ、このサイトの情報には誤りがあって(もしかしたら、この解析のあとにLEGO社の仕様が変わったのかもしれないが)、LEGO社の製造者IDのエンディアンが逆になっていて、この情報のままでは通信できなかった。それに気がつくまでは、結構七転八倒したわけだが、最終的にはBLEパケットモニタでモニタリングしてやっと気がついたということで、めでたく通信が可能となったわけである。
なんちゅうことはない、Advertisementデータをブロードキャストして、製造者IDとシグナル名が一致するデータを勝手に受信するだけという仕組みである。そういう意味では、送受信の確実性はないのが玉に瑕なのだが、お手軽さには勝てないので、早速実装することに。以下に、ESP32のM5StickCPlusやM5StampC3で実行確認済みのライブラリを貼っておくので、このアイデアというかソースコードとかは、自由に使ってもらって構わない。
まさかとは思うが、金を取っていろいろやるものに組み込む人はいないとは思っているのだが、勝手にLEGO社の製造者IDを使っているので、その辺はかなりグレーである。その辺のトラブルには巻き込まれたくないので、使用は各自の目の届く範囲に収めておくこと。
今回は調子に乗って、作品を紹介する動画まで作ってみた。参考までに貼っておく。
みなさんが、これで一歩踏み込んだLEGO MindStormsライフを送れることを祈る!
コロナ禍なのでCO2センサの情報をLEGOに送って何かおもろいからくり作りたいなぁ・・・・
// LEGO Hub2Hub Communication Emulator for ESP32
// Copyright (C) 2022 Kikyoya (Karakuri Studio).
//
// Tested M5StickCPlus, M5StampC3
//
/* 使用法(usage)
Setup()
void initHub2Hub(String dev="Hub2Hub LEGO"); dev:デバイス名(省略可)
loop()
Sending: Advertising to LEGO HUB
void sendHub2HubData(String key,String data,int seq=H2H_AUTOSEQ,int period_ms=300);
key & dataは必須、seqとperiod_msは省略可
LEGOではkeyはシグナル名と表記されている。日本語を使う場合UTF-8で記述
dataは22バイトまで(NULL文字入れて23バイト)
Seqは、送るデータが変わるたびに違う値に更新。省略またはH2H_AUTOSEQで自動更新
period_msは、データ送信する期間。この間複数回にわたって送信する
Recieving: Receive HUB to HUB data
受信パケットをスキャンしてKeyに一致するものがあるかどうか判別
bool scanHub2Hub(String key);
受信したデータを返す
String getHub2HubData();
受信した文字列を返す、受信なしの場合は””が返る
*/
#include <BLEDevice.h> // Bluetooth Low Energy
#include <esp_rom_crc.h> // CRC32 Lib
#define H2H_AUTOSEQ -1
const uint16_t ManuID = 0x0397; // Manufacturer ID(LEGO)
// key string to CRC32(little endian)
uint32_t calCRC(String key){
return esp_rom_crc32_le(0,(uint8_t*)key.c_str(), key.length());
}
#pragma pack(1)
union aPacket{
char aData[32];
struct {
byte len;
byte adtype;
uint16_t manuid;
byte seq;
uint32_t key;
char str[23];
};
aPacket(String k,String d,byte s){
len = d.length()+8;
adtype = 0xff;
manuid = ManuID; // LEGO 0x0397
seq = s;
key = calCRC(k);
strcpy(str,d.c_str());
};
};
#pragma pack()
void sendHub2HubData(String key,String data,int seq=H2H_AUTOSEQ,int period_ms=300)
{
static byte _seq=1;
if(seq==H2H_AUTOSEQ) seq=_seq++; // 引数なし(=H2H_AUTOSEQ)でseqは自動更新
BLEAdvertising *pAdv = BLEDevice::getAdvertising(); // get adv. object
BLEAdvertisementData oAdvData = BLEAdvertisementData(); // get Adv Data
data.remove(22); // limited 22bytes(23文字以降は削除)
aPacket ad = aPacket(key,data,seq); // Key & data
pAdv->setAdvertisementType(ADV_TYPE_SCAN_IND);
oAdvData.addData(ad.aData);
// for(int i=0;i<32;i++) Serial.printf("%02x ",ad.aData[i]); // for Debug
pAdv->setAdvertisementData(oAdvData);
pAdv->start(); // Start Advertising
delay(period_ms);
pAdv->stop(); // stop Advertising
}
bool bRec=false;
uint32_t KeyCRC;
String Hub2HubStr;
// Scan call back object
class Hub2HubCB: public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice dev){
if(dev.haveManufacturerData()){ // data available
static int r_seq = -1;
std::string data = dev.getManufacturerData();
int manu_id = data[1] << 8 | data[0];
int seq = data[2];
uint32_t *hash = (uint32_t*)&(data[3]); // LE
if((manu_id==ManuID) // check ManuID & Key
&&(KeyCRC==*hash)
&&(seq!=r_seq)){ // check seq no
Hub2HubStr=String((char*)&data[7]);
r_seq=seq;
bRec=true;
}
dev.getScan()->stop(); // abort scanning
}
}
};
// scan Hub to Hub Packet
bool scanHub2Hub(String k)
{
KeyCRC=calCRC(k);
bRec=false;
BLEDevice::getScan()->start(1);
return bRec;
}
// get Hub to Hub Data
String getHub2HubData()
{
if(bRec){
bRec=false;
return Hub2HubStr;
}
return "";
}
// init Hub to Hub Lib
void initHub2Hub(String dev="Hub2Hub LEGO")
{
BLEDevice::init(dev.c_str()); // initialize device
// set BLE Scan Callback(コールバック登録)
BLEDevice::getScan()->setAdvertisedDeviceCallbacks(new Hub2HubCB());
}
ゼミでは、様々な形でラズパイを使用することがあるが、それぞれの設定がまちまちで引き継ぎなどに苦労している。そこで、統一したやり方で設定するために、標準の設定をメモとして残しておくことにした。
ゼミで使用しているラズパイはこれだけの種類がある。
3B、4B、ZW、AIY Voice Kit、AIY Vision Kit
AIYシリーズのOSはGoogleさんからDLしたものを使用するとして、ドノーマルなラズパイは基本的に同様の設定をすればSDを差し替えて使用できそうなので、後々の管理が楽になると思われる。もちろん、AIYシリーズもSDを作成した後の設定は同じように行うこととする。
また、設定に先立ち、USB電源、マウスやキーボード、HDMIディスプレイ、必要に応じてUSBやHDMIの変換コネクタは必要なので、書いていないからいらないというわけではない。
ラズパイは、確実にシャットダウンして電源が切れる状態にしないと、むやみに電源を切ることはできない。ラズパイ上の緑色の ACT LEDは、デフォルトでは SDカードへのアクセス時に点滅するが、それをハートビート点滅に変更することで確認しやすくする。
下記の設定をする事で、緑色の ACT LEDの動作がハートビート動作になり 1秒程度の一定間隔で点滅動作をする。シャットダウンしてラズパイの CPUの動作が停止するとハートビート動作も停止するので緑色の ACT LEDは点灯したままとなる。これによって CPUの動作の停止を確認出来るのでコンセントからの給電をオフにできる
$ sudo nano /boot/config.txt
で /boot/config.txtに下記を追加して再起動
dtparam=act_led_trigger=heartbeat
ちなみにシャットダウンしたあとにGPIO3をGNDに接続すると起動する。
秋月で売っているHDMIモニター(↓こんなやつ)に対応させるためには、解像度を調整しないといけないので、以下の設定を必要に応じて実行する。
$ sudo nano /boot/config.txt
で /boot/config.txtに下記を編集して再起動
hdmi_group=2
#hdmi_mode=85 #1920x1080 for Full HD Monitor 通常はこれ
hdmi_mode=81 #1366x768 for Mini HDMI Monitor
マウスやキーボードはおろか、画面も無いようなラズパイでシャットダウンのためだけにリモート接続してシャットダウンするのは非常に面倒である。そこで、シャットダウン用のスイッチをつけて長押しによるシャットダウンを実現させる。
さて、スイッチをつけるにしてもどこにつけるかが問題で、ネットで検索するといろんなGPIOにつけている例を見かけるのだが、ここではGPIO23につけることにする。
実は、このG23はAIYシリーズの2機種とも(↓)上についているボタンに接続されており、最初からスイッチが付いているので都合がよい。
#!/usr/bin/python # coding:utf-8 # import time import RPi.GPIO as GPIO import os GPIO.setmode(GPIO.BCM) #GPIO23pinを入力モードとし、pull up設定とします GPIO.setup(23,GPIO.IN,pull_up_down=GPIO.PUD_UP) while True: GPIO.wait_for_edge(23, GPIO.FALLING) sw_counter = 0 while True: sw_status = GPIO.input(23) if sw_status == 0: sw_counter = sw_counter + 1 if sw_counter >= 100: os.system("sudo shutdown -h now") break else: break time.sleep(0.01)
[Unit] Description=Shutdown raspberry pi by GPIO button input Wants=network.target [Service] ExecStart=/home/pi/shutdownbutton.py Restart=on-failure RestartSec=10s [Install] WantedBy=multi-user.target
これでとりあえず最低限の設定はできたことにする。
次はLAMPにするための設定が待っている。つづく・・・
LEGOによる玉ころがし(ピタゴラ的)のGBC用のコントローラを自作してみました。こういったLEGO装置を作るにはモータの制御を細かくしたいのですが、既存のモノはなかなかないので作ってみました。 詳しくは ProtoPedia にアップしています。詳しくはProtoPed...