はじめに
Raspberry Piに慣れるために、以前、NUCLEO L476RGとCANシールドで作成したボードとRaspberry PiでCAN通信を行うことにしました。
使用機器
メーカ | 型格 |
---|---|
Raspberry Pi | Raspberry Pi 4 Model B |
inno-maker | USB2CAN |
作りたいもの
- Raspberry Pi上で動くGUIアプリケーション
- CAN通信ができる
これを実現するためにPythonを使うことを使うことにしました。GUIを実現する方法はいくつかあるようでしたがGoogle Trendsで上位であったTkinterを使うことにしました。
Pythonの準備
Raspberry Piには標準でPython3がインストールされているのでアップデートするだけ使用できました。
エラーが発生したのでpip(Pythonのパッケージを管理するツール)のアップデートを行いました。
sudo pip3 install --upgrade pip
python-canの準備
PythonでCAN通信を行うためにpython-canをインストールしました。
pip install python-can
inno-markerのユーザーズマニュアルにツールをインストールすることとあったので下記をインストールしました。
sudo apt-get install can-utils
python-canをインストールすればこちらは不要なのかもしれません。
Tkinterの準備
Tkinterのインストールは必要ありませんでした。
GUIアプリケーション
NUCLEOから送られてくるCANデータを1000ミリ秒ごとにポーリングしています。
通信速度は250kbpsとなります。
import tkinter as tk
import tkinter.filedialog
from tkinter.scrolledtext import ScrolledText
from UsbCan import UsbCan
def canopen():
openbtn['state'] = 'disable'
closebtn['state'] = 'active'
fopenbtn['state'] = 'active'
textbox.delete(0, 'end')
can.open()
global id
id = root.after(1000, polling)
return
def canclose():
root.after_cancel(id)
openbtn['state'] = 'active'
closebtn['state'] = 'disable'
fopenbtn['state'] = 'disable'
dwlbtn['state'] = 'disable'
textbox.delete(0, 'end')
can.close()
return
def fileOpen():
fname = tk.filedialog.askopenfilename(filetypes=[('binary', '*.bin')], initialdir='./')
if fname != None:
textbox.insert('end', fname)
dwlbtn['state'] = 'active'
return
def polling():
msg = can.receive()
if msg != None:
text.insert('end', msg)
text.insert('end', '\n')
global id
id = root.after(100, polling)
return
can = UsbCan()
root = tk.Tk()
root.title('USB 2 CAN')
# set window size
root.geometry('680x480')
# frame
frame = tk.Frame(root, relief='flat')
frame.pack(fill='x', side='top')
# create open button
openbtn = tk.Button(frame, text='open', state='active', command=canopen)
openbtn.pack(fill='x', side='left')
# create close button
closebtn = tk.Button(frame, text='close', state='disable', command=canclose)
closebtn.pack(fill='x', side='left')
# frame
fileFrame = tk.Frame(root, relief='flat')
fileFrame.pack(fill='x', side='top')
# create file open button
fopenbtn = tk.Button(fileFrame, text='file', state='disable', command=fileOpen)
fopenbtn.pack(fill='x', side='left')
# create text
textbox = tk.Entry(fileFrame, width=80)
textbox.pack(fill='both', side='left')
# create download button
dwlbtn = tk.Button(root, text='Download', state='disable')
dwlbtn.pack(side='top')
# create scrolled text
text = ScrolledText(root)
text.pack(fill='both', side='top')
# loop
root.mainloop()
import subprocess
import os
import can
class UsbCan:
"""constructor"""
def __init__(self):
self.__state = False
return
"""destructor"""
def __del__(self):
if self.__state == True:
os.system('sudo ifconfig can0 down')
return
"""open can port"""
def open(self):
self.__state = True
os.system('sudo ip link set can0 type can bitrate 250000')
os.system('sudo ifconfig can0 up')
self.__can0 = can.interface.Bus(channel='can0', bustype='socketcan')
return
"""close can port"""
def close(self):
self.__state = False
os.system('sudo ifconfig can0 down')
return
"""send data"""
def send(self, id, data, ext=False):
if self.__state == True:
msg = can.Message(id, data, ext)
self.__can0.send(msg)
return
"""receive data"""
def receive(self):
if self.__state == True:
msg = self.__can0.recv(1.0)
else:
msg = None
return msg
編集後記
- os.system と subprocess.call について
Pythonで他のプログラム(コマンド)を実行するための標準ライブラリであるos.systemですが、これからはsubprocess.callに置き換わるということで使ってみましたが動作しませんでした。 - socketについて
inno-markerのサンプルでは
# Bind the socket to 'can0'.
can0 = can.interface.Bus(cahnnel='can0', bustype='socketcan_ctypes')
とありましたが、socketcan_ctypesがないとエラーになりました。
socketcanにすることで動作しました。
socketcan_nativeを使用すればいいとの情報もありどのように決めるのか分かりませんでした。
python-canの下記のドキュメントからsocketcanにするのだろうと考えています。
python-can versions before 2.2 had two different implementations named socketcan_ctypes and socketcan_native. These were removed in version 4.0.0 after a deprecation period.
DeepLの翻訳
2.2 より前のバージョンの python-can には、socketcan_ctypes と socketcan_native という 2 種類の実装がありました。これらは非推奨期間を経て、バージョン 4.0.0 で削除されました。
参考サイト
Python3
Python-CAN
Tkinter
SocketCAN
USB2CAN WiKi
subprocess