ラズパイでCANを使いたい
環境
- ラズパイ4B一式
- OS:Ubuntu18またはラズパイOS
- MCP2515基板(Amazonで500円くらいで売ってるやつ)
- ジャンパワイヤ-メスメス
以下はあれば嬉しい
- 16Mhz水晶(あれば)
- はんだごて&はんだ
- ハンダシュッ太郎
参考
https://qiita.com/h-kiyo/items/d8583af13768ad67bcd0
前置き
これまでArduinoボードにSPIからMCP2515を接続して,モーターを駆動していた.
このボードには,他にも色々機能をつけていたので,使用していた.
一方,CANしか使用しない場合,いちいちArduinoのシリアルを通してモータ制御するのはめんどくさいので,ラズパイのSPIに直接繋いじゃおうという話.
接続
Raspberry-pi | 配線 | MCP2515 |
---|---|---|
02 5V | <-> | VCC 5V電源 |
06 GND | <-> | GND |
24 GPIO8 | <-> | CS |
21 GPIO9 | <-> | SO |
19 GPIO10 | <-> | SI |
23 GPIO11 | <-> | SCK |
22 GPIO25 | <-> | INT |
configの書き換え
ubuntuの場合
sudo nano /boot/firmware/config.txt
raspiOSの場合
sudo nano /boot/config.txt
書き込み内容
dtparam=spi=on
dtoverlay=mcp2515-can0,oscillator=8000000,interrupt=25
interruptはGPIO25だけど繋いだところに合わせれば良い.
oscillatorは水晶の周波数を記述する.
標準では8Mhz水晶がついているが,これだと500kbpsは対応できても1Mbpsの通信が微妙なので,16Mhzの水晶に付け替える.
ハンダシュッ太郎を使用すると簡単に交換できるので,常備しておくことをオススメする.
設定
認識されているかどうか
下記コマンドを使用する.
何か表示されればok.
表示されなければ認識されてない.
sudo modprobe mcp251x
dmesg | grep mcp251x
can立ち上げ(リンクアップ)
500kbpsの場合
sudo ip link set can0 up type can bitrate 500000
1Mbpsの場合
sudo ip link set can0 up type can bitrate 1000000
正常な場合下記のように表示される.
$ ip link show can0
3: can0: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UP mode DEFAULT group default qlen 10
link/can
下記コマンドでcan0が追加されていればok
ifconfig
ループバックテスト
can-toolの追加
sudo apt install can-utils
ループバックモードで立ち上げ直す.
sudo ip link set can0 down
sudo ip link set can0 type can bitrate 500000 loopback on
sudo ip link set can0 up
下記コマンドを入力して待機
candump can0
別のターミナルを開いて,下記を入力
cansend can0 123#DEADBEEF
candumpコマンドを実行したターミナルで文字が表示されたら成功.
自動起動
今回はserviceファイルに定義する.
cd /etc/systemd/system
sudo nano can.service
[Unit]
Description=Setup CAN interface can0
After=network.target
[Service]
Type=oneshot
ExecStart=/sbin/ip link set can0 up type can bitrate 1000000
ExecStop=/sbin/ip link set can0 down
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
sudo systemctl enable can.service
sudo systemctl start can.service
RoboMasterモータM3508P19を接続
HとLを接続するだけ.
複数個使う場合は,終端抵抗をつける場所について考える.
受信データの表示.ID:201が送られてくる.
candump can0
必要パッケージのインストール
環境はひとまずpython2.7
sudo apt install python-pip
pip install --upgrade setuptools wheel
pip install wrapt==1.10.11
コード
motor_output_current_A に電流値を入れるとモーターが回る.
なんか,時間が経つと,送信バッファがオーバフローしてエラーが出るので,対策する必要がありあそう.
# -*- coding: utf-8 -*-
import can
import time
import struct
# fmap関数と同様の処理
def fmap(x, in_min, in_max, out_min, out_max):
return int((x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min)
# CANインターフェースを初期化
can_interface = 'can0'
bus = can.interface.Bus(can_interface, bustype='socketcan')
# 初期化変数
tx_id = 0x200
rx_id = 0x201
prev_time = time.time()
while True:
try:
# 送信データ作成
motor_output_current_A = 0.0
motor_output_current_byte = fmap(motor_output_current_A, 0, 20, 0, 16384)
tx_data = [
(motor_output_current_byte >> 8) & 0xFF, # 上位バイト
motor_output_current_byte & 0xFF, # 下位バイト
0x00, 0x00, 0x00, 0x00, 0x00, 0x00 # その他のデータ
]
# 20msごとにデータ送信
if time.time() - prev_time > 0.02:
msg = can.Message(arbitration_id=tx_id, data=tx_data, extended_id=False)
bus.send(msg)
print("Sent:", tx_data)
prev_time = time.time()
# CANデータ受信
rx_msg = bus.recv(timeout=0.01) # 10ms待機
if rx_msg is not None and rx_msg.arbitration_id == rx_id:
# データを解析
rx_data = rx_msg.data
angle = struct.unpack('>h', rx_data[0:2])[0]
rpm = struct.unpack('>h', rx_data[2:4])[0]
amp = struct.unpack('>h', rx_data[4:6])[0]
temp = struct.unpack('b', rx_data[6:7])[0]
print("Received ID:", hex(rx_msg.arbitration_id))
print("Angle:", angle, "RPM:", rpm, "Amp:", amp, "Temp:", temp)
except KeyboardInterrupt:
print("Stopping...")
break