ARCS6のリアルタイム性 FRONT PAGE
最終更新日:2022/02/05

ARCS6のリアルタイム性の考え方

念のために一応書いておきますが,ARCS6はソフトリアルタイム志向です。 なので制御周期から逸脱する場合があります。 完璧なリアルタイム性を求めるならば,ARCS6は「そのままでは」使用不可です。

一方で,ARCS6はカーネル空間ではなくユーザ空間で動くので,安定性は抜群です。 その他のリアルタイムカーネルをベースにしたものに比べ,OSを巻き添えにしながら,破壊しながら落ちるようなことは無く, コーディングでヘマをやらかしても安心です。 カーネルをイジったことで起きる様々な副作用に悩むこともありません。 リアルタイム性を守れないときは守れない,それでも十分にテストされた信頼のおけるカーネル上で, できるだけリアルタイム性を守る,それがARCS6のリアルタイム性の考え方です。

リアルタイム性の確認実験1

ではどれだけARCS6はリアルタイム性があるのかですが,実際のマシンで確認実験をしたのでその結果を載せておきます。 動作条件は下記の通りです。

動作条件
Intel Corei7-7700 @ 3.60GHz
Hyper Threading 無効
intel_pstate 無効
クロック周波数固定
Ubuntu 18.04LTS
Kernel Module 最小限
ConstParams.hh: THREAD_TYPE = SFalgorithm::WITHOUT_ZEROSLEEP;
テスト用コード :ControlFunctions.cc
プロット用コード:RealtimeCheck.m

制御周期Ts = 100 μs に設定したときの実験結果を下記に載せておきます。

Fig.1 リアルタイム性の確認のための実験結果

(a)は計算に要した消費時間Tcmp,(b)は実際に計測した制御周期Tact,(c)は(b)のヒストグラムです。 グラフから分かるように,たまーに消費時間Tcmpが急激に増加して制御周期Tactが設定した制御周期Ts = 100 μs を守れていないときがあります。 これがARCS6のリアルタイム性の現状です。

リアルタイム性の確認実験2

とはいえ,やはりもう少しなんとかならないの?と思うところがありますね。 Fig.1の消費時間Tcmpが劇的に上昇した原因は,恐らく制御ループの中で割り込みが入ったからと思われます。 そこで,AlmaLinuxにて設定を見直し,CPUの割り込み設定を突き詰めたところ,リアルタイム性を劇的に向上することができました。 動作条件は下記の通りで,同一条件とはいえずフェアな比較ではありませんが,CPUの割り込み設定が一番効いていそうな感じです。

動作条件
AMD Ryzen5 3500 @ 3.60GHz
MSI X570
DDR4-3200 32GB
M.2 PCIE GEN4 SSD
AlmaLinux 8.4-x84_64-minimal
Kernel Module 最小限
下記のシェルスクリプトの事前実行により割り込みを1つのCPUコアに集中させる:
(echo 1 > /proc/irq/default_smp_affinity) > /dev/null 2>&1
for i in {0..127}; do
(echo 1 > /proc/irq/$i/smp_affinity) > /dev/null 2>&1
done

AlmaLinuxでの環境構築の詳細についてはAlmaLinux Setup for ARCS6に記載しました。 下記が制御周期の計測結果です。

Fig.2 リアルタイム性の確認のための実験結果(割り込み設定見直し)

劇的にリアルタイム性が向上していることが分かります。 ヒストグラムから分かるように 100 ~ 102 μs の範囲で制御周期は収まっています。 ということで,実はリアルタイムカーネル無しでもユーザ空間でのコーディングで,少し工夫するだけでここまでリアルタイム性を出すことができます。 大抵の制御システムでは,ここまでリアルタイム性があれば十分でしょう。

微分器で起きる問題

とはいえ問題が全く無いわけではありません。 制御周期Tsを逸脱したときに,もし何も考えずに普通に信号の微分をしていると微分器の出力にスパイクが発生します。 例えば,ロボットの位置から速度を計算する際に,速度の信号にスパイクが含まれていたらマズイですね。 暴走のトリガーになりえます。 そこで,./lib/SpeedCalculator.hh の実装を見てもらえば分かりますが, 実際の計測した制御周期Tactを使って差分を取ることでスパイクを除去可能です。 制御周期の変動がクリティカルに効いてくる部分は実際の制御周期Tactを使い,それ以外の大して問題にならない部分は固定の制御周期Tsを使うようにします。

それでもリアルタイム性が気になるなら

もしそれでも問題になるときはARCS6でもRTAIなどのリアルタイムカーネルを使うこともできます。 リアルタイムカーネルのスレッド用に./lib/SFthread.hhのスレッドの部分を書き換えればハードリアルタイムに変更可能です。 実際,昔はそうしてました。 (でもリアルタイムカーネルのパッチを当てて動かすための戦いはもう疲れたので,現状の方法で問題が出ない限り自分ではやらないと思う…)