Tomofiles Note

ドローンとインターネット、そして人との関係を考えるソフトウェアエンジニアのアウトプットブログ

自作ドローンの製作記録 〜Part 3 ラズパイ接続〜

こんにちは、Tomofilesです。

ラズパイ4(Raspberry Pi 4 Model B RAM4GB 国内技適版)を手に入れたので、早速ドローンのコンパニオンコンピュータとして使ってみました。
私が持っていたのは初代ラズパイなのですが、RAMが4GBになって、CPUも64bit対応になっていて、すごい進化してるんだなぁと驚きました。
消費電力(電流量)が上がってきているそうで、性能の向上と消費電力の増加のトレードオフでラズパイ4を使用するかどうか判断する必要がありそうですね。

Pixhawkとコンパニオンコンピュータの接続について、まだ説明していなかったので、今回はラズパイ4を使用してドローンのデータを取得してみたいと思います。

f:id:Tomofiles:20191215001256j:plain

Raspberry Pi 4 Model B RAM4GB

ラズパイ4は今年の6月に発売されましたが、国内の技適を通過して技適マーク印字のモデルが発売されたのは11月でした。
私は以下のサイトで購入しました。(Amazonで電子部品を買うのに少し恐怖心を覚えるようになりました 笑)

www.switch-science.com

価格は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アプリからデバイス名を確認して実施しました。視覚的に確認できますし、念には念を入れてしっかりと確認しておきます。

f:id:Tomofiles:20191212220458p:plain

私の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に差し込んで、電源を入れます。
初回起動時にパスワード変更を求められるので、任意のフレーズに変更してください。

インターネット接続

最優先に行うセットアップは、インターネット接続です。
Ubuntu Serverでは、Netplanにて接続先の設定を行います。
設定方法は他のサイトに説明を譲りますが、YamlファイルでIPアドレスWi-Fiアクセスポイントの設定ができて、Raspbianの設定方法よりこちらのほうが個人的に好きです。

インターネット接続の設定ができれば、以降はデフォルトでSSH接続が可能なので、開発PC(Ubuntu Desktopとか)から操作しましょう。

シリアルポートの開放

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接続じゃなくて、実機でログインしていると表示されます)
最初はこういうものかと思いましたが、少しコンソールの挙動がおかしく見えていて不安に思っていたところ、最終的にカーネルパニックになってしまいました。
シリアル接続で受信したパケットが標準入力に流れ込んでいるように見えます。

シリアルコンソールの無効

ちょっと調べたところ、シリアルコンソールという機能が有効になっていました。
シリアルコンソールはシリアルポートからログインできる機能のようで、障害時など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

パケットはバイナリなので、以下のように文字化けして表示されます。

f:id:Tomofiles:20191213000012p:plain

screenの処理を終了するには、「Ctrl + a→k→y」とキー入力してください。

なお、screenコマンド引数の921600はボーレートなのですが、PX4のパラメータで予め設定しておく必要があります。
QGCにPixhawkを接続して、パラメータから「SER_TELx_BAUD」を921600を選択します。
※xの部分は、PixhawkのTELEMの接続状況により、1や2で読み替えてください

f:id:Tomofiles:20191213000501p:plain

なお、コンパニオンコンピュータに接続する際のパラメータは、以下のサイトを参照してください。

Companion Computers · PX4 Developer Guide

Pixhawkとラズパイ4の配線

順番が前後してしまってますが、Pixhawkとラズパイ4の接続方法を説明します。
Pixhawkとラズパイ4の物理的な接続方法は、検索すると結構出てきます。
ラズパイ4のGPIOから、Rx、Tx、GNDを使用して、PixhawkのTELEMxコネクタと接続します。
※各所に注意書きがあるように、5Vの電源コードは接続しないで下さい!

以下のサイトに掲載されている配線図がわかりやすいです。

Raspberry Piを使用したMAVLinkプロトコルによるドローン用フライトコントローラーPIXHAWKとの通信 | 暇村工房

