「M5Atomで作る歩行ロボット」という本の犬型ロボットの製作記です。

前回、WiiのヌンチャクとM5Atom LITE(以降LITE)を接続しましたが、今回は、ヌンチャクのコントローラーの状態やどのボタンが押されていたかを、LITEで読み取る部分を作ったところをまとめます。ヌンチャクが純正品でなかったため結構苦労しました。

開発環境の構築

LITEのプログラムを作るために、Arduino IDEというソフトを使います。

まず、Arduinoのサイトからダウンロードしてインストールしました。

初めに、ボードマネージャーの設定です。以下の場所に、URLを入力します。

Preference>settings>additional boards manager URLs:

URL: https://m5stack.oss-cn-shenzhen.aliyuncs.com

/resource/arduino/package_m5stack_index.json

そして、ボードをインストールします。

Tools>Board>BoardManager>

5Stack を検索してインストール

ライブラリを追加します。

Tools>Manage Libraries

M5Atom をインストール。

Windowsのデバイスマネージャーを開き、LITEをUSBで接続して、COMポートの番号を確認します。自分の場合はCOM3でした。

COMポートの設定をします。

Tools>Port>COM3

Select Board で、COM3>M5Atomを選ぶ。

LEDの点灯テスト

簡単なプログラムが動くかをテストします。

開始すると、LEDが白になり、1秒後に消えます。LEDのボタンを押すと赤が点灯します。また押すと、緑、青、消灯、赤、と、切り替わるプログラムです。

#include "M5Atom.h"

void setup() {
    M5.begin(true, false, true); // M5Atomの初期化
    delay(50);                   
    M5.dis.drawpix(0, 0xffffff); //白
    delay(1000);
    M5.dis.drawpix(0, 0x000000); //消す
    Serial.print("start\n");
}

uint8_t CNT = 0;

void loop() {
    if (M5.Btn.wasPressed()) {  // キーが押された
        switch (CNT) {
            case 0:
                M5.dis.drawpix(0, 0xff0000);  // 赤
                Serial.print("red\n");
                break;
            case 1:
                M5.dis.drawpix(0, 0x00ff00);  // 緑
                Serial.print("green\n");
                break;
            case 2:
                M5.dis.drawpix(0, 0x0000ff);  // 青
                Serial.print("blue\n");
                break;
            case 3:
                M5.dis.drawpix(0, 0x000000);  // 消す
                Serial.print("off\n");
                break;
            default:
                break;
        }
        CNT++;
        if (CNT >= 4) {
            CNT = 0;
        }
    }
    delay(50);
    M5.update();  // キーの状態を更新
}Code language: PHP (php)

「→」ボタンでコンパイルと転送と実行が行われます。

Tools>Serial Monitor で、シリアルモニターを表示し、右端のドロップメニューから、600 bund を選ぶと、ボタンを押すたびに、色の名前が表示されます。

ヌンチャクの信号をI2Cで受け取る

「M5Atomで作る歩行ロボット」では、github でプログラムを公開してくれています。そのなかのLITE用のコードは、ヌンチャクのボタン操作の情報を、wifi経由でROSノードに情報を送るように作られています。ここではまず、ヌンチャクの情報がLITEで取得できることを確認したいので、その部分を抜き出したコードを作りました。

が、ヌンチャクが純正品でなかったためか、取得がうまくいきませんでした。数値はとれるのですが、十字キーをゆっくり左から右へ動かすと、数値が増減を繰り返してしまうような現象がみられました。いろいろ調べたり試したところ、デコーディングの部分をコメントアウトするとうまくいくことがわかりました。

最終的にコードを整えて、十字キーのx, y のアナログ値、x, y, z 方向の加速度、cボタン、zボタンのON/OFFが取得できることが確認できました。

#include "M5Atom.h"
#include <Wire.h>

int loop_cnt=0;
static uint8_t nunchuck_buf[6];   // ヌンチャクの状態保存用バッファ

