目標
任意のCAN信号をシミュレーション環境で送信できるようにする。
1. "Vector Hardware Config"の"Application"を確認。

私の場合は前回"xlCANcontrol"というドライバをインストールしているのでそれが確認できる。
シミュレーションだけで済ませるのであれば、xlCANcontrolなどのドライバをインストールする必要はない。
また、それぞれにxlCANcontrol CAN1/2 を割り当てておく。

"Application"を右クリック→"Add application"で任意のapplicationを追加することができる。

2. 測定側のBUSMASTERの設定を確認する。"Driver Selection"より、"Vector XL"を選択。
Virtual Channel1/2をそれぞれConfigured CAN Hardwareに割り当てる。


3. "Logging"→"Configure"より、ログの設定を確認
"Add"より、ログファイルを追加する。右側の"Log File Details"より、パスなどの設定を変更できる。
基本的にパス設定以外はそのままでOK。

4. "Logging"の"Active"で、ログ測定を有効化する。
5. "Connect"で測定開始。
6. CAN出力は"python-can"を使用する。
https://python-can.readthedocs.io/en/stable/index.html
ターミナルより"pip install python-can"でインストールする。
> pip install python-can
誤って"CAN"をインストールすると、python-canが正しく動作しなくなるので注意
インストールしてしまった場合は"pip-uninstall"だけでなく、手動でフォルダを削除等を実施する必要がある
CANに流したいascを用意する。
Begin Triggerblock
0.000000 Start of measurement
0.000000 1 111 Rx d 3 01 02 03
0.001000 1 222 Rx d 4 0A 0B 0C 0D
0.002000 1 333 Rx d 8 11 22 33 44 55 66 77 88
0.010000 1 111 Rx d 3 01 02 03
0.011000 1 222 Rx d 4 0A 0B 0C 0D
0.012000 1 333 Rx d 8 11 22 33 44 55 66 77 88
0.020000 1 111 Rx d 3 01 02 03
0.021000 1 222 Rx d 4 0A 0B 0C 0D
0.022000 1 333 Rx d 8 11 22 33 44 55 66 77 88
0.030000 1 111 Rx d 3 01 02 03
0.031000 1 222 Rx d 4 0A 0B 0C 0D
0.032000 1 333 Rx d 8 11 22 33 44 55 66 77 88
0.040000 1 111 Rx d 3 01 02 03
0.041000 1 222 Rx d 4 0A 0B 0C 0D
0.042000 1 333 Rx d 8 11 22 33 44 55 66 77 88
End TriggerBlock
ターミナルで以下のように実行することで用意したascファイルをCANに流すことができる。
> python -m can.player -i vector -c 0 -b 500000 --bus-kwargs app_name=xlcancontrol -- test.asc
基本的には以下のドキュメント通り。
https://python-can.readthedocs.io/en/stable/scripts.html
ただし、最後のascファイル指定に関しては"-"を二ついれている。これはpythonのargparseの一般的なオプションで、"-"を二つ入れないと一つ前のoption"bus-kwargs"に、"-test.asc"も含まれてしまい、エラーとなってしまう。
結果がこれ
***BUSMASTER Ver 3.2.2***
***PROTOCOL CAN***
***NOTE: PLEASE DO NOT EDIT THIS DOCUMENT***
***[START LOGGING SESSION]***
***START DATE AND TIME 7:2:2026 10:8:37:61***
***HEX***
***SYSTEM MODE***
***START CHANNEL BAUD RATE***
***CHANNEL 1 - Vector - Virtual Channel 1 SN - 100 - 500000 bps***
***CHANNEL 2 - Vector - Virtual Channel 2 SN - 100 - 500000 bps***
***END CHANNEL BAUD RATE***
***START DATABASE FILES***
***END DATABASE FILES***
***<Time><Tx/Rx><Channel><CAN ID><Type><DLC><DataBytes>***
10:08:39:3302 Rx 1 0x111 s 3 01 02 03
10:08:39:3302 Rx 2 0x111 s 3 01 02 03
10:08:39:3379 Rx 1 0x222 s 4 0A 0B 0C 0D
10:08:39:3379 Rx 2 0x222 s 4 0A 0B 0C 0D
10:08:39:3381 Rx 1 0x333 s 8 11 22 33 44 55 66 77 88
10:08:39:3381 Rx 2 0x333 s 8 11 22 33 44 55 66 77 88
10:08:39:3537 Rx 1 0x111 s 3 01 02 03
10:08:39:3537 Rx 2 0x111 s 3 01 02 03
10:08:39:3538 Rx 1 0x222 s 4 0A 0B 0C 0D
10:08:39:3538 Rx 2 0x222 s 4 0A 0B 0C 0D
10:08:39:3538 Rx 1 0x333 s 8 11 22 33 44 55 66 77 88
10:08:39:3538 Rx 2 0x333 s 8 11 22 33 44 55 66 77 88
10:08:39:3538 Rx 1 0x111 s 3 01 02 03
10:08:39:3538 Rx 2 0x111 s 3 01 02 03
10:08:39:3538 Rx 1 0x222 s 4 0A 0B 0C 0D
10:08:39:3538 Rx 2 0x222 s 4 0A 0B 0C 0D
10:08:39:3538 Rx 1 0x333 s 8 11 22 33 44 55 66 77 88
10:08:39:3538 Rx 2 0x333 s 8 11 22 33 44 55 66 77 88
10:08:39:3697 Rx 1 0x111 s 3 01 02 03
10:08:39:3697 Rx 2 0x111 s 3 01 02 03
10:08:39:3698 Rx 1 0x222 s 4 0A 0B 0C 0D
10:08:39:3698 Rx 2 0x222 s 4 0A 0B 0C 0D
10:08:39:3699 Rx 1 0x333 s 8 11 22 33 44 55 66 77 88
10:08:39:3699 Rx 2 0x333 s 8 11 22 33 44 55 66 77 88
10:08:39:3700 Rx 1 0x111 s 3 01 02 03
10:08:39:3700 Rx 2 0x111 s 3 01 02 03
10:08:39:3855 Rx 1 0x222 s 4 0A 0B 0C 0D
10:08:39:3855 Rx 2 0x222 s 4 0A 0B 0C 0D
10:08:39:3857 Rx 1 0x333 s 8 11 22 33 44 55 66 77 88
10:08:39:3857 Rx 2 0x333 s 8 11 22 33 44 55 66 77 88
***END DATE AND TIME 7:2:2026 10:8:43:68***
***[STOP LOGGING SESSION]***
感覚的には、コマンドにchannel1に信号を流しているのでRx1にのみCANが流れるように感じられるが、virtualCANの場合はvirtual ChannelというバスにChannel1/2どちらもつながってしまっているので、結果としてどちらのチャンネルにもCANを受信してしまっている。
Virtual Device
├ Virtual Channel 1
└ Virtual Channel 2
このchannel1/2どちらにも同じCANを受信してしまっている状態を改善するには、とりあえず先ほど設定したHardware Selectionで"Virtual Channel2"を外すしかない。

