M5STACK BugC
2026.07.04

メルカリで購入した電子工作用パーツに、M5STACK BugC が含まれていたので遊んでみました

発売当時は、M5StickC別売りで本体価格1892円でした。
BugC
BugCは、M5StickCと互換性のあるプログラマブルロボットベースです。
ベース基板には、4つのモーターとLEDを制御するSTM32F030F4マイクロコントローラが搭載されており、
I2Cプロトコル(0x38)を通じて制御します。
基板裏側には16340バッテリーホルダーが付いています。
・リモートコントロール
・プログラマブル
・4wayモータードライバー
・4 x ギアードモーター
・2 x RGB LED
・シンプルでコンパクトなデザイン
・バッテリーホルダー搭載
・全方向への柔軟な動作が可能
・モーターの仕様
・定格電圧:DC3.7V
・定格回転数:15000~2000rpm
・定格電流:50mA
・失速電流: 70mA
・絶縁抵抗: 10MΩ
バッテリーの充電は、M5StickCを接続してUSBによる給電を行います

後継機種のBUGC2は、StickC Plus2 同梱で、SWITCH SCIENCE にて 9856円で販売されています。
●Pinouts

基板にはM5StickCに合わせて8ピンヘッダーがあり、右側のピンがGNDです。

BugCは、通常M5StickCを被せて使用しますが、I2C端子を持つマイコンであれば制御可能です。
〇Seeed Studio XIAO ESP32S3
うぷ主はM5ライブラリのような移植性の低いコードは避けています。
ここでは、XIAO ESP32-S3 を使いました。


BugCの制御基板です。M5StickCに合わせた8ピンヘッダーがあり、左側筐体先頭部分にLEDが2つあります。

まずはユニバーサル基板裏側に8ピン・メスソケット、その右に8ピンヘッダーをはんだ付けして、この2つのパーツの各ピンを平行にはんだで連結しています。

マイコンとヘッダーピンはジャンプワイヤーで繋げています。
空中に浮いているのは3.7V、16340リチウムイオン電池を5Vに昇圧するモジュールです。
| BugC | | ESP32S3 |
| GND | -------------- | GND |
| xxxxxx | | |
| SCL | -------------- | SCL |
| xxxxxx | | |
| SDA | -------------- | SDA |
| BAT | -- 3.7V→5V -- | 5V |
| 3.3V | -------------- | 3.3V |
| xxxxxx | | |

BugCにマイコン基板を挿した様子です
●搭載リチウムイオン電池16340(3.7V)の充電

BugCには、16340バッテリー(750mAh)1個が同梱されています

リチウムイオン電池充電モジュールをBugC基板のGND,BAT端子に繋いで充電します。
充電中は電源スイッチをオンにします。
●BugCが動く仕組み
M5Stackカフェ

