TOPに戻る

ラズパイ5 +Python+CANopenでモータを回す ⑦ CANバス信号を見る<前編>canreset.py candump0.py

 CANopenは、物理層にCANバス・ネットワークを利用しています。CANバスを流れる信号は、ツールを使うと簡単にとらえることができます。ここでは、複数の方法を説明します。

<その1>オシロスコープで信号を見る

 CAN_LとCAN_Hにプローブを当てています。

 二つの信号は極性が異なっているだけで、同じデータです。

 ID(CAN-ID)、ここでは0x58Cですが、通信オブジェクト識別子(COB-ID)と呼ばれることもあり、11ビットの内MSBから4ビットをファンクション・コード、残り7ビットをデバイスのNode-IDで構成されています。ここでつながっているモータのNode-IDは12(0x0c)を設定しています。

 ファンクション・コードで代表的なNMTは0000、PDOは0011~1010、送信のSDOは1011、受信のSDOは1100です。

 したがって、0x58Cは、SDO(送信)のデータ・フレームだとわかります。

 データ・フレーム(一連のデータの塊)のデータ・フィールドは0~8バイトで構成されていますが、ほとんどが8バイトです。

 データ・フィールドの最初の1バイトは0x40と0x4Bが見つかります。0x40は、読み込みのアップロード要求です。0x4Bは、アップロード応答のコマンド指定子CSで、

 

CS(0x4x) Index LB Index HB Subindex LLB (D0) LHB (D1) HLB (D2) HHB (D3)

  • CS = 0x4F;D0に1データ・バイト
  • CS = 0x4B;D0~D1に2データ・バイト
  • CS = 0x47;D0~D2に3データ・バイト
  • CS = 0x43;D0~D3に4データ・バイト

 0x4BはD0~D1に2データ・バイトということになります。

 Index LBとIndex HBは4160なので、逆順にしてオブジェクト・ディクショナリから6041=Bits in Statuswordを読み出していることになります。

 次のSubindexは0なので、ナシ、データは0x401Aだとわかります。これも逆にして、0x1A40=0b1101001000000は、下の表からSwitch on disabledだとわかります。

xxxx xxxx x0xx 0000 Not ready to switch on
xxxx xxxx x1xx 0000 Switch on disabled
xxxx xxxx x01x 0001 Ready to switch on
xxxx xxxx x01x 0011 Switched on
xxxx xxxx x01x 0111

Operation enabled

xxxx xxxx x00x 0111 Quick stop active
xxxx xxxx x0xx 1111 Fault reaction active
xxxx xxxx x0xx 1000 Fault

 各ビットの意味です。

 0 Ready to Switch ON、1 Switched ON、2 Operation Enabled、 3 Fault、 4 Voltage Enabled、5 Quick Stop 、6 Switch ON Disabled、 7 Warning、 8 Drive profile operation ready (manufacturer-specific (MS)) 、9 Remote、 10 Target Reached、 11 Internal Limit Active、12,13 Operation Mode Specific (OMS) 、14 Reserved (manufacturer-specific (MS)) 、15 TLC (manufacturer-specific (MS))

<その2>IXXATのUSB-to_CAN V2 Compactを利用する

 WindowsマシンをCANバスに接続するために使っているIXXATのUSB-to_CAN V2 Compactには、canAnalyser3 Miniというユーティリティ・ソフトが付属します。CANバスのモニタとして利用ができますが、CANopenのプロトコルを解釈してはくれません。その手のソフトは調べると約20万円するようです。

 右上のログ画面には、時刻、ID、データ・フレームが記録されています。

リセット・プログラム canreset.py

 プログラムを作って動かすと暴走することが多々あります。下記の画面は、BLVD_KRDのサポート・ソフトMEXE02のCANopen通信ステータス画面の一部です。暴走すると、左のNMT(通信ステート)がStoppedになったり、右のState Machine(運転ステート)がFault状態で止まってしまい、プログラムを修正しても、正しく動きださないことがあります。

 そこで、いろいろエラーを解除し、電源が入った直後に戻すcanreset.py(ラズパイ用)を作りました。最初のCANバスのデータは、このプログラムなどを動かしたときのものです。100% 電源ONの初期状態に戻らないこともありますが、ほとんどうまく動きます。

import canopen
import time
import logging
# logging.basicConfig(level=logging.DEBUG)

# Start with creating a network representing one CAN bus
network = canopen.Network()

# Connect to the CAN bus
# sudo ip link set can0 up type can bitrate 1000000
network.connect(bustype='socketcan', channel='can0')
print("\n===start  ID=12 OrientalMotor\n")

network.check()

# Add some nodes with corresponding Object Dictionaries
node = canopen.BaseNode402(12,'Downloads/BLVD-KRD_CANopen_V200.eds')
network.add_node(node)

# all nodes simulaneously as a broadcast message
network.nmt.state = 'RESET'
time.sleep(0.5)
print('network state 1) = {0}'.format(network.nmt.state))

# Reset network
node.nmt.state = 'RESET'
node.nmt.wait_for_bootup(15)
node.nmt.state = 'RESET COMMUNICATION'
node.nmt.wait_for_bootup(15)
print('node state 1) = {0}\n'.format(node.nmt.state))

node.setup_402_state_machine()
time.sleep(0.1)
print('state_machine state 1) = {0}'.format(node.state))
#clear Fault
node.sdo[0x6040].raw = 0x80
time.sleep(0.2)
network.check()
print('state_machine state 2) = {0}'.format(node.state))

