ソフトウェアPLCのOpenPLCはオープンソースです。
そのソースコードを利用して、Zephyr(RTOS)に実装してみました。
実際に高速のPLCのスキャンタイムが測定できるか確認しています。
Zephyr RTOSでOpenPLCを実装して、高速スキャンで遊んでみた
ソフトウェアPLCのOpenPLCはオープンソースです。
そのソースコードを利用して、Zephyr(RTOS)に実装してみました。

実際に高速のPLCのスキャンタイムが測定できるか確認しています。
*ただし、簡単なON-OFFや自己保持回路のみのテストです。


この内容をZephyr Project Meetup: Nagoya, Japanで報告させていただきました。
その際の発表資料です。
●後日掲載予定
OpenPLC v3を実装しています
OpenPLCを下記記事で紹介しています。
v4ではまだラズパイなどでは動作できなかったため、v3でテストしています。
OpenPLC v4でラズパイのドライバがまだ未対応だったメモ

ラズパイ+Linux+OpenPLC
ラズパイでOpenPLCを実装する場合には、Raspbian(Linux)上で動くことになります。
色んな機能が使える分、スキャンタイムが遅かったり、ジッタが大きいことを確認しました。

単純なON-OFFジッタのデモ動画が下記となります。
やはり最短1msの周期で、数十usのジッタがある形でした。

ラズパイ+Zephyr(RTOS)+Edited_OpenPLC
OpenPLCのライブラリを一部移植する形で、Zephyr(RTOS)で実装してみました。


GitHub
GitHubのリンク先は下記となります。
*OpenPLCのライブラリを一部利用していますので、ライセンスはGPLとなります。
*単純な自己保持回路のテストとなります。
イメージとしては下記形となります。

以下はGeminiの概要になります。
今回は、軽量かつ強力なZephyr RTOS上で、オープンソースのPLCソフトウェアOpenPLCを動作させるプロジェクトについて解説します。
本プロジェクトの最大の魅力は、IEC 61131-3の標準PLCライブラリをプロジェクト内に内包している点と、10マイクロ秒 (10µs) という極めて短いサイクルタイムでの超高速スキャンを実現している点です。
プロジェクトの概要と特徴
このプロジェクトは、Zephyrの環境にIEC 61131-3準拠のPLCプログラムを統合し、マイコンのGPIOを直接かつ超高速に制御する仕組みを提供しています。
主な特徴
- IEC標準PLCライブラリの完全統合
- Devicetreeを活用したハードウェア抽象化
- マイクロ秒精度の超高速サイクル制御
- シームレスな変数マッピング
プロジェクト内にIEC標準ライブラリを内包
ソースコードの冒頭を見ると、非常に重要なヘッダファイルがインクルードされています。
|
1 2 3 4 |
#include <zephyr/kernel.h> #include <zephyr/drivers/gpio.h> #include <zephyr/sys/printk.h> #include "iec_std_lib.h" // Include path to lib folder |
この #include "iec_std_lib.h" が示す通り、本プロジェクトのフォルダ(lib フォルダ等)にはIEC 61131-3規格に基づくPLCの標準ライブラリ群があらかじめ格納されています。
タイマー(TON/TOF)やカウンタ(CTU/CTD)といったPLC特有の機能がC言語レベルで提供されているため、Zephyrのビルドシステム(CMake等)と組み合わせることで、外部ツールに依存しすぎることなくシームレスにコンパイル・リンクを行うことが可能です。
DevicetreeとPLC変数のマッピング
Zephyrの強力な機能であるDevicetreeを使い、ハードウェアに依存しない形でGPIOピンを取得し、OpenPLCの入出力変数(ポインタ)と結びつけています。
|
1 2 3 4 5 6 7 8 9 |
// OpenPLC側の変数宣言 extern IEC_BOOL *__IX0_6; // 入力 X001に対応 extern IEC_BOOL *__IX0_7; // 入力 X002に対応 extern IEC_BOOL *__QX0_2; // 出力 Y001に対応 // ZephyrのDevicetreeからGPIOスペックを取得 static const struct gpio_dt_spec x001 = GPIO_DT_SPEC_GET(DT_ALIAS(plcin1), gpios); static const struct gpio_dt_spec x002 = GPIO_DT_SPEC_GET(DT_ALIAS(plcin2), gpios); static const struct gpio_dt_spec y001 = GPIO_DT_SPEC_GET(DT_ALIAS(plcout1), gpios); |
メインループ内では、以下のようにブリッジ処理を行います。マイコンボードを変更しても、C言語のコードを書き換えることなく、DTS(Devicetree Source)のエイリアスを変更するだけで移植が可能です。
|
1 2 3 4 5 6 7 8 9 10 11 12 |
// 1. Input: ZephyrのGPIO状態を読み取り、PLC変数へ渡す *__IX0_6 = gpio_pin_get_dt(&x001); *__IX0_7 = gpio_pin_get_dt(&x002); // 2. PLCロジック(ラダー図やST言語)の1スキャンを実行 config_run__(tick++); // 3. Output: PLCの演算結果をZephyrのGPIOへ出力する gpio_pin_set_dt(&y001, *__QX0_2); // タイマー命令(TONなど)を機能させるための内部時間更新 updateTime(); |
ハードウェアサイクルを利用した10µsの超高速スキャン
通常のRTOSのタスクスリープ(k_sleep など)は、システムティック単位(通常100µs〜1ms)の解像度となるため、産業用制御で求められる数十マイクロ秒単位の厳密なリアルタイム性には適していません。
そこで本プロジェクトでは、サイクルタイムを 10000ns(10µs)に設定し、CPUのハードウェアサイクルカウンタを用いた**ビジーループ(スピンロック)**で待機する実装を採用しています。
|
1 2 3 4 5 6 7 8 9 |
// サイクルタイムを10us (10000ns)に設定 common_ticktime__ = 10000; /* ... 処理ループ中略 ... */ // 設定されたサイクルタイムに達するまでビジーループで待機 while (k_cyc_to_ns_floor32(k_cycle_get_32() - start_cyc) < common_ticktime__) { // Spin loop } |
Zephyrの提供する k_cycle_get_32() を利用することで、OSのスリープ精度に邪魔されることなく、ナノ秒レベルの正確な実行周期を担保しています。
また、0.1秒ごとにシリアルコンソールへスキャンタイムなどの稼働状態を出力する機構も備わっており、デバッグも容易です。
単純なprintkではusの表示は難しかった
…と上記にGeminiに概要を紹介してもらいました。
ただし、実際はprintkのログではきっちり10usは表示されませんでした。ざっくり10usです。
usレベルの周期を成立させようとすると、色々補正処理入れる必要がありそうです。

但し、狙っていたusのスキャンとnsレベルのジッタは確認することが出来ました。

デモ動画は下記となります。
Zephyr(RTOS)を利用して、横展開してみた
折角なので、Zephyr(RTOS)のハード抽象化が強力なことを利用してみました。
ラズパイ4Bだけでなく、他のマイコンボードにも展開してみました。


オーバレイ(Devicetree)を弄ることで、簡単に横展開することが出来ました。
ラズパイPico2WやnRF54L15のボードにテストしてみました。


各デモ動画は下記となります。
まとめ
ソフトウェアPLCのOpenPLCはオープンソースです。
そのソースコードを利用して、Zephyr(RTOS)に実装してみました。
実際に高速のPLCのスキャンタイムが測定できるか確認してみました。

コメント