pythonファイルで実施するには以下のようにすれば実現できる。
import can
import time
bus = can.interface.Bus(
interface='vector',
channel=0,
bitrate=500000,
app_name='xlCANcontrol'
)
reader = can.io.ASCReader("test.asc")
start_time = None
for msg in reader:
if msg.timestamp is not None:
if start_time is None:
start_time = msg.timestamp
t0 = time.time()
else:
sleep_time = (msg.timestamp - start_time) - (time.time() - t0)
if sleep_time > 0:
time.sleep(sleep_time)
bus.send(msg)
bus.shutdown()
以下がポイント
if msg.timestamp is not None:
ASCには時刻が付いている行(送信したいCANが記述されている行)と、付いていない行(コメントなど)があり、それを判別するために使用している。
if start_time is None:
start_time = msg.timestamp
t0 = time.time()
ここは一番最初にCANを出力するときに呼び出される。
start_timeに最初のCANフレームを送信する時刻を保存しておく。
また、t0にはその実時刻を保存する。
次にCANフレームを送信する場合、それぞれの送信間での待機時間が必要になる。
例えば、
最初のフレーム: 10.000s
今のフレーム: 10.150s
であれば、0.150s待機する。
そのために、
msg.timestam - start_time
で何秒後にCANフレームを送信するべきかを確認している。
また、CAN送信を開始し始めてから現在までの経過時間を
time.time() - t0
で計算し、最終的に除算することで、本当に必要な待機時間を算出している。
e.g.
1個目のフレーム時刻 = 10.000
2個目のフレーム時刻 = 10.100
現在送信するべきフレーム時刻 = 10.200
スタート時刻 = 15:00:000
現在時刻 = 15:00:140
の場合、
msg.timestamp(10.200) - start_time(10.000) - time.time()(15:00:140) - t0(15:00:000)
=0.200 - 0.140
=0.060



