自作ドローンの製作記録 〜Part 3 ラズパイ接続〜
こんにちは、Tomofilesです。
ラズパイ4(Raspberry Pi 4 Model B RAM4GB 国内技適版)を手に入れたので、早速ドローンのコンパニオンコンピュータとして使ってみました。
私が持っていたのは初代ラズパイなのですが、RAMが4GBになって、CPUも64bit対応になっていて、すごい進化してるんだなぁと驚きました。
消費電力(電流量)が上がってきているそうで、性能の向上と消費電力の増加のトレードオフでラズパイ4を使用するかどうか判断する必要がありそうですね。
Pixhawkとコンパニオンコンピュータの接続について、まだ説明していなかったので、今回はラズパイ4を使用してドローンのデータを取得してみたいと思います。
Raspberry Pi 4 Model B RAM4GB
ラズパイ4は今年の6月に発売されましたが、国内の技適を通過して技適マーク印字のモデルが発売されたのは11月でした。
私は以下のサイトで購入しました。(Amazonで電子部品を買うのに少し恐怖心を覚えるようになりました 笑)
価格は7,700円です。ラズパイって5,000円のイメージがあるので、ちょっと値段が上がってますね。
それでも、これだけの機能を備えたシングルボードコンピュータが1万円切っているのは、十分お得です。(機能をフルに活用できる自信ないですし)
それでは早速、ラズパイ4をセットアップしていきましょう。
Ubuntu Serverをインストール
まずはOSをラズパイ4のSDカードにインストールします。
今回はUbuntu Server for Raspberry Piを使用します。
Raspbianと迷ったのですが、もしかしたらROSにも挑戦することになるかもと考えて、Ubuntuを選びました。Dronecodeの推奨開発環境とも一致しますしね。
Ubuntu Serverは以下からダウンロードします。
記事執筆時点で19.10が最新バージョンでした。32bit版を選んでください。
Install Ubuntu Server on a Raspberry Pi 2, 3 or 4 | Ubuntu
ダウンロードしたら、インストールします。
私は、Dronecodeの開発環境がUbuntu Desktopなので、「On Ubuntu」の手順に従ってインストールしました。
Create installation media for Ubuntu | Ubuntu
ddコマンドでSDカードに書き込むので、書き込み先のデバイスを間違えないように注意してください。
ちなみに私は、GNOME DisksのGUIアプリからデバイス名を確認して実施しました。視覚的に確認できますし、念には念を入れてしっかりと確認しておきます。
私のPCでのデバイス名は、/dev/sdcとなっていました。
私が実際に実行した書き込みコマンドは以下です。
#念のため、書き込み先デバイス名を全角にしています $ xzcat ~/Downloads/ubuntu-19.10.1-preinstalled-server-armhf+raspi3.img.xz | sudo dd of=/dev/sdc=32M $ sync
手順にもある通り、syncコマンドを忘れないようにしてください。
私は見逃して、OSが非同期で書き込み中にSDカードを取り外してしましました 笑
ラズパイ4をセットアップ
インストールが完了したら、SDカードをラズパイ4に差し込んで、電源を入れます。
初回起動時にパスワード変更を求められるので、任意のフレーズに変更してください。
シリアルポートの開放
Pixhawkとラズパイ4を接続するには、GPIOのシリアルポートを使用します。
シリアルポートは/dev/ttyAMA0を使用するのですが、このデバイスファイルはデフォルトではBluetoothが使用しており、代わりにGPIOのシリアルポートは/dev/ttyS0に設定されています。
今回はBluetoothは使用しないので、無効に設定することでOSがGPIOのシリアルポートに/dev/ttyAMA0を割り当ててくれます。
Bluetoothの無効
Bluetoothを無効にするには、/boot/firmware/config.txtに以下の無効設定を追加します。
# disable bluetooth dtoverlay=pi3-disable-bt
この設定でUbuntuを再起動すると、GPIOのシリアルポートが/dev/ttyAMA0に変更されます。
ここまでの設定で、PixhawkをGPIOのシリアルポートに接続すると、/dev/ttyAMA0のデバイスファイルでMavlinkパケットを読み込めるようになります。
ただ、接続してすぐわかるのですが、継続してコンソールに謎のメッセージが表示され始めます。(SSH接続じゃなくて、実機でログインしていると表示されます)
最初はこういうものかと思いましたが、少しコンソールの挙動がおかしく見えていて不安に思っていたところ、最終的にカーネルパニックになってしまいました。
シリアル接続で受信したパケットが標準入力に流れ込んでいるように見えます。
シリアルコンソールの無効
raspiとpixhawkをuartで接続したら、信号を送受信してんのは確認できたけど、そのまま標準入力に影響を与えてるのか、OSがクラッシュする。色んな壁にぶち当たるなぁ、楽しい 笑
— Tomofiles (@tomofiles) 2019年12月9日
あー、ちょっとわかってきたぞ。
— Tomofiles (@tomofiles) 2019年12月10日
シリアルコンソールが有効になってるから、uartの信号が入出力に流れてるんだ。ネット上のarduinoとの接続方法の記事に、ヒントがあった。 https://t.co/IBKMeJnKWT
ちょっと調べたところ、シリアルコンソールという機能が有効になっていました。
シリアルコンソールはシリアルポートからログインできる機能のようで、障害時などSSHができない場合などでもログインできるなどの用途があるようですが、まぁこれも今回は不要かなと思うので無効にします。
以下のようにプロセスを確認すると、シリアルコンソールが起動してます。
$ ps aux | grep ttyAMA0 root 1229 0.0 0.0 5376 1528 ? Ss+ 14:33 0:00 /sbin/agetty -o -p -- \u --keep-baud 115200,38400,9600 ttyAMA0 vt220 ubuntu 1488 0.0 0.0 5944 508 pts/0 S+ 14:35 0:00 grep --color=auto ttyAMA0
シリアルコンソールも、/boot配下のファイルを編集して無効にします。
私の環境では、/boot配下でttyAMA0をコンソール設定している設定ファイルが、以下の2つ存在しました。
$ sudo grep -r ttyAMA0 /boot /boot/config-5.3.0-1014-raspi2:CONFIG_CMDLINE="console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait" 〜〜省略〜〜 /boot/firmware/nobtcmd.txt:net.ifnames=0 dwc_otg.lpm_enable=0 console=ttyAMA0,115200 console=tty1 root=LABEL=writable rootfstype=ext4 elevator=deadline rootwait fixrtc 〜〜省略〜〜
kgdbocはカーネルデバッガーという機能のようですが、詳細は調べてないので不明です。とりあえず無効にしちゃいます。
編集後は以下の通りです。
# /boot/config-5.3.0-1014-raspi2 CONFIG_CMDLINE="root=/dev/mmcblk0p2 rootfstype=ext4 rootwait"
# /boot/firmware/nobtcmd.txt net.ifnames=0 dwc_otg.lpm_enable=0 console=tty1 root=LABEL=writable rootfstype=ext4 elevator=deadline rootwait fixrtc
再起動して、再度プロセスを確認します。
シリアルコンソールのプロセスが存在しなければ、設定完了です。
$ ps aux | grep ttyAMA0 ubuntu 1495 0.0 0.0 5944 560 pts/0 S+ 14:51 0:00 grep --color=auto ttyAMA0
Mavlinkパケットの受信を確認
Pixhawkをシリアルポートに接続して、Mavlinkパケットの受信を確認します。
シリアルポートの確認はscreenコマンドを使用します。
$ sudo screen /dev/ttyAMA0 921600
パケットはバイナリなので、以下のように文字化けして表示されます。
screenの処理を終了するには、「Ctrl + a→k→y」とキー入力してください。
なお、screenコマンド引数の921600はボーレートなのですが、PX4のパラメータで予め設定しておく必要があります。
QGCにPixhawkを接続して、パラメータから「SER_TELx_BAUD」を921600を選択します。
※xの部分は、PixhawkのTELEMの接続状況により、1や2で読み替えてください
なお、コンパニオンコンピュータに接続する際のパラメータは、以下のサイトを参照してください。
Pixhawkとラズパイ4の配線
順番が前後してしまってますが、Pixhawkとラズパイ4の接続方法を説明します。
Pixhawkとラズパイ4の物理的な接続方法は、検索すると結構出てきます。
ラズパイ4のGPIOから、Rx、Tx、GNDを使用して、PixhawkのTELEMxコネクタと接続します。
※各所に注意書きがあるように、5Vの電源コードは接続しないで下さい!
以下のサイトに掲載されている配線図がわかりやすいです。
Raspberry Piを使用したMAVLinkプロトコルによるドローン用フライトコントローラーPIXHAWKとの通信 | 暇村工房
TELEM用のケーブルは、Pixhawkに同梱のものを使用するか、ドローン自作キットの未使用のテレメトリーモジュールに同梱のケーブルを使用します。
私は未使用のテレメトリーモジュールのケーブルを使いました。
GPIOに接続するので、片方のコネクタを1ピン用のコネクタに取り替える必要があります。
私は、過去にラズパイ用のモジュールセットを買ったときに付属していたケーブルのコネクタを取り外し、Pixhawkのケーブルに繋ぎ直しました。(やっとはんだゴテの出番! 笑)
Mavsdkからシリアルポートに接続
さて、Mavlinkパケットの受信が確認できれば、あとはMavsdkからシリアルポートに接続することで、以下の記事でシミュレータに接続したように、Pixhawkに接続して、テレメトリーやミッションの送受信ができます。
この記事で使用したのは、Mavsdk Backend Serverというバイナリですが、ラズパイ4のアーキテクチャに合わせて、今回はarmv7版のMavsdkを使用します。
以下のサイトの「mavsdk_server_linux-armv7」をダウンロードします。
Releases · mavlink/MAVSDK · GitHub
この記事執筆時点では、v0.22.0が最新でした。
$ wget https://github.com/mavlink/MAVSDK/releases/download/v0.22.0/mavsdk_server_linux-armv7 # 権限を変えておく $ sudo chmod +x ./mavsdk_server_linux-armv7
シリアルポートへの接続は以下のように引数を指定して、Mavsdkを実行します。
が、エラーになりました。
$ ./mavsdk_server_linux-armv7 serial:///dev/ttyAMA0:921600 [03:23:18|Info ] MAVSDK version: 0.22.0 (mavsdk_impl.cpp:25) [03:23:18|Debug] New: System ID: 0 Comp ID: 0 (mavsdk_impl.cpp:390) [03:23:18|Info ] Server set to listen on 0.0.0.0:50051 (grpc_server.cpp:47) [03:23:18|Info ] Server started (grpc_server.cpp:31) [03:23:18|Info ] Waiting to discover system... (connection_initiator.h:58) [03:23:18|Debug] Component Autopilot (1) added. (system_impl.cpp:401) [03:23:18|Debug] Discovered 1 component(s) (UUID: 3546673849493043255) (system_impl.cpp:571) [03:23:18|Info ] System discovered [UUID: 3546673849493043255] (connection_initiator.h:62) Bus error (core dumped)
コアダンプ吐いて、バスエラーになっています。
ラズパイ4にログインして実行すると、もう少し情報が出力されます。
alignment trapという例外が発生しているようです。
シリアルコンソールを無効にしたらクラッシュしなくなったけど、今度はmavsdkがalignment trapで落ちるんだけど、送受信データがメモリを破壊してる?さっぱりわからん。。。 https://t.co/LSHGxZ5gxY
— Tomofiles (@tomofiles) 2019年12月10日
alignmentって何だっけってずっと考えてたけど、C言語やってたときに出てきたパディングとかのあれか。メモリに構造体のポインタを設定して直接データを読み取るやつ。すっかり忘れてた。
— Tomofiles (@tomofiles) 2019年12月11日
以下のサイトの説明で色々理解できました。
ARM gcc ¥Ð¥Ã¥É¥Î¥¦¥Ï¥¦½¸
※タイトルが文字化けしてしまっていますが、ホームページの文字コードの影響だと思いますので大丈夫です
過去の案件でC言語をやったときに、構造体のフィールドを4バイトを一つのブロックとして配置するように、パディングフィールドを定義していたのを思い出しました。
CPUによってはalignmentに厳格なものがあるそうで、ラズパイ4で使用しているARM系のCPUはまさにそうで、alignmentを無視したメモリアクセスをすると、例外が発生して落ちるらしいです。一応OSの機能でalignmentの例外ハンドラってのがあるそうですが、今回の状況では一切有効ではなかったです。
さて、これは困りました。
どうしましょうか。
Mavlink Router
raspiとpixhawk接続できた!!!
— Tomofiles (@tomofiles) 2019年12月11日
シリアル接続は結局cpuアーキテクチャの影響を受けて、どうしてもalignment trapでbus errorになってしまいました。そこで、mavlink routerでmavlinkパケットをudpで転送してみたら、mavsdk backend serverから接続できました。 https://t.co/EkLZttk5ni
シリアル接続は物理レイヤに依存しちゃうんですね、どうしても。受信したパケットをメモリに展開してるからでしょうかね。udpのようなソケット通信なら、物理レイヤを抽象化してるからいけるのではと踏んだのですが、当たったようです。
— Tomofiles (@tomofiles) 2019年12月11日
あぁ、もうこんな時間…
色々調べた結果、Mavlink Routerというソフトウェアモジュールを使用することで、解決することがわかりました。
(相変わらずDronecodeの公式サイトの説明は、ちょろっとしか書かれておらず、かつ、複数のページに分散していました)
Routing · MAVLink Developer Guide
github.com
このモジュールをビルド、インストールしてラズパイ上で実行したところ、Mavsdk Backend Serverから接続してテレメトリーの取得ができました。
Mavlink Routerのビルド・インストール
ビルド・インストール方法は、Githubの説明に記載されています。
基本的にその説明に沿ってコマンドを実行していけばいいですが、色々追加パッケージをインストールなどが必要だったので、その辺をまとめていきます。
まずは、gitでMavlink Routerのソースコードを取得します。
$ git clone git@github.com:intel/mavlink-router.git
$ cd mavlink-router/
それから、依存するサブモジュールの取得も行います。
$ git submodule update --init --recursive
ここからGithubの手順では、ビルドをしていくのですが、その過程で不足しているパッケージがいくつかあることがわかったので、先にインストールしておきます。
◆autoreconf
まず、autoreconfが無いと怒られます。
./autogen.sh: 9: autoreconf: not found
インストール方法は以下を参照しました。
【エラー】ラズベリーパイで「autoreconf: コマンドが見つかりません」と表示される
$ sudo apt-get update $ sudo apt-get upgrade $ sudo apt-get install dh-autoreconf
◆pkg-config
次はこちら。
エラーメッセージを読んだ限りでは、さっぱり理解できません。
autoreconfのエラーのようですが、深入りしても時間を浪費するだけなので、解決策だけ探しました。
configure.ac:55: error: possibly undefined macro: AC_CHECK_LIB If this token and others are legitimate, please use m4_pattern_allow. See the Autoconf documentation. autoreconf: /usr/bin/autoconf failed with exit status: 1
見つけたのがこちら。pkg-configをインストールしたら解決したとの情報があります。
試してみたところ、ビンゴでした。
autotools - possibly undefined macro: AC_MSG_ERROR - Stack Overflow
$ sudo apt-get install pkg-config
ということで、ビルドに入っていきます。
Mavlink Routerではconfigure/build/install cycleというビルドシステムを用いているようです。
まずは、ビルド用のMakefileを生成します。
$ ./autogen.sh && ./configure CFLAGS='-g -O2' --sysconfdir=/etc --localstatedir=/var --libdir=/usr/lib64 --prefix=/usr
Makefileが生成できていれば、あとはビルド・インストールです。
ビルドを行う前に、Pythonのセットアップをします。これをしないと、Pythonのモジュールが色々足りなくて、エラーになりました。
◆future
エラーメッセージはこちら。
futureモジュールが無いと怒られます。
ModuleNotFoundError: No module named 'future' make: *** [Makefile:1715: include/mavlink/ardupilotmega/mavlink.h] Error 1
Pythonモジュールをインストールするには、pipが必要です。
以下のサイトを参考に、pipをインストールします。
Ubuntuでpip / pip3がインストールできないときの対処法 | Python2 / 3 - 生物系がゼロから始めるIT技術
実際に実行したコマンドは、以下の通りです。
$ alias python="python3" $ python --version Python 3.7.5 $ sudo apt-get install python3-pip $ pip3 install future
Pythonの環境が整えば、あとはビルド・インストールを行うだけです。
$ make install
ビルド・インストールが完了したら、以下のコマンドでMavlink Routerを起動します。
$ ./mavlink-routerd -e localhost:14550 /dev/ttyAMA0:921600
"-e"オプションがエンドポイントで、UDPの14550ポートに/dev/ttyAMA0のパケットを転送する、という意味のコマンドになります。
サンプルからの接続
以前作成したMavsdk_Cesiumのサンプルから、ラズパイ4上のMavsdkに接続するには、gRPCの接続先をラズパイ4のIPアドレスに変更します。
// mavsdk_cesium.go #21 conn, err := grpc.Dial("<ラズパイ4のIPアドレス>:50051", grpc.WithInsecure())
Pixhawkの機体リファレンスをSIH(Simulation in Hardware)に設定しておけば、ハードウェア上でシミュレータを実行できます。
この辺はおいおい説明します。実機上のシミュレーションなので、プロポを接続してリアルタイムで操縦しながらCesiumで表示させることができます。
まとめ
今回のラズパイ4を搭載したドローンのソフトウェアとインターフェースの構成は以下のイメージです。
ちなみに、最新のMavsdk_Cesiumは以下のようになっています。
3Dモデルを購入して差し替えていて、かつ、アニメーション表示を変更しているので、よりリアルタイム描画が可能となっています。
いずれ、記事を書きますね。
Arm、Disarmでプロペラ回転アニメーションをON、OFFするだけでも、雰囲気出ますね。
— Tomofiles (@tomofiles) 2019年12月7日
プロポで飛ばすと楽しい。 pic.twitter.com/zGDMG7Qem2
現在の自作ドローンの合計金額は、ラズパイ4代を加算して、以下のとおりです。
116,000円
+7,700円
→123,700円
なお、今回あえて記載しなかったのですが、ラズパイ4の電源周りで一つ課題が残っています。
ラズパイ4はバッテリーからBECで5Vを作成して供給する予定ですが、それ自体は問題ないのですが、Pixhawkとラズパイ4を同時に起動すると、ラズパイ4の起動が失敗してしまいます。
起動時からraspiとpixhawk繋いどくと、シリアルポートから流れてくるmavlinkパケットがraspiのboot時の入力デバイスと認識されて、起動がバグる問題が発覚。いーや、どうしたものか。 https://t.co/qeTDLAW7Qv
— Tomofiles (@tomofiles) 2019年12月12日
u-bootってブートローダが、シリアルポートからの入力でブート時の「Hit any key to stop autoboot:」に反応して、ブートが停止してるみたい。環境変数にstdinとかあって、serialが設定されてる可能性が高い。帰ったらこれを試そうか。 https://t.co/5PuoY0Dgos
— Tomofiles (@tomofiles) 2019年12月13日
この辺りはまだ解決していないので、解決できたら記事書きますね。
今回も長くなってしまってすみません。
それでは、また。
◆Previous Part
tomofiles.hatenablog.com