LoginSignup
3
2

More than 5 years have passed since last update.

ArduPilot with Linux その2

Posted at

前回のおさらい

前回からだいぶ間が開きました。
前回は、機能追加を行うための基本的な事柄として、sketchの作成方法を見ました。その中で以下のことを見ました。

  • setup()は最初の一回だけ呼ばれる。
  • setup()が呼ばれたあとで、loop()が繰り返し呼ばれる。
  • 何か、halというグローバル変数がある。少なくともコンソールへの表示は何かのインスタンス経由で行われるようだ。
  • AP_HAL_MAIN()という謎マクロがソースの一番下にある。

そして、以下の疑問点を最後に列挙しました。

  • setup()とloop()は誰が呼び出すのか?
  • AP_HAL_MAIN()とは何者か?
  • halの具体的内容は?
  • 一番最初の図には「ユーザプロセス」とある。今書いたsketchとプロセスの関係は?

今回はソースを読んで、これらの疑問点を確認します。

AP_HAL_MAIN()を確認する

AP_HAL_MAIN()は以下のヘッダファイルに定義されているマクロです。

ardupilot/libraries/AP_HAL_Linux/AP_HAL_Linux_Main.h

#ifndef __AP_HAL_LINUX_MAIN_H__
#define __AP_HAL_LINUX_MAIN_H__

#if CONFIG_HAL_BOARD == HAL_BOARD_LINUX
#define AP_HAL_MAIN() extern "C" {\
int main (int argc, char * const argv[]) {        \
    hal.init(argc, argv);           \
        hal.scheduler->system_initialized(); \
        setup();\
        for(;;) loop();\
        return 0;\
    }\
    }
#endif // HAL_BOARD_LINUX
#endif // __AP_HAL_LINUX_MAIN_H__

実装を見ると、確かにsetup()が1度だけ呼ばれて、その後loop()が無限に呼ばれます。また、setup()とloop()を呼び出している関数名がmain()であることにも注目してください。

ここまでで、以下のことがわかりました。

疑問点 対応する実装
setup()とloop()は誰が呼び出すのか? AP_HAL_MAIN()で定義するmain()関数経由で呼ばれる
AP_HAL_MAIN()とは何者か? C/C++で実行時に呼ばれるmain()関数を定義している
一番最初の図には「ユーザプロセス」とある。今書いたsketchとプロセスの関係は? sketch実装がmain()から呼ばれている。よって、sketch自体があるプロセスの一部となっている。プロセス自体の仕組みはこれから読んでいきます。

halとは何者か

AP_HAL_MAIN()の中には以下の実装が含まれています。

AP_HAL_MAIN()実装より抜粋
    hal.init(argc, argv);           \
        hal.scheduler->system_initialized(); \

halとは何者でしょうか。halというのは、このページのAP_HALの説明にあるとおり、ハードウェアの差異を吸収する抽象化層です。基本的には、具体的なハードの詳細を意識することなくコードの実装ができるように準備されたものです。

さて、前回読んだスケルトンコードには、以下の実装がありました。

const AP_HAL::HAL& hal = AP_HAL_BOARD_DRIVER;

halについて、詳しく知りたければ、AP_HAL_BOARD_DRIVERを見れば良さそうです。
検索すると、以下のヘッダファイルで定義されています。

AP_HAL/AP_HAL_Boards.h
#elif CONFIG_HAL_BOARD == HAL_BOARD_LINUX
#define AP_HAL_BOARD_DRIVER AP_HAL_Linux
/* 以下略 */

AP_HAL_BOARD_DRIVERの実体はAP_HAL_Linuxだということがわかりました。
また、CONFIG_HAL_BOARDの値によって、define値が変わることもわかります。

AP_HAL_Linuxを見る

AP_HAL_Linuxは以下のヘッダで定義されています。

ardupilot/libraries/AP_HAL_Linux/HAL_Linux_Class.h
class HAL_Linux : public AP_HAL::HAL {
public:
    HAL_Linux();
    void init(int argc, char * const * argv) const;
};

また、コンストラクタは以下のファイルで実装されています。

ardupilot/libraries/AP_HAL_Linux/HAL_Linux_Class.cpp
/* HAL_Linuxのコンストラクタ */
HAL_Linux::HAL_Linux() :
    AP_HAL::HAL(
        &uartADriver,
        &uartBDriver,
        &uartCDriver,
        NULL,            /* no uartD */
        &uartEDriver,
#if CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_BEBOP
        &i2cDriver0,
        &i2cDriver1,
        &i2cDriver2,
#else
        &i2cDriver0,
        NULL,
        NULL,
#endif
        &spiDeviceManager,
        &analogIn,
        &storageDriver,
        &uartADriver,
        &gpioDriver,
        &rcinDriver,
        &rcoutDriver,
        &schedulerInstance,
        &utilInstance)
{}

const HAL_Linux AP_HAL_Linux;

さて、クラス定義をみるとわかりますが、クラスHAL_Linuxは、クラスAP_HAL::HALを継承しています。
定義は、ardupilot/libraries/AP_HAL/HAL.h にあります。
AP_HAL::HALは長いのでここでは引用しません。しかし、Ardupilotでは基本となるクラスですので、必ず目を通してください

疑問点 対応する実装
halの具体的内容は? Linuxベースのシステムでは、クラスHAL_LinuxのインスタンスAP_HAL_Linux。AP_HAL::HALを継承している。

次回

次回は、以下の実装を掘り下げます。次回は少し難しくなるかもしれません。

AP_HAL_MAIN()実装より抜粋
    hal.init(argc, argv);           \
        hal.scheduler->system_initialized(); \
3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2