BugCには上の写真のように4つの小さなモーターが少し外側に向かって付いていて、モーターの軸が床に斜めに接します。
モーターを写真のような向きに回転させたとき、この足は画面の手前から奥に向かって移動します。
この独立した4つのモーターの回転方向、速度を調節して、BugCを制御します。
●Protocol I2C(0x38)
BugCのI2C制御は、モーターとオンボードLEDの2種類です
/*-------------------------------------------------------*/
| MOTOR SPEED REG | 0x00
| -------------------------------------------------------
| FRONT_LEFT_reg[0] | R/W | FRONT_LEFT SPEED
| FRONT_RIGHT_reg[1] | R/W | FRONT_RIGHT SPEED
| REAR_LEFT_reg[2] | R/W | REAR_LEFT SPEED
| REAR_RIGHT_reg[3] | R/W | REAR_RIGHT SPEED
/*-------------------------------------------------------
Wire.beginTransmission(0x38);
Wire.write(0x00);
Wire.write(FRONT_LEFT SPEED);
Wire.write(FRONT_RIGHT SPEED);
Wire.write(REAR_LEFT SPEED);
Wire.write(REAR_RIGHT SPEED);
Wire.endTransmission();
/*-------------------------------------------------------*/
| RGB LED COLOR REG | 0x10
| -------------------------------------------------------
| left/right_reg[0] | R/W | left/right control
| | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| | R | R | R | R | R | R | R | SELECT |
| | -SELECT: 0 FRONT_LEFT RGB LED
| | 1 FRONT_RIGHT RGB LED
| rgb_r_reg[1] | R/W | RED value
| rgb_g_reg[2] | R/W | Green value
| rgb_b_reg[3] | R/W | Blue value
/*-------------------------------------------------------
Wire.beginTransmission(0x38);
Wire.write(0x10);
Wire.write(0); // FRONT_LEFT RGB LED
Wire.write(Red);
Wire.write(Green);
Wire.write(Blue);
Wire.endTransmission();
Wire.beginTransmission(0x38);
Wire.write(0x10);
Wire.write(1); // FRONT_RIGHT RGB LED
Wire.write(Red);
Wire.write(Green);
Wire.write(Blue);
Wire.endTransmission();
●ソースコード
〇bugC.cpp
/*
* @Author: Sorzn
* @Date: 2019-11-22 13:38:26
* @LastEditTime: 2019-11-22 14:28:56
* @Description: M5Stack Hat BUGC Lib
* @FilePath: /M5StickC/examples/Hat/BUGC/bugC.cpp
*/
#include "bugC.h"
void BUGC::Init() {
Wire.begin(SDA, SCL);
// Wire.begin(0, 26); // M5Stick-C
}
void BUGC::Write1Byte(uint8_t address, uint8_t Register_address, uint8_t data) {
Wire.beginTransmission(address);
Wire.write(Register_address);
Wire.write(data);
Wire.endTransmission();
}
void BUGC::Write2Byte(uint8_t address, uint8_t Register_address,
uint16_t data) {
Wire.beginTransmission(address);
Wire.write(Register_address);
Wire.write(data >> 8); // MSB
Wire.write(data & 0xFF); // LSB
Wire.endTransmission();
}
void BUGC::WriteBytes(uint8_t address, uint8_t Register_address, uint8_t *data,
size_t size) {
Wire.beginTransmission(address);
Wire.write(Register_address);
for (int i = 0; i < size; i++) {
Wire.write(*(data + i));
}
Wire.endTransmission();
}
uint8_t BUGC::ReadBytes(uint8_t address, uint8_t subAddress, uint8_t count,
uint8_t *dest) {
Wire.beginTransmission(address); // Initialize the Tx buffer
Wire.write(subAddress); // Put slave register address in Tx buffer
uint8_t i = 0;
if (Wire.endTransmission(false) == 0 &&
Wire.requestFrom(address, (uint8_t)count)) {
while (Wire.available()) {
dest[i++] = Wire.read();
}
return true;
}
return false;
}
//*******************************************************//
// if speed > 0; clockwise rotation
void BUGC::BugCSetSpeed(uint8_t pos, int8_t speed) {
speed = (speed > 100) ? 100 : speed;
speed = (speed < -100) ? -100 : speed;
Write1Byte(BUGC_ADDR, pos, speed);
}
void BUGC::BugCSetAllSpeed(int8_t speed_0, int8_t speed_1, int8_t speed_2,
int8_t speed_3) {
int8_t speed_out[4] = {speed_0, speed_1, speed_2, speed_3};
for (uint8_t i = 0; i < 4; i++) {
speed_out[i] = (speed_out[i] > 100) ? 100 : speed_out[i];
speed_out[i] = (speed_out[i] < -100) ? -100 : speed_out[i];
}
WriteBytes(BUGC_ADDR, 0x00, (uint8_t *)speed_out, 4);
}
void BUGC::BugCSetColor(uint32_t color_left, uint32_t color_right) {
uint8_t color_out[4];
color_out[0] = 0;
color_out[1] = (color_left & 0xff0000) >> 16;
color_out[2] = (color_left & 0x00ff00) >> 8;
color_out[3] = (color_left & 0x0000ff);
WriteBytes(BUGC_ADDR, 0x10, color_out, 4);
color_out[0] = 1;
color_out[1] = (color_right & 0xff0000) >> 16;
color_out[2] = (color_right & 0x00ff00) >> 8;
color_out[3] = (color_right & 0x0000ff);
WriteBytes(BUGC_ADDR, 0x10, color_out, 4);
}
〇bugC.h
/*
* @Author: Sorzn
* @Date: 2019-11-22 13:38:31
* @LastEditTime: 2019-11-22 14:33:56
* @Description: M5Stack Hat BUGC Lib
* @FilePath: /M5StickC/examples/Hat/BUGC/bugC.h
*/
#ifndef __BUG_C_H
#define __BUG_C_H
#include "Arduino.h"
#include "Wire.h"
#define BUGC_ADDR 0x38
#define FRONT_LEFT 0
#define FRONT_RIGHT 1
#define REAR_LEFT 2
#define REAR_RIGHT 3
class BUGC {
public:
void Init();
/**
* @description: Set BugC single motor speed
* @param pos: 0 ~ 3
* @param speed: -100 ~ 100
* @return:
*/
void BugCSetSpeed(uint8_t pos, int8_t speed);
/**
* @description: Set BugC motor speed
* @param speed_0: -100 ~ 100
* @param speed_1: -100 ~ 100
* @param speed_2: -100 ~ 100
* @param speed_3: -100 ~ 100
* @return:
*/
void BugCSetAllSpeed(int8_t speed_0, int8_t speed_1, int8_t speed_2,
int8_t speed_3);
/**
* @description: Set BugC sk6812 color
* @param color_left: (r << 16) | (g << 8) | b
* @param color_right: (r << 16) | (g << 8) | b
* @return:
*/
void BugCSetColor(uint32_t color_left, uint32_t color_right);
private:
void Write1Byte(uint8_t address, uint8_t Register_address, uint8_t data);
void Write2Byte(uint8_t address, uint8_t Register_address, uint16_t data);
void WriteBytes(uint8_t address, uint8_t Register_address, uint8_t* data,
size_t size);
uint8_t ReadBytes(uint8_t address, uint8_t subAddress, uint8_t count,
uint8_t* dest);
};
#endif
〇bugC.ino
#include "bugC.h"
BUGC BugC;
#define BUGC_ADDR 0x38
#define BUGC_LED_REG 0x10
#define BUGC_LED_LEFT 0x00
#define BUGC_LED_RIGHT 0x01
#define WAIT 20
void color(int velocity) {
uint8_t R, G, B;
velocity = velocity % 255;
if (velocity < 85) {
R = 255 - velocity * 3;
G = 0;
B = velocity * 3;
} else if (velocity < 170 ) {
velocity -= 85;
R = 0;
G = velocity * 3;
B = 255 - velocity * 3;
} else {
velocity -= 170;
R = velocity * 3;
G = 255 - velocity * 3;
B = 0;
}
Wire.beginTransmission(BUGC_ADDR);
Wire.write(BUGC_LED_REG);
Wire.write(BUGC_LED_LEFT);
Wire.write(R);
Wire.write(G);
Wire.write(B);
Wire.endTransmission();
Wire.beginTransmission(BUGC_ADDR);
Wire.write(BUGC_LED_REG);
Wire.write(BUGC_LED_RIGHT);
Wire.write(R);
Wire.write(G);
Wire.write(B);
Wire.endTransmission();
delay(WAIT);
}
void shou_led() {
int i = 0;
while(1) {
color(i);
if ((++i) == 255) i = 0;
}
}
void stop() {
BugC.BugCSetColor(0x100000, 0x100000); // RED
BugC.BugCSetAllSpeed(0, 0, 0, 0);
delay(1000);
}
void forward(float speed) {
int8_t leftF = 100 * speed;
int8_t rightF = -60 * speed;
int8_t leftR = 100 * speed;
int8_t rightR = -60 * speed;
BugC.BugCSetColor(0x000010, 0x000010); // BLUE
BugC.BugCSetAllSpeed(leftF, rightF, leftR, rightR);
delay(1000);
}
void back(float speed) {
int8_t leftF = -90 * speed;
int8_t rightF = 80 * speed;
int8_t leftR = -90 * speed;
int8_t rightR = 80 * speed;
BugC.BugCSetColor(0x101000, 0x101000); // YELLOW
BugC.BugCSetAllSpeed(leftF, rightF, leftR, rightR);
delay(1000);
}
void forward_left(float speed) {
int8_t leftF = 0 * speed;
int8_t rightF = -100 * speed;
int8_t leftR = 0 * speed;
int8_t rightR = -50 * speed;
BugC.BugCSetColor(0x001000, 0x000000); // GREEN
BugC.BugCSetAllSpeed(leftF, rightF, leftR, rightR);
delay(1000);
}
void forward_right(float speed) {
int8_t leftF = 100 * speed;
int8_t rightF = 0 * speed;
int8_t leftR = 50 * speed;
int8_t rightR = 0 * speed;
BugC.BugCSetColor(0x000000, 0x001000); // GREEN
BugC.BugCSetAllSpeed(leftF, rightF, leftR, rightR);
delay(1000);
}
void back_left(float speed) {
int8_t leftF = 0 * speed;
int8_t rightF = 50 * speed;
int8_t leftR = 0 * speed;
int8_t rightR = 100 * speed;
BugC.BugCSetColor(0x001000, 0x000000); // GREEN
BugC.BugCSetAllSpeed(leftF, rightF, leftR, rightR);
delay(1000);
}
void back_right(float speed) {
int8_t leftF = -50 * speed;
int8_t rightF = 0 * speed;
int8_t leftR = -100 * speed;
int8_t rightR = 0 * speed;
BugC.BugCSetColor(0x000000, 0x001000); // GREEN
BugC.BugCSetAllSpeed(leftF, rightF, leftR, rightR);
delay(1000);
}
void rotate_left(float speed) {
int8_t all = -30 * speed;
BugC.BugCSetColor(0x001000, 0x000000); // GREEN
BugC.BugCSetAllSpeed(all, all, all, all);
delay(1000);
}
void rotate_right(float speed) {
int8_t all = 30 * speed;
BugC.BugCSetColor(0x000000, 0x001000); // GREEN
BugC.BugCSetAllSpeed(all, all, all, all);
delay(1000);
}
void setup() {
delay(10000);
BugC.Init();
stop();
forward(0.8);
back(0.8);
rotate_left(0.8);
rotate_right(0.8);
forward_left(0.8);
forward_right(0.8);
back_left(0.8);
back_right(0.8);
stop();
while (1);
}
void loop() {}
実際に動かしてみると、
モーターの個体差、筐体の重心のズレなどにより接地圧が異なり、推進力にバラツキが生じます。
そのため、プログラムではモーターごとの補正を行っています。
M5StickCを使えば実装している6軸(加速度、ジャイロ)センサにより、ある程度の姿勢制御が可能かとは思いますが、
制御プログラムの作成にはかなり時間が掛かると思います。
●開発環境
ソースコードのビルドには、PlatformIOを使用しています。
Arduino開発環境構築 PlatformIO
|
Raspberry Pi(ラズベリー パイ)は、ARMプロセッサを搭載したシングルボードコンピュータ。イギリスのラズベリーパイ財団によって開発されている。
たいていのことは100日あれば、うまくいく。長田英知著
「時間がなくて、なかなか自分のやりたいことができない」
「一念発起して何かを始めても、いつも三日坊主で終わってしまう」
「色んなことを先延ばしにしたまま、時間だけが過ぎていく」
そこで本書では、そんな著者が独自に開発した、
まったく新しい目標達成メソッド「100日デザイン」について、
その知識と技術を、余すところなくご紹介します。
まんがで納得ナポレオン・ヒル 思考は現実化する
OLとして雑務をこなす日々に飽き足らず、科学者だった父が残した薬品を商品化すべく、起業を決意した内山麻由(27)。彼女はセミナーで知り合った謎の女性からサポートを得ながら、彼女と二人三脚でナポレオン・ヒルの成功哲学を実践し、さまざまな問題を乗り越えていく。
ヒル博士の<ゴールデンルール>に従い、仕事に、恋に全力疾走する彼女の、成功への物語。
今日は人生最悪で最高の日 1秒で世界を変えるたったひとつの方法 ひすいこたろう著
偉人の伝記を読むと、最悪な日は、不幸な日ではなく、新しい自分が始まる日であることがわかります。最悪な出来事は、自分の人生が、想像を超えて面白くなる兆しなのです。偉人伝を読むことで、このときの不幸があったおかげで、未来にこういう幸せがくるのかと、人生を俯瞰する視線が立ち上がるのです。
ご飯は私を裏切らない heisoku著
辛い現実から目を背けて食べるご飯は、いつも美味しく幸せを届けてくれる。
29歳、中卒、恋人いない歴イコール年齢。バイト以外の職歴もなく、短期バイトを転々とする日々。ぐるぐると思索に耽るけど、ご飯を食べると幸せになれる。奇才の新鋭・heisokuが贈るリアル労働グルメ物語!
【最新版Gemini 3に対応!】できるGemini (できるシリーズ)
Geminiを「最強の知的生産パートナー」として使いこなすための、実践的なノウハウを凝縮した一冊です。
基本的な操作方法から、具体的なビジネスシーンでの活用、日々の業務を自動化するGoogle Workspaceとの連携、さらには自分だけのオリジナルAIを作成する方法まで余すところなく解説します。
Rustプログラミング完全ガイド 他言語との比較で違いが分かる!
Rustの各手法や考え方を幅広く解説!
500以上のサンプルを掲載。実行結果も確認。
全24章の包括的なチュートリアル。
ポチらせる文章術
販売サイト・ネット広告・メルマガ・ブログ・ホームページ・SNS…
全WEB媒体で効果バツグン!
カリスマコピーライターが教える「見てもらう」「買ってもらう」「共感してもらう」すべてに効くネット文章術
小型で便利な Type-C アダプター USB C オス - USB3.1 オスアダプター
Type-C端子のマイコンボードをこのアダプタを介して直接Raspberry Piに挿すことができます。ケーブルなしで便利なツールです。
Divoom Ditoo Pro ワイヤレススピーカー
15W高音質重低音/青軸キーボード/Bluetooth5.3/ピクセルアート 専用アプリ/USB接続/microSDカード
電源供給USBケーブル スリム 【5本セット】
USB電源ケーブル 5V DC電源供給ケーブル スリム 【5本セット】 電源供給 バッテリー 修理 自作 DIY 電子工作 (100cm)
|