断片は分かるけど、抜けてるところも多いから。
admin
la vie libre
M5stackには色々な機能が含まれているので、順次の機能確認でまずはBLE機能を使ってみます。
ソースはPlatformIOのライブラリでBuil-in中のESP32 BLE ArduinoのRevealから見えるBLE_scanから持ってきています。ライブラリーにM5stack追加とソースに
#include <m5stack.h> はM5stack使う時には必ず追加必要です。
#include <m5stack.h> // this is needed to the original source code.
/*
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp
Ported to Arduino ESP32 by Evandro Copercini
*/
#include <bledevice.h>
#include <bleutils.h>
#include <blescan.h>
#include <bleadvertiseddevice.h>
int scanTime = 5; //In seconds
BLEScan* pBLEScan;
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice advertisedDevice) {
Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str());
}
};
void setup() {
Serial.begin(115200);
Serial.println("Scanning...");
BLEDevice::init("");
pBLEScan = BLEDevice::getScan(); //create new scan
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
pBLEScan->setInterval(100);
pBLEScan->setWindow(99); // less or equal setInterval value
M5.begin(); //Init M5Core.
M5.Power.begin(); //Init Power module.
M5.Lcd.fillScreen(BLACK); //Set the screen background color to black.
M5.Lcd.setTextColor(GREEN , BLACK); //Sets the foreground color and background color of the displayed text.
M5.Lcd.setTextSize(2); //Set the font size.
M5.Lcd.setCursor(0, 70);
M5.Lcd.printf("pow on");
}
void loop() {
// put your main code here, to run repeatedly:
BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
Serial.print("Devices found: ");
Serial.println(foundDevices.getCount());
Serial.println("Scan done!");
pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory
delay(2000);
}
monitor_speed = 115200
を追加して実行させると、メッセージを吐き出しますが以下はその一部です。
Devices foundが0というのは不思議ですが。
admin
何の略語か気にしたことはなかったけれども、ラテン語の“pro bono publico”(公共善のために)ということなのだ。
bonoはbonum(中性名詞)のablative(日本語だと奪格)、同じくpublicoはpublicus(形容詞)のablativeで、前置詞pro(この場合はforが適切か)は後にくる名詞はablativeであることが前提だからそのように格変化。ラテン語が英語化しているものは多いけれどもその中のひとつ。
admin
二つ前の記事でIMUとサーボモーターを連動させたので、構造部分を作成してM5stackの直立状態を保持できるような姿勢制御を作ってみました。
前回からの変更点はサーボ制御部分のみです。
#include <imu.h>
int servopinx=2; // dio port definition for X axis
int servopiny=5; // dio port definition for Y axis
int pulsewidth; // pwm on time
int repeat=1; // number of pwm write cycle repetition
int ax; // angle for servo motors
int ay;
int az;
float p_accX; // to hold IMU read data
float p_accZ;
int p_angX; // to hold servo motor angles
int p_angZ;
boolean first = true; // check if it is first cycle or not.
//
void servo(int myangle, int motor) // servo motor pwm contorol. motor 0 : servoponx , motor 1 : servopiny
{
for (int i = 0; i < repeat; i ++) // i is used to keep a moving time, since this source does not use the library.
{
int port;
if (motor == 0){
port = servopinx;
}
else{
port = servopiny;
}
pulsewidth=map(myangle,0,180,500,2500);
digitalWrite(port,HIGH);
delayMicroseconds(pulsewidth);
digitalWrite(port,LOW);
delay(20-pulsewidth/1000);
}
}
void init_sm()
{
servo(90, 0);
servo(90, 1);
p_angX = 90;
p_angZ = 90;
delay(600);
}
void setup()
{
setup_imu();
pinMode(servopinx,OUTPUT);
pinMode(servopiny,OUTPUT);
}
void loop()
{
loop_imu();
if (first == true){
init_sm(); // initialize to 90 degree
first = false;
}
// the angle change is needed? & the change is reflected? & check the angle limit
if (accX < -0.05 && abs(p_accX - accX) > 0.02 && p_angX < 180){ p_angX ++; } else{ if (accX > 0.05 && abs(p_accX - accX) > 0.02 && p_angX > 0){
p_angX --;
}
}
if (accZ < -0.05 && abs(p_accZ - accZ) > 0.02 && p_angZ < 180){ p_angZ ++; } else{ if (accZ > 0.05 && abs(p_accZ - accZ) > 0.02 && p_angZ > 0){
p_angZ --;
}
}
p_accX = accX; // set to the previous values
p_accZ = accZ;
servo(p_angZ , 0); // drive the servo motor
servo(p_angX , 1);
delay(1);
M5.Lcd.setCursor(0, 114);
M5.Lcd.printf("%3d %3d ", p_angX, p_angZ);
}
imu.hには変更ありません。
今回はM5stackを垂直で使うので、二次元を水平に保つのはX軸とZ軸になるので、IMUからの読み出しデータはそれらを使います。
M5stackが移動するときには重力加速度以外の加速度も加算されますが、このアプリではそれを勘案する必要はないでしょう。多少動きがオーバーシュートするのはそのせいかもしれませんが。
写真は以下の通り。
サーボーモーターの電源入れない状態でM5stackを動かしているので、画面のアングル表示は変な値になっています。初期値がどうであっても、最後は収束しますが。
コードと3dプリンタ用のstlファイルは、
https://github.com/chateight/servo_
に置いてあります。M5stack追従のロジックは改善の余地があるように思います。
M5stack本体との接続は、DIO2,5とGNDの三本だけ。
admin
先週末にアップデートしましたが、以下が挙動不審。
① 毎日早朝のリフレッシュブートが実行されない
② timemachineの定時バックアップが実行されない
スケジューラーはTimeMachineEditor使ってます。
アップデートしてないAirはちゃんと動いているようだから、おそらくOSアップデートでの問題だろうと思う。まあ過去の経験からそのうち修正されるでしょう。
admin
M5stackの加速度計(重力加速度)とサーボモーターを組み合わせることで、M5stackの姿勢をフォローするものを作ります。
M5stackの加速度測定数値は結構揺らぎがあるので、平滑化と有効ビットの削減をおこなっています。
<servo.cpp>
#include <imu.h>
int servopinx=2; // dio port definition
int servopiny=5;
int pulsewidth; // pwm on time
int repeat=1; // number of pwm write cycle repetition
int ax; // angle for servo motors
int ay;
int az;
float comp = 1.1; // compensate not to show minus value
float adj = 30; // adjuct the angle with map() function not to exceed the range upper limit 180 & eliminate the noise
float p_accX = 0.5;
float p_accY = 0.5;
float p_accZ = 0.5;
boolean first = true; // check if it is first cycle or not.
float smooth = 0.6; // smoothing the angle value. it causes a delay time to the angle change.
//
void servo(int myangle, int motor) // servo motor pwm contorol. motor 0 : servoponx , motor 1 : servopiny
{
for (int i = 0; i < repeat; i ++) // i is used to keep a moving time, since this source does not use the library.
{
int port;
if (motor == 0){
port = servopinx;
}
else{
port = servopiny;
}
pulsewidth=map(myangle,0,180,500,2500);
digitalWrite(port,HIGH);
delayMicroseconds(pulsewidth);
digitalWrite(port,LOW);
delay(20-pulsewidth/1000);
}
}
void setup()
{
setup_imu();
pinMode(servopinx,OUTPUT);
pinMode(servopiny,OUTPUT);
}
void loop()
{
loop_imu();
if (first == true){ // smoothing
p_accX = accX;
p_accY = accY;
p_accZ = accZ;
first = false;
}
else{
p_accX = p_accX*smooth + accX*(1-smooth);
p_accY = p_accY*smooth + accY*(1-smooth);
p_accZ = p_accZ*smooth + accZ*(1-smooth);
}
ax = map((int)((p_accX+comp)*adj), 0, 66, 0, 180); // translate acc values to the range 0 to 180
ay = map((int)((p_accY+comp)*adj), 0, 66, 0, 180);
az = map((int)((p_accZ+comp)*adj), 0, 66, 0, 180);
M5.Lcd.setCursor(0, 114);
M5.Lcd.printf("%3d %3d %3d ", ax, ay, az);
servo(ax , 0); // drive the servo motor
servo(ay , 1);
delay(5);
}
本来的なヘッダーファイルの使い方とは多少異なりますが、M5stack IMUの加速度数値を読み取るルーチンです。
<imu.h>
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core sample source code
* Visit the website for more information:https://docs.m5stack.com/en/core/gray
*
* describe:MPU6886 example.
* date:2021/7/21
*******************************************************************************
*/
#define M5STACK_MPU6886
#include <m5stack.h>
float accX = 0.0F; // Define variables for storing inertial sensor data
float accY = 0.0F;
float accZ = 0.0F;
void setup_imu(){
M5.begin(); //Init M5Core.
M5.Power.begin(); //Init Power module.
M5.IMU.Init(); //Init IMU sensor.
M5.Lcd.fillScreen(BLACK); //Set the screen background color to black.
M5.Lcd.setTextColor(GREEN , BLACK); //Sets the foreground color and background color of the displayed text.
M5.Lcd.setTextSize(2); //Set the font size.
}
void loop_imu() {
M5.IMU.getAccelData(&accX,&accY,&accZ); //Stores the triaxial accelerometer.
// Accelerometer output is related
M5.Lcd.setCursor(0, 70);
M5.Lcd.printf("accX, accY, accZ");
M5.Lcd.setCursor(0, 92);
M5.Lcd.printf("%5.2f %5.2f %5.2f G", accX, accY, accZ);
}
やりたいことにはもう一工夫がいるので、それを追加して3Dプリンタで構造を作れば完成型になります。
P.S.
傾き(θ)に対して重力加速度はリニアではなく、重力加速度からarcsin()で傾きを計算しないといけないわけですが、大まかな振る舞いを見るには直線性は無視しても構わないと思います。
P.S.2
Switch Science記載のサーボモーターのピン番号は間違っている(PowとSig入れ違い)ので、正しいピン番号を記載しておきます。
admin
IMUとservo機能を連携させようとしますが、ソースファイルを一個にするのは汚い管理なので、機能ごとに分割します。
この時にArduino IDEだとバックエンドで無意識に処理をしてくれますが、VScodeを使う時にはほぼcの作法に従う必要があります。つまり、
・他のソースを使う時には、xxx.hとしてインクルードする。
今回のケースではservo.cppからimu.hを呼び出しています。
しかし、imu.hの組み込みで”M5にIMUは見つからないよ”とコンパイルエラーになります。
で調べると、
と、
https://github.com/m5stack/M5Stack/blob/master/src/M5Stack.h
にあるようにimu.hの先頭部分は、
従ってservo.cppからは、#include <M5Stack.h>を削除してimu.hの記述を使うようにするとうまくいきました。二重インクルードはこの場合にはエラーにならず、最初の#include <m5stack.h>が有効になるからでしょう。
== top of the servo.cpp ==
//#include <m5stack.h> // M5stack needs this module
#include <imu.h>
== top of the imu.h ==
#define M5STACK_MPU6886
#include <m5stack.h>
ということなので、Arduino IDEと違ってVScodeは普通のc開発に近いよということでした。
admin
サーボモーター(LFD-01M)到着したので早速動作確認。制御は標準的なPWM方式。PWMの周波数も標準的な50Hzです。
接続はモーターへの電源、そしてM5stackからのPWM制御信号です。GNDの共有を忘れずに。当然モーターの電源は大電流なので外部電源で5Vを使います。PWMは多くの他の信号がそうであるように3.3V振幅ですが、入力はどうせC-MOSだろうから問題なし。
https://coskxlabsite.stars.ne.jp/html/for_students/M5Stack/RCServo/RCServo.html
PWMピンは上記を参照してDIOの2ピン目を使用。
動作確認用のソースはHiwonderのwebページからですが、サーボモーター用のライブラリは使ってません。存在しないのかもしれませんが、直接コードを書く方が動作の理解には助けになります。
https://drive.google.com/drive/folders/1Bgf1HGrfhB8N8XIxlRpz-U9_2oxVurDv
Arduino用なので多少の修正が必要なのと、画面表示がないと電源オンもわからないのでメッセージを出すようにしてます。ライブラリを使わないと、動作時間制御もコードで指定(この場合には20ms*20 = 400ms)しています。試しに9行目の20を10にすると90度ぐらいしか回転しません。
/*******舵机测试程序*******
* Arduino型号:Arduino UNO
**************************/
#include <m5stack.h> // M5stack needs this module
int servopin=2;
int pulsewidth;
void servo(int myangle)
{
for (int i = 0; i < 20; i ++) // i is used to make moving time, since this source does not use library.
{
pulsewidth=map(myangle,0,180,500,2500);
digitalWrite(servopin,HIGH);
delayMicroseconds(pulsewidth);
digitalWrite(servopin,LOW);
delay(20-pulsewidth/1000);
}
}
void setup()
{
pinMode(servopin,OUTPUT);
M5.begin();
M5.Lcd.fillScreen(BLACK); //Set the screen background color to black.
M5.Lcd.setTextColor(GREEN , BLACK); //Sets the foreground color and background color of the displayed text.
M5.Lcd.setTextSize(2); //Set the font size.
}
void loop()
{
M5.Lcd.setCursor(0, 70);
M5.Lcd.printf("servo_motor drive");
servo(0);
delay(500);
servo(180);
delay(500);
}
駆動波形はこんな感じ。
動作時の動画は、
となります。180度以上振れてるようなので、キャリブレーションは必要そうです。
admin