rikuya-h
2025年3月28日 10時02分
お世話になっております。
Armadillo-IoT G4 にて開発を進めておりますが
RS-485通信を行う必要が出てきたため、以下のUSBとのコンバータを使用
https://www.switch-science.com/products/8426
RS-485通信にあまり知見が無く...試しに
PCとArmadillo-IoT G4間で通信させたく思うのですが
上手く通信させる事が出来ておりません。
ご教授頂けると大変助かります。
※PC(ドライバーインストール済み)及びArmadillo側でのコンバータ認識は出来ております。
コメント
rikuya-h
> アットマークテクノの下山です。
>
> まず、お互いのコンバータのA+・B+・GNDを接続した状態であることを確認してください。
> PC側のコンバータをTeratermなどで表示している場合は、改行コードを送信・受信ともにLFに設定してください。
>
> ■通信設定
> G4の通信設定を以下のように設定します
> ここでは、baudrateを115200として設定してます、PC側も同じbaudrateに設定してください
>
> armadillo:~# stty -F /dev/ttyACM0 speed 115200 parenb -parodd brkint ignpar -icrnl -ixon -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke >
>
> ■G4から送信する場合
> 以下のコマンドでPC側に文字は表示されますでしょうか?
>
> armadillo:~# echo "hello" > /dev/ttyACM0 >
>
> ■G4が受信する場合
> 以下のコマンドを実行してから、PC側で文字入力+EnterでG4側のコンソールに文字は表示されますでしょうか?
>
> armadillo:~# while read var ; do echo $var ; done < /dev/ttyACM0 >
>
> よろしくお願いします
上記手順でPC側及びG4側で文字出力を確認出来ました!
ありがとうございます。
続けてで恐縮ですが、
これらで実験的にModbus Protocolを用いた通信を行いたいのですが、
どの様に設定し、操作すれば良いかもご教授頂けると大変助かります。
at_shota.shimoyama
rikuya-h
at_shota.shimoyama
> 実運用でもPythonを使用しようと考えていました。
> G4がマスター側になります。
本来はABOSDEでPythonプロジェクトから実行環境などを用意するのが望ましいのですが、
実験的に手っ取り早く確かめるなら、ABOS上に直接インストールしてスクリプトを実行することもできます。
■パッケージ等のインストール
armadillo:~# apk update armadillo:~# apk add python3 py3-pip armadillo:~# pip3 install pymodbus pyserial --break-system-packages
■スクリプト
例えばスレーブIDが1のデバイスの入力レジスタ0x07d0から10ワード読み取る(read_input_registers)処理は次のようになります。
そのあたりやbaudrateについては適宜変更してください。
from pymodbus.client import ModbusSerialClient client = ModbusSerialClient( port='/dev/ttyACM0', baudrate=115200, parity='N', stopbits=1, bytesize=8, timeout=3, ) if client.connect(): print("client.connect() OK") else: print("client.connect() Failed") exit() reg = client.read_input_registers(0x07d0, count=10, slave=1) if not reg.isError(): r = reg.registers print(r) else: print("Error read_input_registers 0x07d0") client.close()
また、/dev/ttyACM0がデバイスファイル名になるだけで、RS-485やModbus/RTUの使用方法においてArmadilloに固有の操作などは特にありませんので、インターネットから得られる一般的な情報を参考にできます。
PyModbusの使用方法などについては
https://pymodbus.readthedocs.io/en/v3.8.6/
などを参照してください。
rikuya-h
ご無沙汰しております。
頂いたコメントにて参考にArmadilloを"マスター"にした際の方法で開発を進めています。
ただ、最近Armadilloを"スレーブ"にした際の簡単な検証をしたところレジスタの初期化が上手くいかず悩んでいます。
Armadillo G4 Slave side
import asyncio import pymodbus from pymodbus.server import StartAsyncSerialServer from pymodbus.datastore import ModbusSequentialDataBlock from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext async def run(): store = ModbusSlaveContext(hr=ModbusSequentialDataBlock(0, [18] * 100),ir=ModbusSequentialDataBlock(0, [19] * 100)) slaves = { 0x01: store, } context = ModbusServerContext(slaves=slaves, single=False) await StartAsyncSerialServer(context=context, port="/dev/ttyACM0", baudrate=115200, stopbits=1, bytesize=8, parity="N") if __name__ == "__main__": pymodbus.pymodbus_apply_logging_config("DEBUG") asyncio.run( run(), debug=True )
PC Master side
from pymodbus.client import ModbusSerialClient import pymodbus def run(): client = ModbusSerialClient( port='COM15', baudrate=115200, parity='N', stopbits=1, bytesize=8, timeout=3, ) if client.connect(): print("client.connect() OK") else: print("client.connect() Failed") exit() # ホールディングレジスタを読み取る reg = client.read_holding_registers(0x00, count=10, slave=1) if not reg.isError(): r = reg.registers print("HR読み取ったレジスタ:", r) else: print("Error read_holding_registers 0x00") # インプットレジスタを読み取る reg = client.read_input_registers(0x00, count=10, slave=1) if not reg.isError(): r = reg.registers print("IR読み取ったレジスタ:", r) else: print("Error read_input_registers 0x00") client.close() if __name__ == "__main__": pymodbus.pymodbus_apply_logging_config("DEBUG") run()
Armadillo G4 側出力
2025-06-20 12:06:28,510 DEBUG transport:256 Awaiting connections server_listener 2025-06-20 12:06:28,516 INFO base:85 Server listening. 2025-06-20 12:06:28,518 DEBUG transport:277 Connected to server 2025-06-20 12:06:32,706 DEBUG transport:329 recv: 0x1 0x3 0x0 0x0 0x0 0xa 0xc5 0xcd old_data: addr=None 2025-06-20 12:06:32,706 DEBUG base:91 Processing: 0x1 0x3 0x0 0x0 0x0 0xa 0xc5 0xcd 2025-06-20 12:06:32,707 DEBUG decoders:113 decoded PDU function_code(3 sub -1) -> ReadHoldingRegistersRequest(dev_id=0, transaction_id=0, address=0, count=10, bits=[], registers=[], status=1) 2025-06-20 12:06:32,707 DEBUG base:101 Frame advanced, resetting header!! 2025-06-20 12:06:32,711 DEBUG context:121 getValues: fc-[3] address-1: count-10 2025-06-20 12:06:32,712 DEBUG transport:386 send: 0x1 0x3 0x14 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xa3 0x67 2025-06-20 12:06:32,723 DEBUG transport:329 recv: 0x1 0x4 0x0 0x0 0x0 0xa 0x70 0xd old_data: addr=None 2025-06-20 12:06:32,724 DEBUG base:91 Processing: 0x1 0x4 0x0 0x0 0x0 0xa 0x70 0xd 2025-06-20 12:06:32,724 DEBUG decoders:113 decoded PDU function_code(4 sub -1) -> ReadInputRegistersRequest(dev_id=0, transaction_id=0, address=0, count=10, bits=[], registers=[], status=1) 2025-06-20 12:06:32,724 DEBUG base:101 Frame advanced, resetting header!! 2025-06-20 12:06:32,726 DEBUG context:121 getValues: fc-[4] address-1: count-10 2025-06-20 12:06:32,727 DEBUG transport:386 send: 0x1 0x4 0x14 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x95 0x81
PC 側出力
client.connect() OK 2025-06-20 12:06:32,746 DEBUG base:91 Processing: 0x1 0x3 0x14 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xa3 0x67 2025-06-20 12:06:32,746 DEBUG decoders:113 decoded PDU function_code(3 sub -1) -> ReadHoldingRegistersResponse(dev_id=0, transaction_id=0, address=0, count=0, bits=[], registers=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], status=1) 2025-06-20 12:06:32,747 DEBUG base:101 Frame advanced, resetting header!! HR読み取ったレジスタ: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2025-06-20 12:06:32,761 DEBUG base:91 Processing: 0x1 0x4 0x14 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x95 0x81 2025-06-20 12:06:32,761 DEBUG decoders:113 decoded PDU function_code(4 sub -1) -> ReadInputRegistersResponse(dev_id=0, transaction_id=0, address=0, count=0, bits=[], registers=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], status=1) 2025-06-20 12:06:32,761 DEBUG base:101 Frame advanced, resetting header!! IR読み取ったレジスタ: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
以下コードで初期値を設定しているはずですが、"0"が値としては返ってきてしまっています。
store = ModbusSlaveContext(hr=ModbusSequentialDataBlock(0, [18] * 100),ir=ModbusSequentialDataBlock(0, [19] * 100))
"マスター:Armadillo G4","スレーブ:PC"の関係だと正しく動作するのですが、 "スレーブ:Armadillo G4"だと正しく動作しない様に見えます。
私の勉強不足かもしれませんが、何か分かればご教示頂けると助かります。
at_shota.shimoyama
rikuya-h 様
こちらでも再現できました(マスターがPC・Armadillo G4のどちらであっても起こりました)
原因を調べてみたのですが、pymodbusライブラリ内のバグ(仕様?)でした…
ModbusSlaveContext(...)
のところで、di=...
の引数も指定しないと、他のco=... , ir=... , hr=...
は無効になります
例えば、添付いただいたコードでは、
store = ModbusSlaveContext(hr=ModbusSequentialDataBlock(0, [18] * 100),ir=ModbusSequentialDataBlock(0, [19] * 100))
となっていますが、di=...
の指定がないため、hrとirはデフォルトの [0]*65536 になってしまいます。(そのため0しか読み取れない)
ですので、何かテキトーな数値でよいので、以下のようにdi=...
も指定してください
store = ModbusSlaveContext(di=ModbusSequentialDataBlock(0, [1]), hr=ModbusSequentialDataBlock(0, [18] * 100),ir=ModbusSequentialDataBlock(0, [19] * 100))
ちなみに、pipでインストールできるpymodbusの最新バージョン(3.9.2)だと上記のバグがありますが、
githubで公開されているレポジトリでは4月末に修正されたようです↓
https://github.com/pymodbus-dev/pymodbus/commit/eb84cfef92ddab8780652bd…
3.9.2より新しいバージョンが公開されたら、もしかしたらこのバグも治るかもしれません
rikuya-h
> rikuya-h 様
>
> こちらでも再現できました(マスターがPC・Armadillo G4のどちらであっても起こりました)
>
> 原因を調べてみたのですが、pymodbusライブラリ内のバグ(仕様?)でした…
> ModbusSlaveContext(...)
のところで、di=...
の引数も指定しないと、他のco=... , ir=... , hr=...
は無効になります
>
> 例えば、添付いただいたコードでは、
>
> store = ModbusSlaveContext(hr=ModbusSequentialDataBlock(0, [18] * 100),ir=ModbusSequentialDataBlock(0, [19] * 100)) >
> となっていますが、di=...
の指定がないため、hrとirはデフォルトの [0]*65536 になってしまいます。(そのため0しか読み取れない)
>
> ですので、何かテキトーな数値でよいので、以下のようにdi=...
も指定してください
>
> store = ModbusSlaveContext(di=ModbusSequentialDataBlock(0, [1]), hr=ModbusSequentialDataBlock(0, [18] * 100),ir=ModbusSequentialDataBlock(0, [19] * 100)) >
>
> ちなみに、pipでインストールできるpymodbusの最新バージョン(3.9.2)だと上記のバグがありますが、
> githubで公開されているレポジトリでは4月末に修正されたようです↓
> https://github.com/pymodbus-dev/pymodbus/commit/eb84cfef92ddab8780652bd…
>
> 3.9.2より新しいバージョンが公開されたら、もしかしたらこのバグも治るかもしれません
at_shota.shimoyama様
ご丁寧な回答ありがとうございます!
バグ(仕様)だったとの事で現時点での修正案
diを追加する事で私の環境でも期待通りの動作になりました。
これで開発を進められます。ありがとうございました。
at_shota.shimoyama
2025年3月28日 12時04分
アットマークテクノの下山です。
まず、お互いのコンバータのA+・B+・GNDを接続した状態であることを確認してください。
PC側のコンバータをTeratermなどで表示している場合は、改行コードを送信・受信ともにLFに設定してください。
■通信設定
G4の通信設定を以下のように設定します
ここでは、baudrateを115200として設定してます、PC側も同じbaudrateに設定してください
■G4から送信する場合
以下のコマンドでPC側に文字は表示されますでしょうか?
■G4が受信する場合
以下のコマンドを実行してから、PC側で文字入力+EnterでG4側のコンソールに文字は表示されますでしょうか?
よろしくお願いします