Atom Liteを使ってロボットの起動音を作ってみた – TANG制作記録Part6

AgriRobotics

blog

Atom Liteを使ってロボットの起動音を作ってみた – TANG制作記録Part6

TANG制作記録
Atom LiteTANG

はじめに、、

お久しぶりの投稿です。TANGちゃんの開発はブログには全然書けていないですが、元気に続けています。去年の12月には実証実験も行ったので、その内容もぜひブログに書きたいです。きっと書きます。きっとです。

今回の記事では、Atom Liteを使ってロボットの起動音を作ってみたので、ただブザーを鳴らす方法からRaspberry Pi 4とAtom Liteが通信してロボットの起動音を鳴らすまでの実践的な方法まで解説していきたいと思います。

今回作ったロボットの起動音→モード切替の音

やりたいこと

ざっくりと図で書いてみました。

使用した部品

Atom Liteの開発環境構築

Atom Liteの開発環境は以下の3つが用意されています。

  • ArudinoIDE
  • UIFlow
  • MicroPython

詳細は公式チュートリアルに記載されています。自分は3つとも試してみましたが、普段からPythonを書くのに慣れているのもあってMicroPythonで開発しました。
UIFlowは初めてでしたが、プログラムを書かずにあらかじめ定義された処理、例えば「ブザーを鳴らす」「1秒間停止する」のような処理をブラウザ上でマウスでポチポチするだけでプログラムを実行することができるので驚きでした。

MicroPythonの開発環境は、基本的には公式チュートリアルに沿って進めていけば問題ないです。
本記事でも補足を交えながら書いていきますね。

  1. USB driverのインストール
    Atom LiteをPCに接続後、正常に認識できるようにUbuntuが入ったPCにUSB driverをインストールします。
    まずFTDI driverを公式サイトからダウンロードするためにこちらのリンクにアクセスします。
    そして、下にスクロールしてLinuxの項目の中のReadMeと書かれた箇所をクリックします。

    開いたPDFに書かれたインストール手順1~7を上から順番に行っていきます。
    これでUSB driverのインストールは完了です。
  2. Building toolのインストールと設定
    次は、ファームウェアを書き込むためのツールをインストールします。下記画像のLinuxと書かれた項目のDownloadをクリックして、ツールをインストールします。
    その後の手順は公式チュートリアルとほぼ同じなので割愛します。

    ただ、UIFlow Configurationの項目で、公式チュートリアルではStart ModeがInternet Modeになっていますが、USB modeに変更しておいてください。
    Internet Modeはブラウザ上でUIFlowを使ってプログラムを書き込むときに設定する必要がありますが、今回はUSB Type-Cを介してプログラムを書き込むのでModeは変更しておく必要があります。
  3. VSCodeのインストールと設定
    最後に、MicroPythonでプログラムを書くためにVSCodeをインストールします。
    インストールは下記画像のDownload. VSCode IDEをクリックすれば実行されます。
    ただ、これだけではAtom Liteにプログラムの書き込みや実行はできないです。
    追加で下記画像のように「vscode-m5stack-mpy」というプラグインをインストールします。VSCodeの拡張プラグインをインストールするアイコンをクリックし、「M5Stack」と検索してvscode-m5stack-mpyが出てくるはずなので、それをインストールしてください。
    ここまでで開発環境の構築は完了です。

ロボットの起動音を作ってみる


では、実際にプログラムを書いてみましょう。
最初にUbuntuが入ったPCとAtom LiteをUSB Type-Cケーブルで接続します。
次に、先ほどインストールしたVSCodeを開いて、公式チュートリアルの「Connect to Device.」に沿ってAtom Liteのプログラムを開けるようにします。
そして、次にAtom Lite内のプログラムの書き換えを行います。
下記画像のように最初はboot.py, main.py, test.pyがあらかじめ用意されているはずです。
boot.pyにプログラムを書くことで、Atom Liteに電源が入るもしくは、本体中心にあるリセットボタンを押したときにプログラムが実行されます。今回は、このboot.pyを書き換えていきます。

実際のプログラムは下記のとおりです。

from machine import Pin, PWM
import time

frequency = 440
duty = 0.1
pwm = PWM(Pin(26), frequency, duty) # create and configure in one go
time.sleep(1.0)
pwm.duty(0)

簡単にコードの補足をします。
machineモジュールは、MicroPython特有のモジュールで、このモジュールを使ってGPIOやPWMの関数を呼び出します。

from machine import Pin, PWM

次に、ブザーの音量をPWMで指定して音を鳴らします。
machineモジュールのPWM関数は、第一引数にどのピンをPWMピンとするか、第2引数に周波数frequency、第3引数にduty比を設定します。
周波数を変えることで音の高低を変更できることができ、duty比を変えることで音量を変えることができます。duty比は0~10まで設定が可能です。

frequency = 440
duty = 0.1
pwm = PWM(Pin(26), frequency, duty) # create and configure in one go
time.sleep(1.0)
pwm.duty(0)

あとは、これを画面右上にある再生ボタンを押してAtom Liteに書き込めば完了です。
リセットボタンを押すごとにブザーが鳴ります。

ここまでが、Atom Liteを使ってブザーを鳴らすまでのやり方です。

次にもう少しロボットの起動音にふさわしい音を作ってみましょう。
実際の音は動画を再生してみてください。

ロボットの起動音はお掃除ロボットルンバの起動音を参考にしてみました。
また、起動後の2種類の音はモード切替を行った時の音です。
詳細なコードは次の章で書いています。