TELEM用のケーブルは、Pixhawkに同梱のものを使用するか、ドローン自作キットの未使用のテレメトリーモジュールに同梱のケーブルを使用します。
私は未使用のテレメトリーモジュールのケーブルを使いました。

GPIOに接続するので、片方のコネクタを1ピン用のコネクタに取り替える必要があります。
私は、過去にラズパイ用のモジュールセットを買ったときに付属していたケーブルのコネクタを取り外し、Pixhawkのケーブルに繋ぎ直しました。(やっとはんだゴテの出番! 笑)

f:id:Tomofiles:20191214232803j:plain

Mavsdkからシリアルポートに接続

さて、Mavlinkパケットの受信が確認できれば、あとはMavsdkからシリアルポートに接続することで、以下の記事でシミュレータに接続したように、Pixhawkに接続して、テレメトリーやミッションの送受信ができます。

tomofiles.hatenablog.com

この記事で使用したのは、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にログインして実行すると、もう少し情報が出力されます。

f:id:Tomofiles:20191213004106j:plain

alignment trapという例外が発生しているようです。

以下のサイトの説明で色々理解できました。

ARM gcc ¥Ð¥Ã¥É¥Î¥¦¥Ï¥¦½¸
※タイトルが文字化けしてしまっていますが、ホームページの文字コードの影響だと思いますので大丈夫です

過去の案件でC言語をやったときに、構造体のフィールドを4バイトを一つのブロックとして配置するように、パディングフィールドを定義していたのを思い出しました。
CPUによってはalignmentに厳格なものがあるそうで、ラズパイ4で使用しているARM系のCPUはまさにそうで、alignmentを無視したメモリアクセスをすると、例外が発生して落ちるらしいです。一応OSの機能でalignmentの例外ハンドラってのがあるそうですが、今回の状況では一切有効ではなかったです。

さて、これは困りました。
どうしましょうか。

Mavlink Router

色々調べた結果、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 Backend Serverの起動

Mavlink Router実行時のMavsdkの起動コマンドは以下に変わります。
UDPでのアクセスに変更します。

$ ./mavsdk_server_linux-armv7 udp://localhost:14550

これで、めでたくMavsdk Backend Server経由でgRPCを使用してテレメトリー・ミッションなどの送受信が可能となります。

サンプルからの接続

以前作成したMavsdk_Cesiumのサンプルから、ラズパイ4上のMavsdkに接続するには、gRPCの接続先をラズパイ4のIPアドレスに変更します。

tomofiles.hatenablog.com

// mavsdk_cesium.go #21
	conn, err := grpc.Dial("<ラズパイ4のIPアドレス>:50051", grpc.WithInsecure())

Pixhawkの機体リファレンスをSIH(Simulation in Hardware)に設定しておけば、ハードウェア上でシミュレータを実行できます。
この辺はおいおい説明します。実機上のシミュレーションなので、プロポを接続してリアルタイムで操縦しながらCesiumで表示させることができます。

まとめ

今回のラズパイ4を搭載したドローンのソフトウェアとインターフェースの構成は以下のイメージです。

f:id:Tomofiles:20191215124526j:plain

ちなみに、最新のMavsdk_Cesiumは以下のようになっています。
3Dモデルを購入して差し替えていて、かつ、アニメーション表示を変更しているので、よりリアルタイム描画が可能となっています。
いずれ、記事を書きますね。

現在の自作ドローンの合計金額は、ラズパイ4代を加算して、以下のとおりです。

116,000円
+7,700円
→123,700円

なお、今回あえて記載しなかったのですが、ラズパイ4の電源周りで一つ課題が残っています。
ラズパイ4はバッテリーからBECで5Vを作成して供給する予定ですが、それ自体は問題ないのですが、Pixhawkとラズパイ4を同時に起動すると、ラズパイ4の起動が失敗してしまいます。

この辺りはまだ解決していないので、解決できたら記事書きますね。

今回も長くなってしまってすみません。
それでは、また。

◆Previous Part
tomofiles.hatenablog.com