【RaspberryPi】 RaspberryPiとArduinoをCAN通信させた 2回目
少し前に"Rasbee オリジナル MCP2515 CAN バス モジュール TJA1050 レシーバーSPIモジュール Arduinoのための AVR"を1つ壊してしまったのでMCP2561とMCP2515を改めて購入。
組み立てができたのでpython-canを用いて、RaspberryPiとArduinoのCAN通信で遊んでみたのでメモ。
ハード側の準備
- RaspberryPi2
- Arduino uno
- 1Mbps CANトランシーバ MCP2561-E/P(CANトランシーバ)
- CANコントローラ MCP2515-I/P(CANコントローラ)
- セラミック発振子 コンデンサ内蔵タイプ 8MHz
- Rasbee オリジナル MCP2515 CAN バス モジュール TJA1050 レシーバーSPIモジュール Arduinoのための AVR
- 超音波距離センサモジュール HC-SR04
構成
配線などはfritzingの使い方覚えたら公開
(が、配線は察しorz)
ソフト側の準備
Arduino
ソースはこんな感じ。
#include <mcp_can.h> #include <SPI.h> #define TRIG_PIN 8 #define ECHO_PIN 9 int Duration; float Distance; MCP_CAN CAN0(10); // Set CS to pin 10 byte Txbuffer[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; void CanInit() { // Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled. if(CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_16MHZ) == CAN_OK) Serial.println("MCP2515 Initialized Successfully!"); else Serial.println("Error Initializing MCP2515..."); CAN0.setMode(MCP_NORMAL); // Change to normal mode to allow messages to be transmitted } void CanSetTxBuffer(int t_duration) { int v; for(int i = 0; i < 8; i++) { Txbuffer[i] = 0x00; } v = max(0, t_duration); Txbuffer[0] = (v >> 8) & 0xFF; Txbuffer[1] = v & 0xFF; } int CanTransmitt(int id) { byte sndStat = CAN0.sendMsgBuf(id, 0, 8, Txbuffer); if(sndStat == CAN_OK) { return 1; } else { return 0; } } void HcSr4Init() { pinMode(TRIG_PIN,OUTPUT); pinMode(ECHO_PIN,INPUT); } void HcSr4Run() { digitalWrite(TRIG_PIN,LOW); delayMicroseconds(1); digitalWrite(TRIG_PIN,HIGH); delayMicroseconds(11); digitalWrite(TRIG_PIN,LOW); Duration = pulseIn(ECHO_PIN,HIGH); if (Duration>0) { Distance = Duration/2; Distance = Distance*340*100/1000000; // ultrasonic speed is 340m/s = 34000cm/s = 0.034cm/us } } void setup() { Serial.begin(9600); CanInit(); HcSr4Init(); } void loop() { HcSr4Run(); Serial.print(" Hex: "); Serial.println(Duration,HEX); Serial.print(Duration); Serial.print(" us "); Serial.print(Distance); Serial.println(" cm"); CanSetTxBuffer(Duration); if(CanTransmitt(0x100) == 1){ Serial.println("Message Sent Successfully!"); } else { Serial.println("Error Sending Message..."); } delay(500); }
RaspberryPi
まず、下記を実行
sudo ip link set can0 type can bitrate 500000
ソースはこんな感じ。
import RPi.GPIO as GPIO import can import time from struct import * GPIO.setmode(GPIO.BCM) GPIO.setup(25, GPIO.IN) bus = can.interface.Bus(channel = 'can0', bustype='socketcan_native', bitrate=500000, canfilters=None) try: while True: if not(GPIO.input(25)): msg = bus.recv(0) if msg: duration = (msg.data[0] << 8) & 0xFF00 duration |= msg.data[1] & 0xFF distance = duration // 2 distance = distance * 340 * 100 / 1000000 print(hex(duration)) print(distance) except KeyboardInterrupt: GPIO.cleanup()
簡単な解説
mcp2515のINTピン(割込みピン)をRaspberryPiのGPIO25に繋げているため
GPIO.input(25)で割込み判定を実施。
割り込み時はLowレベルになるので、notで判定しています。
後は、受信したデータをデシリアライズして出力しています。
※今思うと、ID100のみ受け取れるようにしないといけないですね。
実行結果
左がArduinoの送信情報(シリアルモニタ)
右側がRaspberryPi(teraterm)の受信情報。
というわけで無事に取りえたい情報を通信できました。
また、距離センサーに手を近づけると、
それらしい反応を出しているのでやりたいことはできているっぽい。
補足
- MCP2561は他のサイトでは、MCP2551で紹介されている。
端子の命名が一部変わっているものの、ほぼ同じものと考えて良いっぽい。
- 紹介した、超音波距離センサモジュールは古いっぽいので
新しいものを買うのを推奨。
メモ
最近は専ら、RaspberryPiを使ってラジコンを作りたいと奮闘中。
上手いこと上記のやりとりをしながら自動停止とかしてみたい。。。