void setup() {
  M5.begin(true, false, true); // M5Atomの初期化(シリアル通信、I2C通信、ディスプレイの有効化)
  M5.dis.drawpix(0, 0x00ff00); // LEDを緑に点灯

  Serial.begin(19200); // シリアル通信の開始
  Wire.begin(19, 22); // M5AtomのSDAとSCLピンを指定してI2Cバスに参加
  Wire.beginTransmission(0x52); // デバイス0x52にデータを送信
  Wire.write((uint8_t)0x40); // メモリアドレスを送信
  Wire.write((uint8_t)0x00); // 0を送信
  Wire.endTransmission(); // 送信を終了
}

// ヌンチャクにデータをリクエストする
static void nunchuck_send_request()
{
    Wire.beginTransmission(0x52);// transmit to device 0x52
    Wire.write((uint8_t)0x00);// sends one byte
    Wire.endTransmission();// stop transmitting
}

// データのデコーディング
static char nunchuk_decode_byte (char x)
{
    // x = (x ^ 0x17) + 0x17; // 純正品は必要
    return x;
}

// ヌンチャクからデータを受信する
static int nunchuck_get_data()
{
    int cnt=0;
    Wire.requestFrom (0x52, 6);// request data from nunchuck
    while (Wire.available ()) {
        // receive byte as an integer
        nunchuck_buf[cnt] = nunchuk_decode_byte( Wire.read() );
        cnt++;
    }
    nunchuck_send_request();  // send request for next data payload
    // If we recieved the 6 bytes, then go print them
    if (cnt >= 5) {
        return 1;   // success
    }
    return 0; //failure
}

// returns zbutton state: 1=pressed, 0=notpressed
static int nunchuck_zbutton()
{
    return ((nunchuck_buf[5] >> 0) & 1) ? 0 : 1;
}

// returns zbutton state: 1=pressed, 0=notpressed
static int nunchuck_cbutton()
{
    return ((nunchuck_buf[5] >> 1) & 1) ? 0 : 1;
}

// returns value of x-axis joystick
static int nunchuck_joyx()
{
    return nunchuck_buf[0]; 
}

// returns value of y-axis joystick
static int nunchuck_joyy()
{
    return nunchuck_buf[1];
}

// returns value of x-axis accelerometer
static int nunchuck_accelx()
{
    return nunchuck_buf[2];
}

// returns value of y-axis accelerometer
static int nunchuck_accely()
{
    return nunchuck_buf[3];
}

// returns value of z-axis accelerometer
static int nunchuck_accelz()
{
    return nunchuck_buf[4]; 
}


void loop() {
    nunchuck_get_data();

    int zbut = nunchuck_zbutton();
    int cbut = nunchuck_cbutton(); 
    int joyx = map(nunchuck_joyx(),3,252,-15,15);  // -15, 15の範囲に変換
    int joyy = map(nunchuck_joyy(),2,253,-15,15);  // -15, 15の範囲に変換
    int accx = map(nunchuck_accelx(),0,255,-15,15);
    int accy = map(nunchuck_accely(),0,255,-15,15);
    int accz = map(nunchuck_accelz(),0,255,-15,15);
    
    Serial.print("zbut:"); Serial.print(zbut * 10); Serial.print(",");
    Serial.print("cbut:"); Serial.print(cbut * -10); Serial.print(",");
    Serial.print("joyx:"); Serial.print(joyx); Serial.print(",");
    Serial.print("joyy:"); Serial.print(joyy); Serial.print(",");
    Serial.print("accx:"); Serial.print(accx); Serial.print(",");
    Serial.print("accy:"); Serial.print(accy); Serial.print(",");
    // Serial.print("accz:"); Serial.print(accz); Serial.print(","); // 表示しきれないためにコメントアウト

    Serial.print("min:"); Serial.print(-20); Serial.print(","); // グラフ表示用
    Serial.print("max:"); Serial.print(20); //グラフ表示用
    Serial.print("\n");
    
    delay(20);
}Code language: C++ (cpp)

ちなみに動画で表示しているグラフは、Aruduino IDE 2.3.3 についていたSerial Plotter という機能で表示しています。こちらのブログで使い方を解説してくれています。