ARTSAT

Morikawa の詳細

1 INVADER のハードウェア

INVADER はパワーモジュール・メインモジュール・ミッションモジュールと呼ばれる3つのサブシステムから構成されている。
パワーモジュールは衛星全体の電力管理を行い最も権限が強く、メインモジュールは地上局との通信やミッションモジュールの起動など衛星全体のオペレーションを行う。ミッションモジュールはメインモジュールに従属する形で動作する Arduino 互換の実験用ソフトウェア実行環境である。
architecture

2 ミッションモジュール

2.1 搭載される機能

INVADER に搭載されているミッションモジュールは Morikawa と呼ばれる。
Morikawa は Arduino 互換のソフトウェア動作環境に各種センサや出力デバイスとメモリを接続した設計となっている。情報の可視化やジェネラティブアートのパラメータとして利用できるようにセンサデータを簡単に取得できる。
MorikawaFM
Morikawa には以下の機能が搭載されている。
  • 入力デバイス: CMOS カメラ・太陽電池電圧 / 電流 / 温度・蓄電池電圧 / 電流 / 温度・バス電圧 / 電流 / 温度・送信機電流 / 温度・角速度・磁力・共有メモリ
  • 出力デバイス: 方形波音色・合成音声・LED・共有メモリ
  • 記憶デバイス: FlashROM・FRAM・EEPROM (共有メモリ)・EEPROM (ATmega 内臓)

2.2 Morikawa ハードウェアの設計

2.2.1 設計の概要
diagram_1
Morikawa の設計の中心はメイン CPU である ATmega2560 である。
Morikawa は地上で単独動作する Arduino とは違い、衛星全体を管制するメインモジュールや電力システムを管理するパワーモジュールと協調して動作する必要がある。衛星の電池残量が少なくなれば計画的に強制終了される可能性もありデータの読み書きの安全性なども検討項目となる。
Morikawa では標準的な Arduino の回路設計や基盤ソフトウェアに改造を加えることなく、設計を工夫することでこれらの問題を解決する。
diagram_2
メイン CPU である ATmega 2560 を中心に配置し、各種センサ、データ格納用のメモリや音声合成 LSI などがペリフェラル機器として接続される。
Morikawa を能動的にメインモジュールやパワーモジュールと連携させず、メインモジュールに従属する受動的な設計とすることにより、Morikawa もまたメインモジュールから見ればペリフェラル機器の1つとなる。このような設計では、ペリフェラル機器ごとにハードウェアとソフトウェアをモジュール化することが可能となり、機器の差し替えや追加を容易に行うことができ INVADER 衛星の開発だけでなくさまざまな衛星の開発においても資産を生かすことが可能となる。
table_1
2.2.2 メインモジュールとの協調
Morikawa はメインモジュールに従属する設計であるがメインモジュールとの間でテレメトリーデータの伝達や状態の通知などの通信を行う。
Morikawa とメインモジュールの間は Arduino Mega 2560 の Serial1 を利用したシリアル通信 (UART) によって接続される。メインモジュールからの受信データは Arduino Mega 2560 の Timer1 を利用したタイマー割り込みの中で Serial1 をポーリングすることにより確実に取得される。
Morikawa とメインモジュールの間では以下のようなコマンドが送受信されるが、コマンドの内容や実装も含めてソフトウェアライブラリ層により隠蔽される。
table_2
2.2.3 共有メモリを利用した協調
Morikawa とメインモジュールの間でシリアル通信を利用して伝達されるデータは限られた種類のデータのみである。Morikawa に搭載されたアプリケーションが生成した個別のデータは共有メモリに書き込まれてメインモジュールに引き渡される。また、メインモジュールが Morikawa を起動する際に起動パラメータを伝達する目的にも利用され、共有メモリの一部が特別に割り当てられている。
共有メモリは Morikawa が起動されている間は Morikawa が読み書きの権限を保持しており、Morikawa とメインモジュールは排他的に共有メモリにアクセスする。

2.3 Morikawa ソフトウェア

Morikawa のペリフェラル機器を操作するソフトウェアはペリフェラル機器1種類につき1つの C++ 言語クラスとして提供される。
Morikawa の基本機能を操作するインターフェースとペリフェラル機器を操作するインターフェースを統合した Morikawa クラスがアプリケーションプログラミングインターフェース (API) として開発者に提供される。
Morikawa ソフトウェアは具体的なアプリケーションの中身については実装せず、可能な限り抽象的な形でハードウェアのすべての機能を操作できるように MorikawaSDK として提供される。

3 MorikawaSDK

3.1 MorikawaSDK の概要

table_3 diagram_3
MorikawaSDK には上記のクラスが含まれる。TSTMorikawa クラスは最も重要なクラスであり TSTMorikawa アプリケーションの開発では主にこのクラスを利用する。
TSTFRAM、 TSTFlashROM、TSTSharedMemory、TSTLED、TSTTone、TSTDigitalker、TSTCamera クラスはそれぞれ ATmega 2560 に接続されたペリフェラル機器を表しており読み書きやその他の操作を行うための機器固有の実装を含んでいる。ペリフェラル機器のクラスは TSTMorikawa クラスを通して利用する設計でありアプリケーション開発者が直接利用することはできない。これによりハードウェアの部品が入れ替わったり実装の詳細が変更された場合でもアプリケーションレベルではソフトウェアの変更を行うことなく対応することができる。
TSTCriticalSection クラスは ATmega 2560 のハードウェア割り込みを一時的に禁止するためのクラスである。
TSTTrinity クラスはプリミティブ変数の3冗長化を行うクラスであり C++ 言語のテンプレート機能を用いて実装されている。例えば int i; という整数型を TSTTrinity i; と変更すると3冗長化された変数にアクセスすることが可能となる。
TSTSCCB クラスは OV7675 と通信するための SCCB プロトコルを実装したクラスである。

