pythonでcanデータの読み取り

会社技術

はじめに

会社で他社車のBMデータ整理することになった。canってなに?の状況からデータ処理まで何とか頑張ったのでまとめる。記事を書き上げるのを優先したため、分かりにくい部分はご勘弁。

pythonでの読み取り方法

ここではanacondaのパッケージをインストールしていることを前提とする。
こちらを参考にしたが、ところどころ自分で試行錯誤しているところがあるので、参考になればと思う。

コンソール上で必要なパッケージをインストール

コンソール上で下記のコマンドを実行
 pip install cantools
 pip install python-can
筆者はspyderを使っているため、以下の赤〇のところで上記のコマンドをうち、エンターした。

blfの読み取り (import&準備)

先ほど必要なパッケージをインストールしたのでさっそくここで使う。canの読み取りで使うのは、
 import cantools
 import can
それぞれの役割は理解していない。。
そしてcsv化で使うpandas
 import pandas as pd
外部関数として読み取り部分を作成している。
引数はblfのファイル名(~.blf)としている。
.dbcファイルにはbitrateや変数名が格納されているようで、
「dbc_can」に情報を格納する。
続いてblfデータを「blfdata」に格納する。

抽出部分

canのデータはmessageとして各信号に応じたsampringで吐き出されているようだ。そこでmessageを抽出し、変数として保存する必要がある。
信号が吐き出される時刻が信号ごとにそれぞれ異なるため、
下記変数を持たせておく。
 timestamp_shoki=0
また、あらかじめ変数を格納する箱を作成しておく。
 outputー=[]
まずは欲しい信号のmessageを受け取る部分
さきほど作成したblfには沢山のメッセージが詰まっているため、
欲しいメッセージを抽出する。
抽出方法は、
 for msg in blfdata
とし、messageごとに識別する。
識別は、messageのidを見る
 msg.arbitation_id==int(ー)
このidは??と迷うだろう。dbcを色々見るとどうにか分かるだろう
下図の〇はid、△はmessage番号、□は各信号の名前。
書き間違えるとエラー出るのでトライ&エラーでどうにかなるだろう。
識別した後はそのmsgに含まれる情報を格納する。
 temp=dbc_can.getーー
の部分だ。式が長いためーーで省略している。
次にtempに格納した変数を取り出す。
 ー=temp["xx"]
xxにはdbcに記載の文字を入れる。文字を間違えるとエラーになるので注意。
おそらくtemp["xx"]でtempからxxの箱に入っている値を取り出す処理をしているのであろう。
最後に箱に変数をappendする。
注:はじめのmessageはtimestamp_shokiの時間を格納するために使っている。


読み取り部分


DBC中身

csv化

上記までではpythonの通常のlistが作成されている。これをnumpyやpandasで扱えるようにすればあえてcsvにする必要もないが、一応手順を載せる。まずはpandasで扱えるように先ほど作ったlistを下記のように変換する。
 df=pd.DataFrame[ー]
ーは先ほど作成したlist名
次にコラムの作成
 df.columns=(["a","b","c","d"])
a~dには先ほどお好きに。。
最後にpandasでcsv作成。
 df.to_csv(ー)
ーにはファイル名を入れる。

使い方

上記で外部関数として作っており、メインのところでこれを実行する。
引数はファイル名としているので、メインのところで同じフォルダ中のblfファイル名を抽出して、実行するのが都合がよいだろう。
 list=glob.glob(‘*.csv’)
 print(list)
 for x in list:
    abcd(x)
abcdは先ほどの外部関数。メイン関数で使えるようにimportしておくこと。
ちなみにglobも使えるようにimportを忘れずに。

最低限のコード

こちらは動作確認未だが、作ってみた。

import pandas as pd
import cantools
import can

filename=input("please input dbc filename:")
print(filename)
dbc_can=cantools.database.load_file(filename)

file=input("please input blf filename:")
print(file)
blfdata=can.io.blf.BLFReader(file)

BO=input("please input BO Num.:") #red circle at picture 
print(BO)

name=input("please input Message Num.:") #red triangle at picture
print(name)

variable=input("please input variable.:") #red squere at picture
print(variable)

#initialized time constant
timestamp_ini=0
#initialized list
outputlist=[]

for msg in blfdata:
    if(msg.arbitration_id==int(BO)):
        temp=dbc_can.get_message_by_name(name).\
            decode(msg.data, decode_choices=False)
        aaa=temp[variable]
        #bbb=temp[]
        #ccc=temp[]
        if(timestamp_ini==0):
            timestamp_ini=msg.timestamp
        else:
            Timer=msg.timestamp-timestamp_ini
            outputlist.append([Timer,aaa])

df=pd.DataFrame(outputlist)
df.columns=(["Time","aaa"])
df.to_csv(file[:-4]+".csv") #.blf -> .csv

注意点

この手順でやってみてもよくわからないエラーが出ることがある。エラーメッセージ見て対応すればどうにかなるだろう。一点だけよくありそうなエラーを載せる。これはメッセージ中にデータの重複があると言っているようだ。そこでdbc中のテキストを編集する。重複している片方の行を削除すれば解決する。例えば、上で載せた「DBC中身」にある赤□の行が重複行に該当しているならば削除する。

余談

会社ではcanalyzerやcanoeのライセンスが限られているはずだ。自分もdemo版でトライしようとしたが、messageが1000行?超えると読み取れないようだ。もしかしたら自分の知識不足で出来るかもしれないが、データ処理もpythonに任せるのでどうにか読み取りからデータ処理まで一括で出来るように頑張ったのがこの記事だ。。このために色々ネットで調べたが情報少なく、英語の記事も多かったため、いつかアクセス数稼ぎのために英語化したい。。。