以前製作した、LEGOブロックで作ったラジコンについて、操作部に使用していた「M5StickC Plus」が生産中止になったため、後継機の「M5StickC Plus2」でも動くように書き換えました。
以前製作したLEGOラジコンは以下のリンクで詳しく紹介しています。
1.LEGOラジコンについて
・外観
・配線図
・作り方
2.M5StickC Plus2とは
3.ATOM Liteとは
4.サンプルプログラム(コピペ)
・操作部:M5StickC Plus2
・駆動部(車体):ATOM Lite
5.動作確認
6.プログラムの詳細
・操作部
・駆動部
7.まとめ
1.LEGOラジコンについて
・外観
前回作成したLEGOラジコンは下画像になります。
今回作成したLEGOラジコンは下画像になります。
前回とほぼ同じですが、操作部には「M5StickC Plus2」を使用し、ラジコンカーの方は「ATOM Matrix」から「ATOM Lite」に変更。
バッテリーは「ATOM TailBat」からモバイルバッテリーに変更しています。
前回製作したLEGOラジコンの作り方は、以下「youtube」の「ロジカラチャンネル」で紹介しています。
・配線図
ラジコンの操作部と駆動部の配線は以下のようになります。
※配線図には「M5StickC Plus」の画像を使ってますが「M5StickC Plus2」でも同じ配線です。
操作部(コントローラー)
駆動部(360°回転サーボ+180°RCサーボSG90)
操作部は「M5StickC Plus2」と「JoyStick」を付属の「GROVEコネクタ配線」で接続するだけです。
駆動部は「360°回転サーボ」の信号線を「ATOM」の「G21」に接続し、「180°RCサーボSG90」の信号線を「G25」に接続します。
サーボの「5V」と「0V」を「ATOM」の「5V」と「G」を分岐(L型ピンヘッダー改造またはジャンパー線やブレッドボード等を使用)させてそれぞれに接続します。
・作り方
作り方については上の「youtube」が分かりやすいと思いますが、LEGOは前回製作したものとほぼ同じなので、以下リンクで画像でも紹介しています。
以下ダイジェスト的になりますが製作画像になります。
LEGOの購入は「楽天」の「ブリッカーズ楽天市場店」がおすすめです。
「テクニックシリーズ」で探せば、ほぼ手に入ると思います。
以下のような安価な互換品もあります。精度は良くないので、はめ込みが固かったりゆるかったりします^^; その辺りを気にしなければたくさんの部品が安く入手できるのでおすすめです。
2.M5StickC Plus2とは
「M5StickC Plus2」とは「M5Stackテクノロジー社」のマイコンボードで1.14インチTFT液晶画面や入出力端子、ボタン、LED、赤外線送信、ブザー、3軸ジャイロ+3軸加速度センサ、マイク、RTC(リアルタイムクロック)、バッテリーが内蔵されています。
他にもシリアル通信はもちろんWiFiやBluetooth通信にも対応しており、プログラムは「C言語」ベースの「Arduino IDE」「PlatformIO」や「ビジュアルプログラミング(UiFlow)」「Python(MicroPython)」で作成できます。
外観は下画像のようになります。(寸法:H48 x W25 x D13 mm)
端子配列は以下になります。
以下Amazonでも買えるようですが少し割高で納期もかかり、写真にはLEGOのパーツが載ってないので、多分ついてると思いますが・・・スイッチサイエンスで購入した方が確実です。
端子機能は以下になります。
「M5StickC Plus2」については以下のリンクで詳しく紹介しています。
3.ATOM Liteとは
「ATOM Lite」とは、「M5Stackテクノロジー社」のマイコンボードで、液晶画面は無いですが、出力端子を2本使って「I2C通信」でOLED表示器を外付けできます。
1個だけですが本体ボタンもあり、フルカラーLEDも内蔵されています。
小さいのにシリアル通信はもちろんWiFiもBluetoothも使える。何といっても安い!さらに基板剥き出しではなくケースに入っていて安心して使用できます。
拡張ユニットも豊富でこれらのユニットを接続すれば、SDカードやGPS、バーコードリーダー、スピーカー、RS-232C/RS-485/CAN等の通信、リレー等を使用することができます。
外観は下画像になります。(寸法:H24 x W24 x D10 mm)
端子配列は以下になります。
端子機能は以下になります。
項目 | 機能 |
---|---|
電源5V | USBからの電源5Vが出力されます USBを接続しない時5Vを入力して使用できます |
制御用電源3.3V | 入出力制御用の電源として使用します。(入力不可) |
0V | 電源の0V(コモン)を接続します |
入力 | 入力端子として設定可 |
出力 | 出力端子として設定可 |
ADC | アナログ入力端子として設定可 ※G25,G26は無線と併用不可 |
DAC | デジタル出力端子として設定可 |
GROVE | 4極のコネクタ、拡張ユニット等が接続できます |
IR | 赤外線送信(上部側面穴から送信、受信不可) |
LED | 本体LED(フルカラー(RGB)、ソフト制御) |
Button | 本体ボタン |
「ATOM Lite」については以下のリンクで詳しく紹介しています。
4.サンプルプログラム(コピペ)
LEGOラジコンカー(M5StickC Plus2仕様)のサンプルプログラムは以下になります。
操作部(M5StickC Plus2)と駆動部(ATOM Lite)でそれぞれコピペで書き込んで動作確認してください。
・操作部:M5StickC Plus2
操作部のサンプルプログラムは以下になります。「コピペ」して書き込んでください。
※下コード(黒枠)内の右上角にある小さなアイコンのクリックでコピーできます。
#include <M5StickCPlus2.h> // 本体設定用ヘッダーファイル
#include <Wire.h> // I2C通信用
#include "BluetoothSerial.h" // Bluetooth通信用
BluetoothSerial SerialBT;
// 変数宣言
String slave_name = "RC_CAR"; // スレーブ側の接続名
String master_name = "CONTROLLER"; // マスターの接続名
bool connected = 0; // 接続状態格納用
int connect_count = 3; // 再接続実行回数
String data = ""; // 受信データ格納用
int btn_pw = 0; // 電源ボタン状態取得用
float battery; //バッテリー残量表示用
float x_data; // ジョイスティックX軸(角度サーボ)
float y_data; // ジョイスティックY軸(回転サーボ)
int press; // ジョイスティック押し込みボタン
int btn_a = 0; // 本体ボタンA動作確認用
/********************** 再起動(リスタート)処理 **********************/
void restart() {
if (digitalRead(35) == (LOW)) { // 電源が押されていれば
ESP.restart(); // 再起動
}
}
// 初期設定 ----------------------------------------------------------
void setup(){
auto cfg = M5.config(); // 本体初期化
StickCP2.begin(cfg);
Serial.begin(9600); // シリアル出力初期化
Wire.begin(32, 33); // Grove端子をI2C設定(SDA, SCL)
// LCD表示設定
M5.Lcd.fillScreen(BLACK); // 背景色
M5.Lcd.setFont(&fonts::Font4); // フォント
// 入力端子
pinMode(35, INPUT_PULLUP); // 入力設定(プルアップ)
// Bluetooth接続開始
SerialBT.begin(master_name, true); // マスターとして初期化。trueを書くとマスター、省略かfalseを指定でスレーブ
M5.Lcd.print("Bluetooth\nSearch!\nRC_CAR\n.");
Serial.print("Bluetooth\nSearch!\nRC_CAR\n.");
// Bluetooth接続実行
while (connected == 0) { // connectedが0(未接続)なら接続実行を繰り返す
if (connect_count != 0) { // 再接続実行回数カウントが0でなければ
connected = SerialBT.connect(slave_name); // 接続実行(接続成功で1を返す)
M5.Lcd.print(".");
connect_count--; // 再接続実行回数カウント -1
} else { // 再接続実行回数カウントが0なら接続失敗
M5.Lcd.setTextColor(RED, BLACK);
M5.Lcd.print("\nFailed!");
Serial.print("\nFailed!");
while (1) {restart();} // 無限ループ(再起動待機)
}
}
// 接続確認
M5.Lcd.setTextColor(WHITE, BLACK);
if (connected) { // 接続成功なら
M5.Lcd.setTextColor(CYAN, BLACK);
M5.Lcd.println("\nConnected!"); // 「Connected!」表示
Serial.println("\nConnected!");
} else { // 接続失敗なら
M5.Lcd.setTextColor(RED, BLACK);
M5.Lcd.println("\nFailed!!"); // 「Failed!!」表示
Serial.println("\nFailed!!");
while (1) {restart();} // 無限ループ(再起動待機)
}
delay(1000); // 接続結果確認画面表示時間
// LCD表示リセット
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setTextColor(WHITE, BLACK);
}
// メイン処理 --------------------------------------------------------
void loop() {
M5.update(); // ボタン状態更新
// ジョイスティックI2Cデータ取得
Wire.requestFrom(0x52, 3); // I2Cデータ取得(アドレス、バイト数)
while (Wire.available()) { // 通信データがあれば
x_data = Wire.read(); // X軸アナログ値取得(0〜255)
y_data = Wire.read(); // Y軸アナログ値取得(0〜255)
press = Wire.read(); // 押し込み時ボタン状態取得(true/false)
}
// ボタン操作処理(未使用)
if (M5.BtnA.wasPressed()) { // ボタンAが押されていれば
btn_a = !btn_a; // ボタン状態反転
}
// Bluetoothデータ送信(「CR」区切り文字)
if (connected == 1) { // connectedが1(接続済)ならデータ送信
SerialBT.printf("%3.0f,%3.0f,%d,%d\r", x_data, y_data, press, btn_a); // X軸アナログ値, Y軸アナログ値, 押し込み時ボタン状態, 本体ボタンA操作状態
}
// 液晶表示
M5.Lcd.setCursor(0, 0); // 座標指定
M5.Lcd.setTextFont(4); // フォント設定
M5.Lcd.println("Controller"); // 項目表示
M5.Lcd.printf("X : %3.0f \n", x_data); // X軸アナログ値
M5.Lcd.printf("Y : %3.0f \n", y_data); // Y軸アナログ値
M5.Lcd.printf("Press : %d \n", press); // 押し込みボタン状態表示
M5.Lcd.printf("BtnA : %d \n", btn_a); // 本体ボタン操作状態表示
// Bluetoooth受信データをLCDに表示
if (SerialBT.available()) { // Bluetoothデータ受信で
data = SerialBT.readStringUntil('\r'); // 区切り文字「CR」までデータ取得
M5.Lcd.print("BT: "); // 受信データ液晶表示
M5.Lcd.println(data + " "); // 液晶表示は改行あり
Serial.print(data + "\r"); // シリアル出力(「CR」付きで先頭復帰し常時表示)
} else { // Bluetoothデータ受信なしで
M5.Lcd.setTextColor(ORANGE, BLACK);
M5.Lcd.println("LOST! "); // 警告表示
M5.Lcd.setTextColor(WHITE, BLACK);
}
// バッテリー残量取得(パーセント)
battery = StickCP2.Power.getBatteryLevel(); // 0〜100% で取得
M5.Lcd.setTextFont(2); // フォント設定
M5.Lcd.setCursor(90, 220); // 座標
M5.Lcd.printf("%3.0f%%\n", battery); //バッテリー残量表示
restart(); // 再起動(リスタート)処理
delay(100); // 遅延時間
}
・駆動部(車体):ATOM Lite
駆動部のサンプルプログラムは以下になります。「コピペ」して書き込んでください。
※下コード(黒枠)内の右上角にある小さなアイコンのクリックでコピーできます。
#include <M5Atom.h>
#include "BluetoothSerial.h"
BluetoothSerial SerialBT;
//FastLED(CRGB構造体)設定
CRGB dispColor(uint8_t r, uint8_t g, uint8_t b) {
return (CRGB)((r << 16) | (g << 8) | b);
}
// 変数宣言
float x_data; // ジョイスティックX軸(角度サーボ)
float y_data; // ジョイスティックY軸(回転サーボ)
float speed; // 回転サーボ速度値換算
int press; // ジョイスティック押し込みボタン
int btn_a; // コントローラ側本体ボタンA操作状態
float setting[16][5]; // チャンネル[0〜15]ごとの[周波数, bit数, 0゜パルス時間ms, 最大角度パルス時間ms, 最大動作角度]格納配列
float x_angle; // X軸角度指示値
float y_round; // Y軸角度指示値
float duty_angle; // X軸角度初期値
float duty_y_angle; // Y軸角度初期値
float read_angle_data; // X軸角度現在値
float read_round_data; // Y軸角度現在値
int cnt; // シリアル出力カウント用
/******************* PWM出力、サーボ仕様設定関数 *******************/
void servo_set(int pin, int channel, float freq, float bit_num, float time_min, float time_max, float angle_max) {
// サーボ設定値をチャンネルごとの配列に格納
setting[channel][0] = freq; // 周波数
setting[channel][1] = bit_num; // bit数
setting[channel][2] = time_min; // 0゜パルス時間ms
setting[channel][3] = time_max; // 最大角度パルス時間ms
setting[channel][4] = angle_max; // 最大動作角度
// PWM設定
pinMode(pin, OUTPUT); // PWM用ピンを出力設定
ledcSetup(channel, freq, bit_num); // PWM設定(チャンネル, 周波数, ビット数)
ledcAttachPin(pin, channel); // PWMチャンネル割り当て(ピン番号, チャンネル)
}
/********************** サーボ動作実行関数 **********************/
float servo(int channel, float angle) {
float resolution; // 分解能
float period; // 周期ms
float duty_min; // 0゜Duty計算値
float duty_max; // 最大角度Duty計算値
float duty_active; // 動作範囲のDuty計算値
int duty_value; // PWM出力Duty値(High状態)※整数型として小数点以下切り捨て
float read_angle; // PWM出力Duty値からの角度換算
// サーボ定数算出
resolution = pow(2, setting[channel][1]); // 分解能(2のbit数乗)
period = 1000 / setting[channel][0]; // 周期(1000ms / 周波数)
duty_min = (resolution / period) * (setting[channel][2]); // 0゜Duty計算値((分解能/周期)*0゜パルス時間μs)
duty_max = (resolution / period) * (setting[channel][3]); // 最大角度Duty計算値((分解能/周期)*最大角度パルス時間μs)
duty_active = duty_max - duty_min; // 動作範囲のDuty計算値
duty_value = (angle * (duty_active / setting[channel][4])) + duty_min; // 角度指定値(浮動小数点数) → PWM出力Duty値(整数)換算
if (duty_value <= duty_min) { // PWM出力Duty値が0゜Duty計算値以下なら
duty_value = duty_min + 1; // PWM出力Duty値+1
}
// PWM出力実行
ledcWrite(channel, duty_value); // 指定したチャンネルにDuty値を指定してPWM出力実行
read_angle = (ledcRead(channel) - duty_min) * setting[channel][4] / duty_active; // PWM出力Duty値を取得して角度に換算
return read_angle; // 角度を返す
}
// 初期設定 ----------------------------------------------------------
void setup(){
M5.begin(false, false, true); // 本体初期化(UART, I2C, LED)
Serial.begin(9600); // シリアル出力初期化
// Bluetooth接続開始
SerialBT.begin("RC_CAR"); // 接続名を指定して初期化。第2引数にtrueを書くとマスター、省略かfalseでスレーブ
// PWM出力、サーボ仕様設定(サーボごとに使用する端子、チャンネル等を設定)
// PWM出力のチャンネルは 0,1/ 2,3/ 4,5/ 6,7/ 8,9/ 10,11 /12,13 /14,15でペア ※周波数と分解能はペアで同じにする必要があります。
// (出力端子, チャンネル, 周波数, bit数, 0゜パルス時間ms, 最大角度動作時間ms, 最大動作角度)
servo_set(25, 1, 50, 12, 0.5, 2.4, 180); // チャンネル1(ステアリング):PWM出力、サーボ仕様設定関数呼び出し
servo_set(21, 2, 50, 12, 0.5, 2.5, 255); // チャンネル2(回転駆動):PWM出力、サーボ仕様設定関数呼び出し
}
// メイン処理 --------------------------------------------------------
void loop() {
M5.update(); // ボタン状態更新
// Bluetooth通信データ受信処理
if (SerialBT.available()) { // コントローラからデータ受信で
M5.dis.drawpix(0, dispColor(0, 50, 50)); // LED点灯色指定
// ローカル変数宣言
int i = 0; // 取得データカウント用
String data; // 受信データ格納用
data = ""; // データ初期化
char c; // 受信データ文字取得用
// 受信データの文字列をint型に変換して変数に格納
while (SerialBT.available()) { // 受信データがある間実行
c = SerialBT.read(); // Bluetoothデータを文字変数「c」へ格納
if (c != ',' || c != '\r') { // 受信データがカンマ「,」でも「CR」でなければ
data = data + c; // 文字変数「c」を文字列変数「data」に加算
}
if (c == ',') { // カンマ「,」なら
switch (i) { // 「i」で分岐
case 0: // 「0」ならX軸データ
x_data = data.toInt(); // ジョイスティックX軸データ取得
break;
case 1: // 「1」ならY軸データ
y_data = data.toInt(); // ジョイスティックY軸データ取得
break;
case 2: // 「2」ならスティック押し込みボタン状態
press = data.toInt(); // ジョイスティック押し込みボタン状態取得(未使用)
break;
}
i++; // i +1
data = ""; // 文字列変数初期化
}
if (c == '\r') { // 「CR」なら最終データ(コントローラ側本体ボタンA)まで取得完了
btn_a = data.toInt(); // コントローラ側本体ボタンA操作状態データ取得(未使用)
}
}
// ジョイスティックX軸受信データをステアリング角度サーボ指示値に換算
x_angle = 65 * (x_data / 255) + 10; // X軸ステアリング角度(65°)換算 + 微調整角度
// ジョイスティックY軸受信データを回転駆動サーボ指示値に換算
if (y_data >= 110 && y_data <= 129) { // 回転駆動不動領域設定、Y軸がこの範囲なら
speed = 127; // 回転駆動停止(Duty比50%)
} else {
speed = y_data; // y軸受信データを回転駆動サーボ指示値へ
}
if (speed >= 255) { // +領域の増加分が255以上なら
speed = 255; // 回転サーボ速度値は255(最大値)
}
y_round = 255 - speed; //ジョイスティックY軸 - 回転駆動指示値換算(動作反転指示)
// ステアリング(角度)サーボ動作実行
read_angle_data = servo(1, x_angle); // チャンネル1:サーボ動作実行関数呼び出し(チャンネル, 角度値)
// 駆動(360゜回転)サーボ動作実行
read_round_data = servo(2, y_round); // チャンネル2:サーボ動作実行関数呼び出し(チャンネル, 回転指示値)
// Bluetoothデータ送信
SerialBT.printf("%3.0f,%3.0f\r", read_angle_data, read_round_data); // 区切り文字「CR」をつけてマスター側へ送信
} else {
M5.dis.drawpix(0, dispColor(100, 30, 0)); // LED点灯
}
// シリアル出力
if (cnt == 10) { // シリアル出力カウントが10なら
Serial.printf("X: %3.0f Y: %3.0f P: %d B: %d A: %5.1f R: %5.1f\n", x_data, y_data, press, btn_a, read_angle_data, read_round_data); // X軸アナログ値, Y軸アナログ値, 押し込み時ボタン状態取得, コントローラ側本体ボタンA操作状態, 回転サーボDutyオン幅, 角度サーボDutyオン幅
cnt = 0; // シリアル出力カウントリセット
}
cnt++; // シリアル出力カウント加算
delay(20); // 遅延時間
}
5.動作確認
操作方法は以前製作したLEGOラジコンと同じで以下のようになります。
(下画像はM5Stick PlusのものですがPlus2も同じです。)
<通信接続開始>
<通信接続完了>
<操作可能>
<通信遮断>
ラジコンカー本体「ATOM Lite」の電源を入れてから、操作部「M5StickC Plus2」の電源も入れます。(左下側面ボタン1秒以上押すとON、6秒以上長押しで電源OFF)
すると、操作部とラジコンカー本体とでBluetooth接続が開始されます。
接続が完了すると「Connected!」が表示され、画面が切り換わってラジコン操作可能状態になります。
操作中はジョイスティックのX,Y座標が送信され、ラジコンカー側からサーボの動作角度、回転速度の値を受信し続けます。
パワータイプ から スピードタイプへ組み換え
ラジコンカーは2つのギヤの組み合わせを変えることで、パワータイプとスピードタイプに換えられます。
初期状態ではギア比を減速(パワータイプ)するように組んでますが、下写真のようにギアを入れ換えることでギア比を増速(スピードタイプ)するように組み換えることができます。
速度は4倍になるのでコッチの方が速くて遊んでて楽しいです♪
6.プログラムの詳細
プログラムについては過去に紹介してきた記事の内容を組み合わせたもので、初心者の方がいきなり理解するのは難しいかもしれません。
過去の記事で各動作を個別に詳しく紹介していますので、過去記事で詳細をご確認ください。
・操作部
操作部は「BluetoothSerial」ライブラリを使用して「M5StackC Plus2」をマスター側として設定し「ジョイスティック」の操作状態(X軸、Y軸の値)を文字列でスレーブ側の「ATOM Lite」へ送信しています。
「Bluetooth通信」や「ジョイスティック」の使用方法は以下のリンクで詳しく紹介しています。
・駆動部
駆動部は操作部と同様に「Bluetooth」通信を使用していますが、こちらはスレーブ側となり、マスター側からの「ジョイスティック」の操作状態(X軸、Y軸の値)を文字列で受信します。
受信したY軸の値を「駆動用360°サーボの回転方向と速度」に、X軸の値を「ステアリング用サーボ(SG90)の回転角度」に設定してラジコンカーを駆動します。
「サーボ」の使い方や制御方法については以下のリンクで詳しく紹介しています。
7.まとめ
Bluetooth通信を使用してジョイスティックで操作するLEGOラジコンの作り方を紹介しました。
以前も同様のものを製作しましたが、操作部に使用していた「M5StickC Plus」が生産中止となり、後継機の「M5StickC Plus2」用に書き換えました。
プログラムの構成に大きな変更はありませんが「M5StickC Plus2」の初期設定の箇所をいくつか修正しています。
駆動部の制御には前回は「ATOM MATRIX」を使用していましたが、バッテリー(ATOM TailBat)が弱ってきたのか、始動時に電圧降下で頻繁にリセットがかかったため、LEDの数が少ない「ATOM Lite」に変更しましたが、症状が変わらず・・・結局モバイルバッテリーを搭載できるように改造しています。
モバイルバッテリーを搭載したおかげで長く遊べるようになりました。
プログラムについては過去に紹介してきた記事の内容を組み合わせたもので、初心者の方がいきなり今回のサンプルプログラムの全てを理解するのは難しいかもしれません。
以下の過去記事で個別に詳しく紹介していますので、個別に動作確認しながら「各デバイスの使い方」や「Bluetooth通信」「PWM制御」による「RCサーボ」の使い方「ジョイスティック」の使い方を理解していきましょう。
コメント