📄Raspberry Pi PicoとArduino IDEでCAN通信
このまえCANコントローラの無いRaspberry Pi Pico(RP2040)でCAN通信をしました。(CAN通信=ロボマスモーターを回すこと だと思ってる人種)
以前の記事に書いた通り、Arduino UNOはR4になってCANコントローラを内蔵したことは知っていたのですが、実物が手元になかったので試せませんでした。
触る機会がやってきたので回してみました。
以前のコード(RP2040)はArduino CAN互換のCANライブラリで動いていたので、今回はほとんどそのままで、寧ろ削るくらいで回せました。
一番困ったのはArduino UNO R4 MinimaとWiFiでCANRX,TXのピン配置が異なっていたことです。Minima用のピンで動かないなぁと5分くらいクネクネやってました。パッと検索して出てくるピン配置の図にCANの表示も入れてほしいですね。
| UNO R4 Minima / Nano R4 | UNO R4 WiFi |
|---|---|
| D4(CANTX0) | D10(CANTX0) |
| D5(CANRX0) | D13(CANRX0) |
ついでにDamiaoモーター
以前の記事のコードと違ってフィードバック情報のシリアル出力を一定時間毎にしています。1kHzのままでは暴走したのでやめました。クロック周波数がRaspberry Pi Picoの1/3くらいしかないので単純に処理能力の差なんですかね。
/*
UNO R4 Minima/Nano R4
D4(CANTX0)
D5(CANRX0)
UNO R4 WiFi
D10(CANTX0)
D13(CANRX0)
*/
#include <Arduino_CAN.h>
const float P_GAIN = 100.0f; // Pゲイン
const float TARGET_RPS = 10.0f; // 目標回転数
const int16_t CURRENT_LIMIT_MA = 10000; // 電流指令値の制限 (mA) (-10A to +10A)
const uint32_t MOTOR_COMMAND_ID = 0x200; // 指令を送信するCAN ID
float fmap(float x, float in_min, float in_max, float out_min, float out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
void setup() {
Serial.begin(115200);
CAN.begin(CanBitRate::BR_1000k);
}
void loop() {
while (CAN.available()) {
CanMsg rxMsg = CAN.read();
int16_t rotorPositionRaw = (int16_t)(rxMsg.data[0] << 8 | rxMsg.data[1]);
int16_t rpm = (int16_t)(rxMsg.data[2] << 8 | rxMsg.data[3]);
int16_t actualTorqueCurrent = (int16_t)(rxMsg.data[4] << 8 | rxMsg.data[5]);
//data[6] and data[7] are Null
float rotorDegree = fmap(rotorPositionRaw, 0, 8192.0f, 0, 360.0f);
float rps = rpm / 60.0f;
float error = TARGET_RPS - rps;
float targetCurrent = P_GAIN * error;
int16_t commandCurrent = constrain(targetCurrent, -CURRENT_LIMIT_MA, CURRENT_LIMIT_MA);
CanMsg txMsg = {};
txMsg.id = MOTOR_COMMAND_ID;
txMsg.data_length = 8;
txMsg.data[0] = commandCurrent >> 8; // モーターid1 電流値上位バイト8ビット
txMsg.data[1] = commandCurrent; // モーターid1 電流値下位バイト8ビット
// txMsg.data[2] = commandCurrent >> 8; // モーターid2 電流値上位バイト8ビット
// txMsg.data[3] = commandCurrent; // モーターid2 電流値下位バイト8ビット
// txMsg.data[4] = commandCurrent >> 8; // モーターid3 電流値上位バイト8ビット
// txMsg.data[5] = commandCurrent; // モーターid3 電流値下位バイト8ビット
// txMsg.data[6] = commandCurrent >> 8; // モーターid4 電流値上位バイト8ビット
// txMsg.data[7] = commandCurrent; // モーターid4 電流値下位バイト8ビット
CAN.write(txMsg);
static unsigned long lastPrintTime = 0;
if (millis() - lastPrintTime > 10) {
lastPrintTime = millis();
Serial.print("ID: 0x");
Serial.print(rxMsg.id, HEX);
Serial.print(", Angle: ");
Serial.print(rotorDegree);
Serial.print(" deg, RPS: ");
Serial.print(rps);
Serial.print(", Command_mA: ");
Serial.print(commandCurrent);
Serial.print(", Actual_mA: ");
Serial.print(actualTorqueCurrent);
Serial.println();
}
}
delay(1);
} ハードウェアに左右されないコードだと移植が楽すぎて気分がいいです。
Arduino IDE環境のマイコンでは、Arduino UNO R4, RP2040, RP2350, ESP32でCAN通信をしてロボマスモーターを回せました。ついでにDamiaoモーターも回せました。
あとはSTM32だけ。
