Ubuntu Weekly Recipe

第684回 UbuntuからRaspberry Pi Picoを使う

この記事を読むのに必要な時間:およそ 7.5 分

USBシリアルコンソールを使ってみる

これだけだと最初の結果と同じなので味気ないですね。せっかくなのでPicoからなにか表示させてみましょう。Picoには複数のUARTピンがあります。さらにFlash書き込み・給電用に使っているUSBポートにつながっているコントローラーは,ホストとしてもデバイスとしても振る舞えます。そこで余計な配線を省いてテストするために,⁠USBポートからUSBシリアルコンソールとしてデータを出力するファームウェア」を作ってみましょう。

もちろんこれも,pico-examplesにすでに存在します。hello_world/usbがそれです。ちなみにhello_world/serialを使えば,USBではなくてUART0に出力します。

$ cd ../hello_world/usb/
$ make -j $(nproc)
(中略)
[ 50%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/home/ubuntu/pico-sdk/src/rp2_common/pico_stdio/stdio.c.obj
[ 50%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/home/ubuntu/pico-sdk/src/rp2_common/pico_stdio_usb/reset_interface.c.obj
[ 50%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/home/ubuntu/pico-sdk/src/rp2_common/pico_stdio_usb/stdio_usb.c.obj
[ 50%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/home/ubuntu/pico-sdk/src/rp2_common/pico_stdio_usb/stdio_usb_descriptors.c.obj
[ 50%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/home/ubuntu/pico-sdk/lib/tinyusb/src/portable/raspberrypi/rp2040/dcd_rp2040.c.obj
(中略)
[100%] Linking CXX executable hello_usb.elf
[100%] Built target hello_usb

pico-sdkのほうでstdio_usb.ctinyusbもセットでビルドされていることがわかりますね。実際,pico-examplesのほうのコードはシンプルでUSBシリアルコンソールを使うかどうかをビルドオプションで設定しているだけであり,USBシリアルコンソールに関するコードはpico-sdkのほうに存在します。

作成されたhello_usb.uf2をUSBマスストレージ経由でPicoに書き込んでください。自動的に再起動し,今度はLEDは点滅しなくなるはずです。

PicoにUSBシリアルコンソールとして接続しましょう。hello_usb.uf2が動いている場合,PCからはUSBコミュニケーションデバイスクラスとして認識され,/dev/ttyACM0が作成されます。このデバイスはudevルールによって,rootとdialoutグループにのみ書き込み権限が与えられています※5⁠。よって次のようにdialoutグループに所属するか,sudo経由でアクセスする必要があります。

※5
シリアルポートとudevの関係は第555回「いま,あらためてudev」3ページ目でも説明していますので,詳しい仕組みはそちらを参照してください。
$ sudo usermod -a -G dialout $(whoami)

dialoutグループへの参加は一度ログインしなおすことで,変更が反映されます。idコマンドで確認してみてください。ちなみにdialoutグループに追加したあと,次のようにnewgrpコマンドを実行すると,ログインし直さなくても一時的にプライマリーグループをdialoutに変更できます。

$ newgrp dialout

/dev/ttyACM0へのアクセス権限が得られたので,次はシリアルコンソール接続用のソフトウェアを動かします。minicom,ckermit,picocom,screenなどなど多種多様な選択肢が存在しますが,ここではpicocomを使ってみましょう。

$ sudo apt install picocom
$ picocom /dev/ttyACM0 -b 115200
picocom v3.1
(中略)
Type [C-a] [C-h] to see available commands
Terminal ready
Hello, world!
Hello, world!

(picocomを終了するためにはCtrl-a Ctrl-xを入力)

Terminating...
Thanks for using picocom

ひたすら「Hello, world!」と表示し続けていたら成功です。これによりPicoが,⁠その電力が続く限り世界に挨拶をし続ける」という,狂気のデバイスへと生まれ変わりました。

Picoを姿勢測定デバイスとして動かす

既存のRaspberry Piと比べるとPicoは,単体でできることが限られています。その真価は,各種IOポートにいろいろなデバイスを接続することで発揮できるのです。

すでにPico向けのさまざまなオプションボードが登場しています。そこで今回は最後にWaveshareのセンサーデバイスであるPico-10DOF-IMUを使ってみましょう。これはそれぞれ3軸の加速度センサー・ジャイロセンサー・地磁気センサーを備えたICM-20948と気圧・気温センサーであるLPS22HBを搭載したPico向けのボードで,ピンヘッダがついているPicoであれば接続してすぐ利用できます※6⁠。

※6
9軸センサー+気圧・気温なら10DoFじゃなくて11DoFでは?とも思うかもしれませんが,気圧は気温で補正しているので,おそらくここは1自由度扱いなのだと思います。ちなみに今回は使用しませんが,ICM-20948のほうにも気温センサーが搭載されています。

もちろんPico用のサンプルコードもあるので,⁠とりあえず試す」だけならファームウェアをビルドして書き込むだけで済みます。

$ sudo apt install unzip
$ wget https://www.waveshare.com/w/upload/3/3d/Pico-10dof-imu.zip
$ unzip Pico-10dof-imu.zip

サンプルコードはC言語向けとMicroPython向けが用意されています。Picoは公式にMicroPythonもサポートしており,Pythonスクリプトを実行するだけでなくインタープリター環境を持ったファームウェアを書き込むことも可能です。今回はC言語のほうを使うことにします。

$ cd pico-10dof-imu/c/build/
$ cmake ..
Using PICO_SDK_PATH from environment ('/home/ubuntu/pico-sdk')
PICO_SDK_PATH is /home/ubuntu/pico-sdk
Defaulting PICO_PLATFORM to rp2040 since not specified.
Defaulting PICO platform compiler to pico_arm_gcc since not specified.
-- Defaulting build type to 'Release' since not specified.
PICO compiler is pico_arm_gcc
-- The C compiler identification is GNU 9.2.1
-- The CXX compiler identification is GNU 9.2.1
-- The ASM compiler identification is GNU
-- Found assembler: /usr/bin/arm-none-eabi-gcc
Defaulting PICO target board to pico since not specified.
Using board configuration from /home/ubuntu/pico-sdk/src/boards/include/boards/pico.h
-- Found Python3: /usr/bin/python3.8 (found version "3.8.10") found components: Interpreter
TinyUSB available at /home/ubuntu/pico-sdk/lib/tinyusb/src/portable/raspberrypi/rp2040; adding USB support.
-- Configuring done
-- Generating done
-- Build files have been written to: /home/ubuntu/pico-10dof-imu/c/build

$ make -j $(nproc)
(中略)
[100%] Linking CXX executable imu.elf
[100%] Built target imu

このあたりはpico-examplesと手順は同じですね。最終的にimu.uf2が作られるため,これをPicoに書き込んでください。

このファームウェアはUSBシリアルとUART0の両方に出力する設定になっています。具体的にはpico-10dof-imu/c/CMakeLists.txtの次の記述が該当します。

pico_enable_stdio_usb(imu 1)
pico_enable_stdio_uart(imu 1)

そこで「USBシリアルを使ってみる」と同じように,/dev/ttyACM0にpicocomで接続してみます。

$ picocom /dev/ttyACM0 -b 115200
picocom v3.1
(中略)
 /-------------------------------------------------------------/

 Roll: 2.62     Pitch: -1.49     Yaw: -158.66
Pressure = 999.34 hPa , Temperature =  31.46 °C

 /-------------------------------------------------------------/

 Roll: 2.57     Pitch: -1.44     Yaw: -158.57
Pressure = 999.33 hPa , Temperature =  31.45 °C

100ms周期で,⁠各軸の回転角度と気圧・気温」を表示してくれていることがわかります。

ロール(Roll)はX軸の回転角度で,ピッチ(Pitch)がY軸,ヨー(Yaw)がZ軸になります。デバイスに対してXYZ軸がどちらを向いているのかはPico-10DOF-IMUのボード上に記載されています。ただしPicoに接続してしまうと隠れてしまうので注意が必要です。回路図のPDFのPDFにも記載されているため,そちらを参照すると良いでしょう。USBコネクタのシルクがある面を見て,USBコネクタのシルクが上にある状態にしたときに,向かって右方向がX軸の正の向き,上方向がY軸の正の向き,手前方向がZ軸の正の向きになるようです(いわゆる右手系です⁠⁠。

実際に上記の出力を眺めながら個々の軸を回転させるとイメージがつかめると思います。

pico-10dof-imu/c/main.cが本体のコードです。ここから中身を見ていくと良いでしょう。たとえば,メインループの中では次のように,各センサーの生データの出力がコメントアウトされています。

                printf("\r\n /-------------------------------------------------------------/ \r\n");
                printf("\r\n Roll: %.2f     Pitch: %.2f     Yaw: %.2f \r\n",stAngles.fRoll, stAngles.fPitch, stAngles.fYaw);
           printf("Pressure = %6.2f hPa , Temperature = %6.2f °C\r\n", PRESS_DATA, TEMP_DATA);
                //printf("\r\n Acceleration: X: %d     Y: %d     Z: %d \r\n",stAccelRawData.s16X, stAccelRawData.s16Y, stAccelRawData.s16Z);
                //printf("\r\n Gyroscope: X: %d     Y: %d     Z: %d \r\n",stGyroRawData.s16X, stGyroRawData.s16Y, stGyroRawData.s16Z);
                //printf("\r\n Magnetic: X: %d     Y: %d     Z: %d \r\n",stMagnRawData.s16X, stMagnRawData.s16Y, stMagnRawData.s16Z);
                sleep_ms(100);

これをコメントアウトを外して//を削除して⁠⁠,再ビルドし(makeを実行し⁠⁠,ファームウェアを書き込むと次のような結果が得られます。

 Roll: 1.45     Pitch: 0.38     Yaw: -174.00
Pressure = 1004.02 hPa , Temperature =  26.06 °C

 Acceleration: X: -234     Y: -198     Z: 16970

 Gyroscope: X: 8     Y: 2     Z: -9

 Magnetic: X: 97     Y: -41     Z: -504

Pioc-10DOF-IMUのコードは本当にサンプルと言うべきシンプルなものなので,これをとっかかりにしていろいろカスタマイズすると良いでしょう。サンプルコードはクォータニオンの計算をソフトウェア側で行っています。ICM-20948にはDMP(Digital Motion Processor)と呼ばれる,このあたりの計算を行ってくれるプロセッサーが搭載されています。DMPを使うようにするのもおもしろいかもしれませんね※7⁠。

※7
ちなみにSparkfunのICM-20948を搭載したボード用のコードにはDMPに関する詳しい情報が記載されています。

著者プロフィール

柴田充也(しばたみつや)

Ubuntu Japanese Team Member株式会社 創夢所属。数年前にLaunchpad上でStellariumの翻訳をしたことがきっかけで,Ubuntuの翻訳にも関わるようになりました。