次は、もう少し実際のロボットに使うためのやり方をご紹介しますね。

Raspberry Pi 4と通信してロボットの起動音を鳴らす

では、実際のロボットで使えるようにRaspberry Pi 4とAtom Liteで通信して、ロボットの起動音やモード切替音を鳴らします。

具体的にはAtom LiteのUARTピンを使い、USBシリアル変換モジュールを介してRaspberry Pi 4に接続します。

では、実際にRaspberry Pi 4→Atom LiteにUART通信を使って指令を送ってAtom Liteのブザーを鳴らします。
まず送信する側(Raspberry Pi 4)のコード(atom_lite.py)を紹介します。

import serial
import time

usb_device = serial.Serial('/dev/ttyUSB0', '9600', timeout=1.0)

def main():
    command = "HumanFollow"
    while(True):
        try:
            print("Write signal")
            usb_device.write(command.encode())
            time.sleep(1.0)
        except:
            print("close usb_device", flush=True)
            usb_device.close()
            return

if __name__ == "__main__":
    main()

上記のコードを実行します。実行するときのコマンドは以下の通りです。

$ sudo chmod 777 /dev/ttyUSB0
$ python3 atom_lite.py

次に受信する側(Atom Lite)のコードについてです。
以下の3つのコードをAtom Liteに書き込みます。
config.pyは、音の高さの設定をあらかじめ書いておくファイルです。
robot_music.pyは、ロボットの起動音を設定しておくファイルです。ロボットの起動音と、今回の自分のロボットの場合は、人追従モードと手動モードの2種類あるので、それぞれのモードに対しても音を設定しておきます。
また、MicroPythonでUART通信を行うコードを書くときは、machineライブラリのUART関数を使いました。引数でtxピン、rxピンを指定することで通信することができます。
さらに、PWM関数やUART関数の中身を調べる際はこちらの公式ドキュメントも参考にしました。

class MusicScale():
    do = 1046
    re = 587
    so = 1567
    do_high = 2000
    do_low = 261
import time
from machine import Pin, PWM

import config

music_scale = config.MusicScale()

class RobotMusic:
    def __init__(self, pin, duty):
        self.pin  = pin
        self.duty = duty

    def bringup_music(self):
        pwm = PWM(Pin(self.pin), music_scale.so, self.duty) 
        time.sleep(0.4)
        pwm.duty(0)
        pwm = PWM(Pin(self.pin), music_scale.do, self.duty) 
        time.sleep(0.4)
        pwm.duty(0)
        pwm = PWM(Pin(self.pin), music_scale.re, self.duty) 
        time.sleep(0.4)
        pwm.duty(0)
        pwm = PWM(Pin(self.pin), music_scale.so, self.duty) 
        time.sleep(1.0)
        pwm.duty(0)
        time.sleep(0.1)
        pwm = PWM(Pin(self.pin), music_scale.so, self.duty) 
        time.sleep(1.0)
        pwm.duty(0)
        time.sleep(0.1)
        pwm = PWM(Pin(self.pin), music_scale.so, self.duty) 
        time.sleep(1.0)
        pwm.duty(0)
        time.sleep(0.1)

    def follow_mode_music(self):
        pwm = PWM(Pin(self.pin), music_scale.do, self.duty)
        time.sleep(0.2)
        pwm.duty(0)
        pwm = PWM(Pin(self.pin), music_scale.do_high, self.duty)
        time.sleep(0.1)
        pwm.duty(0)

    def manual_mode_music(self):
        pwm = PWM(Pin(self.pin), music_scale.do_high, self.duty) 
        time.sleep(0.2)
        pwm.duty(0)
        pwm = PWM(Pin(self.pin), music_scale.do, self.duty)
        time.sleep(0.1)
        pwm.duty(0)
from machine import Pin, PWM, UART
import time
import robot_music

sound  = robot_music.RobotMusic(26, 0.1)
sound.bringup_music()

# Create a serial port instance
uart1 = machine.UART(1, tx=22, rx=19)

# Initialize the serial port
uart1.init(9600, bits=8, parity=None, stop=1)

# Is there any content in the cache?
uart1.any()

# Read the content in the buffer area
uart1.read()

# Write content to the serial port
uart1.write('Hello')

# Read/write case
while True:
    if uart1.any():
        data = uart1.read()
        decoded_data = data.decode('utf-8')
        if(decoded_data == "HumanFollow"):
            sound.follow_mode_music()
        elif(decoded_data == "Manual"):
            sound.manual_mode_music()
        else:
            uart1.write(decoded_data)
    pwm = PWM(Pin(26), 440, 0.5)
    time.sleep(0.2)
    pwm.duty(0)
    time.sleep(0.5)

以下の動画は、ロボットが起動してモード切替を行うまでを模したデモです。
これで、ロボットの電源が入ると同時にAtom Liteの電源も入り、ロボットの起動音を鳴ります。
次にロボットのモードに応じて音を変えて、作業者にモードが切り替わっているかどうかを知らせることができます。
動画内ではひたすら「Manual」という文字列をラズパイからAtom Liteに送って、文字列を受け取ったAtom Liteはその文字列に応じた音を鳴らします。

まとめ

今回は、Atom Liteを使ってロボットの起動音を作ってみました。
自分は、今回で初めてM5Stack系を触ってみました。最初の環境構築では、初めてのことが多かったので躓くときもありました。また、Atom Lite+MicroPythonの資料がネット上でそこまで多く見つけられなかったので、今回の記事が誰かの役に立てれば幸いです。