3.2 C++ 言語を用いた実装

MorikawaSDK は C++ 言語を用いて実装されているが、これは Arduino の基盤ソフトウェアが C++ 言語を用いて実装されていることに起因する。
C++ 言語には仮想継承、仮想関数、typeid、dynamic_cast やテンプレートなどのオブジェクト指向プログラミングのための機能が備わっているが仮想継承や仮想関数はメモリ使用量の増加と実行時オーバーヘッドの増大を生じさせる。typeid や dynamic_cast などの実行時型情報をサポートするにはコンパイラの設定を変更する必要がある。同様に例外を利用する場合にもコンパイラの設定の変更と ABI のリターゲットが必要になる。これらの機能は ATmega 2560 のような8ビットマイコンではできるだけ使用しない方が確実な動作が期待できるため MorikawaSDK では利用できない。

3.3 完全なカプセル化

MorikawaSDK ではメンバ変数はすべて private 変数であり、大域変数は一部の変数を除いてオブジェクトファイルをスコープの範囲とする。メンバ関数についても private・protected・public の順に優先的に利用され積極的に非公開メンバ関数とされる。

3.4 関数の仕様の統一化

3.4.1 コンストラクタ / デストラクタ
MorikawaSDK では例外を使用しないのでコンストラクタやデストラクタの中で発生したエラーを外部に搬出する手段が存在しない。これらの内部では状態管理用の変数の初期化などエラーを発生させない処理のみが記述される。
3.4.2 set / get 系関数
set / get 系関数は主として private なメンバ変数へのアクセッサを提供する。MorikawaSDK ではペリフェラル機器の状態を操作する関数も含まれるためそのような関数ではエラーが適切に返される。
単純なアクセッサ
void setXXX(typename const& param);
typename const& getXXX(void) const;
エラーを返すアクセッサ
TSTError setXXX(typename const& param);
TSTError getXXX(typename* result) const;
3.4.3 read / write 系関数
read / write 系関数は主としてデータ格納用メモリなどの記憶素子への読み書き機能を提供する。ペリフェラル機器との通信ではエラーを発生させる可能性があるためにこれらの関数はエラーを返す可能性がある。
TSTError writeXXX(…);
TSTError readXXX(…);
3.4.4 setup / cleanup / isValid 系関数
コンストラクタやデストラクタでは変数の初期化など単純な操作のみ可能であるためエラーを発生させる可能性のある操作は setup / cleanup 系関数が行う。
isValid 系関数は setup / cleanup 系関数の呼び出し状態を判定するための関数であり setup 系関数の成功から cleanup 系関数の呼び出しまでのあいだ true を返し、それ以外の場合は false を返す。
TSTError setup(…);
void cleanup(void);
bool isValid(void) const;
3.4.5 関数のコーディング規約
MorikawaSDK では上記の特別な関数以外においても次のような規約を採用している。
  • 関数名の先頭は小文字で始まり2単語目からは先頭が大文字である(getData / getAngleX)
  • R.A.M. や R.O.M. などの略語はすべて大文字とし関数名の先頭には用いない(getFRAMSize)
  • position を pos などのように1単語を略さない
  • インスタンスに対して操作を行う関数は動詞の原型で始まる(findItem / update)
  • インスタンスの状態を取得する関数は is + 形容詞や動詞の三人称単数形 + 名詞の単数形とし bool 型を返す(isValid / hasUpdate)
  • ハードウェア割り込みから呼び出される関数は on で始まる(onReceive / onTimer)
  • インスタンスの内容を変更しない関数は const 関数とする
  • 関数の引数にプリミティブ型以外のインスタンスを渡し、関数が引数の内容を変更しない場合は const 参照渡しとする
  • 関数が引数の内容を変更する場合はポインタ渡しとする
  • 関数がエラーを返す場合には成功失敗を表現する bool 型ではなく TSTError 型を返す

3.5 実行時エラーの補足

例外を使用しないのでエラーは関数の戻り値として搬出する。errno のようなエラーを保持する大域変数は呼び出しシーケンスによって解釈が変更される可能性があるために利用しない。

3.6 エラー発生時の引数の内容の保持

関数の内部でエラーが生じた場合でも、引数として渡されたインスタンスの中身は呼び出し前と同じであることが保証される。このような規約により以下に示すように同じ引数を代替関数に渡して安全に処理を続行したりエラーから容易に復帰することが可能となる。
int value = 123;
if (func(&value) == TSTERROR_OK) {
    // value will be changed successfully
}
else {
    // value = 123
}

3.7 ハードウェアの停止

Morikawa はシングルタスクで動作しておりオペレーティングシステムを利用せず、メモリ保護機能も搭載しない。そのため、不正なメモリアクセスや0除算などを行った場合の動作は不定である。
また、Morikawa では Watch dog timer を利用しておらず Watch dog timer の利用はアプリケーション開発者に任せられている。
メインモジュールは Morikawa を起動すると設定された時間の後に強制的に電源を停止する。これにより Morikawa の不意な停止時にも電力の消費を抑え Morikawa を再起動することが可能となる。Morikawa の電源が遮断されると CPU 内部の各種レジスタや揮発性メモリの状態は保持されず破壊される。