print('\ngoing to exit... stopping...')
if network:
    for node_id in network:
        node = network[node_id]
        node.nmt.state = 'PRE-OPERATIONAL'
        #node.nmt.stop_node_guarding()
        #node.nmt.state = 'STOPPED'
#network.sync.stop()
network.disconnect()

 実行している様子です。

 network.nmt.state = 'RESET'

 このCANバスにつながっているすべてに対してリセットを発行?しているので、別の機材の接続が切れるなどするかもしれません。

 このプログラムは、仮想環境で動かしています。

(envtest) yoshi@ras05:~ $ pip list
Package           Version
----------------- -------
canopen           2.2.0
msgpack           1.0.8
packaging         24.0
pip               23.0.1
python-can        4.3.1
setuptools        66.1.1
typing_extensions 4.10.0
wrapt             1.16.0

<その3>Linuxのcan utils

 CANバスの信号をラズパイで見ます。can-utilsをインストールします。仮想環境envcanで動かしています。

(envcan) yoshi@ras05:~ $ sudo apt-get install can-utils

Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
can-utils is already the newest version (2020.11.0-1).
The following packages were automatically installed and are no longer required:
  libcamera0.1 libssl1.1 linux-headers-6.1.0-rpi7-common-rpi linux-headers-6.1.0-rpi7-rpi-2712
  linux-headers-6.1.0-rpi7-rpi-v8 linux-image-6.1.0-rpi7-rpi-2712 linux-image-6.1.0-rpi7-rpi-v8 rtimucli
Use 'sudo apt autoremove' to remove them.
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

 ターミナルを一つ立ち上げて、 can-utilsでインストールしたアプリケーションの一つcandumpを動かします(仮想環境でなくてよい)。

$ candump can0

 can0は、プログラムで利用しているネットワーク・デバイスの名前です。

# sudo ip link set can0 up type can bitrate 1000000
network.connect(bustype='socketcan', channel='can0')

 元のターミナルに戻って、canreset.pyを起動します。

(envcan) yoshi@ras05:~ $ python canreset.py

===start  ID=12 OrientalMotor

network state 1) = INITIALISING
node state 1) = PRE-OPERATIONAL

state_machine state 1) = NOT READY TO SWITCH ON

going to exit... stopping...

 もう一つのターミナルの表示です。CANバスを流れるデータが見えました。

少しプログラムでデータを見やすく candump0.py

 ダンプをファイルに落とします。canreset.pyを起動します。

$ candump can0>t.txt

 フレームの最初はCAN-ID(ID)です。functionとNode-IDが組み合わさった11ビットなので、これを、デコードします。

FUNCTION = {'0000':'NMT','0001':'EMCY','0010':'TIME','0011':'TPDO1','0100':'RPDO1',
        '0101':'TPDO2','0110':'RPDO2','0111':'TPDO3','1000':'RPDO3','1001':'TPDO4',
        '1010':'RPDO4','1011':'SDO(tx)','1100':'SDO(rx)','1110':'HERTBEA'}

f = open('t.txt', 'r')
line = f.readline()
print('CAN-ID( function     Node-ID)  Length      frame ')

while line:
    nokori = line.strip()[11:]
    function7 = int(line.strip()[6:8],16)
    #print(function7)
    function4 = int(line.strip()[6:8],16) >>3
    #print(str(bin(function4))[2:])
    if function7 == 0:
        F = 'SYNC        '
    else:  
        F = FUNCTION[str(bin(function4))[2:]]
    #print(F)
    node_ID = int(line.strip()[8:9],16)
    #print(function4)
    print(' {}   {:x} {:b} {} {}      {}'.format(line.strip()[6:9],function7,function4,F,node_ID,nokori))
    line = f.readline()
f.close()

 プログラムの名称をcandump0.pyとしました。実行します。読み出すのはリダイレクトしたt.txtです。

 ほとんど役に立たないですね。

 第9回で、Analog Devices TCML-IDEを利用します。このツールは無償で使え、CANopenの流れるデータをリアルタイムでデコードできます。

資料

<オシロスコープ> PicoScope 5242B(垂直方向の分解能が最大16ビット、帯域が60MHz、入力2チャネル、発振出力1チャネル)

<ixxat Windows driver software> https://www.ixxat.com/technical-support/support/windows-driver-software

<MEXE02> https://www.orientalmotor.co.jp/ja/products/detail?hinmei=MEXE02

連載 ラズパイ5 +Python+CANopenでモータを回す

(1) 構成と環境(オリエンタルモーター の「BLMR5100K-A-B」 + 「BLVD-KRD」)

(2) サポート・ソフト MEXE02

(3) PythonでSDOの読み出し(仮)caninfo.py

(4) CANopenのベーシックな規格とSDO/PDO、オブジェクト・ディクショナリ<前編>

(5) CANopenのベーシックな規格とSDO/PDO、オブジェクト・ディクショナリ<後編>

(6) 二つの状態遷移(NMTとStatus Machine)

(7) CANバス信号を見る<前編>canreset.py candump0.py

(8) CANバス信号を見る<中編>Arduino

(9) CANバス信号を見る<後編>CANopenのデコードができ無償で使えるツールAnalog Devices TMCL-IDE

(10) モーション CiA 402の規格<Homing mode> canHome.py

(11) モーション CiA 402の規格<Profile Position Mode (PPM)-前編> canPPMread.py

(12) モーション CiA 402の規格<Profile Position Mode (PPM)-中編> caninfo2.py canppm.py

(13) モーション CiA 402の規格<Profile Position Mode (PPM)-後編> canppm2.py

(14) モーション CiA 402の規格<Profile Velocity Mode (PVM)> campvm.py