CAN (Controller Area Network) este un protocol de comunicare utilizat pe larg în industria automotive pentru asigurarea transmiterii mesajelor între modulele diferite ale unui automobil. Structura rețelei CAN constă din module, numite noduri, care se conectează în paralel la rețea. Rețeaua este construită pe două cabluri, la capetele cărora stau două rezistoare cu valori de ordinul sutelor de Ohmi. (Fig. 1) În acest articol vom ilustra modul în care poate ficontrolat un motor electric cu ajutorul acestei rețele. Codul sursă utilizat poate fi găsit aici:
Fig. 1 Structura rețelei CAN
Pasul 1. Descărcarea bibliotecilor necesare. Dat fiind faptul că modulul CAN nu este unul prestabilit pentru Arduino, este necesară instalarea unei biblioteci speciale care să asigure comunicarea microcontrollerului cu modulul. Pentru a instala această bibliotecă în PlatformIO, descărcați-o de pe acest link (în format zip). Deschideți o nouă fereastră de terminal și introduceți comanda pio lib -g install drumul_spre_fisier. După executarea acesteia, ar trebui să obțineți un răspuns de genul celui din Fig.2.
Fig. 2 Exemplu de comandă pentru instalarea bibliotecii
Notă: O eroare frecventă de configurare se datorează neincluderi rutei spre PlatformIO în fișierele globale ale sistemului de operare. Aceasta arată în modul următor: command not found: pio .Pentru a realiza aceasta, urmați pașii de mai jos:
Deschideți o fereastră nouă în terminal și introduceți comanda set PATH=%PATH%;%USERPROFILE%\.platformio\penv\bin , unde USERPROFILE e numele de utilizator utilizat pe calculatorul pe care îl configurați
Introduceți echo %PATH% pentru a vă asigura că drumul este configurat corect
Pentru a salva configurația, utilizați setx PATH %PATH%
În final, puteți verifica instalarea prin platformio --version
În cazul în care problema persistă, accesați acest link pentru mai multe informații.
Pasul 2. Programarea modulului pentru controlul motoarelor. Pentru început, vom defini o structură de date care să ne ajute să stocăm ID-ul modulului care a trimis un mesaj pe rețea, tipul mesajului (recepționat sau transmis) și mesajul în sine. Vom creea un tablou unidimensional constituit din mai multe astfel de structuri care să conțină toate mesajele care au fost trimise pe rețea.
enum msg_type
{
RX,
TX
};
struct CAN_Message
{
unsigned char payload[MAX_PAYLOAD_SZ];
msg_type type;
}; //structura care va contine toata informatia dintr-un mesaj
CAN_Message CAN_Matrix[MAX_MODULES]; //matrice care va contine toate mesajele de pe retea
Ulterior trebuie să declarăm un obiect prin intermediul căruia să interacționăm cu rețeaua:
mcp2515_can CAN(SPI_CS_PIN); // Seteaza pin-ul de Chip Select
În funcția setup se vor inițializa pinii necesari, specificându-se tipul acestora (de intrare sau ieșire). Tensiunea pe pinii de ieșire se setează la 0V.
//initializarea pinilor care vor fi folositi
pinMode(ENPIN, OUTPUT);
pinMode(DIRPIN_F, OUTPUT);
pinMode(DIRPIN_B, OUTPUT);
digitalWrite(DIRPIN_F, LOW);
digitalWrite(DIRPIN_B, LOW);
digitalWrite(ENPIN, LOW);
Se introduc în matrice valorile modulului programat. Acestea vor trebui modificate odată cu transmiterea unui nou mesaj pe rețea:
//inserarea in matricea CAN a propriului ID si informatie
unsigned char self_buf[] = {0, 0};
CAN_Matrix[ID].payload[0] = self_buf[0];
CAN_Matrix[ID].payload[1] = self_buf[1];
CAN_Matrix[ID].type = TX;
Se inițializează interfața serială și modulul de CAN:
Serial.begin(9600);
while (!Serial)
{
};
while (CAN_OK != CAN.begin(CAN_500KBPS))
{ // initiaza bus-ul de CAN
Serial.println("CAN init fail, retry...");
delay(100);
}
Serial.println("CAN init ok!");
delay(100);
În funcția loop vom aștepta mesajele. La apariția unui nou mesaj, îl vom stoca în matrice și îl vom interpreta, apelând funcțiile care controlează nemijlocit motorul. Un exemplu pentru scrierea acestor funcții este disponibil în repozitoriul de pe github. Totuși, implementarea acestora poate fi diferită în funcție de tipul motorului.
if (CAN_MSGAVAIL == CAN.checkReceive())
{ // verifica daca sunt date pe CAN
CAN.readMsgBuf(&len, buf); // citeste datele, len: lungimea, buf: mesajul
if (buf[0] == 'F')
{ //daca primul byte din buf este 'F', mergi inainte
if (buf[1] == 'M')
mvForward(10); //daca al doilea byte este M, mergi cu viteza 10 (maxima)
else
mvForward(buf[1]); //daca nu, mergi cu viteza egala cu al doilea byte
time = millis();
} //analog functioneaza rotirea inversa
else if (buf[0] == 'B')
{
if (buf[1] == 'M')
mvBackward(10);
else
mvBackward(buf[1]);
time = millis();
}
CAN_Matrix[CAN.getCanId()].type = RX;
CAN_Matrix[CAN.getCanId()].payload[0] = buf[0];
}
Pentru simplitate, puteți descărca proiectul de pe github. Totuși, este necesar să vă asigurați că valorile variabilelor din configurarea proiectului coesrpund cu cele de care aveți nevoie.
Fig. 3 Fișierul de configurare a proiectului
Este necesar să verificați dacă coincide placa și portul pentru încărcarea codului. De asemenea, ar putea fi necesar să modificați configurațiile din fișierul Config.h. SPI_CS_PIN este dependent de tipul microcontrollerului. Pentru identificarea numărului acestuia, căutați pinout-ul microcontrollerului pe care îl utilizați și căutați care pin este pentru CS. ENPIN, DIRPIN_F, DIRPIN_B, sunt pinii de la puntea H care controlează motorul și trebuie modificați în funcție de alegerea făcută pe partea de hardware. MAX_MODULES indică numărul maxim de module pe rețea, MAX_PAYLOAD_SZ indică lungimea maximă a mesajului transmis, iar ID este identificatorul modulului programat.
Pasul 3. Conectarea modulului de CAN la microcontroller și a punții H la motor. Modulul CAN se conectează la Arduino prin interpediul interfeței de comunicare SPI. Astfel, cablurile vor trebui conectate în modul următor:
Arduino – MCP2515
5V – VCC
GND – GND
D10 – CS
D12 – SO
D11 – SI
D13 – SCK
După realizarea conexiunii dintre modulul CAN și placa Arduino, modulul va trebui conectat la alte module din rețea, în paralel cu acestea. Această conexiune este realizată cu ajutorul pinolor H și L. Este important ca H să fie comun pentru toate modulele și ca L să fie, de asemenea, comun pentru toate modulele din rețea. Cablurile care asigură comunicarea dintre module trebuie răsucite pentru diminuarea zgomotului indus în cabluri.
Atenție! Pinii responsabili de interfața SPI sunt diferiți în funcție de microcontroller. Consultați pinout-ul microcontrollerului folosit înainte de a face conexiunea dintre modulul CAN (MCP2515) și Arduino. De asemenea, două dintre modulele din rețea trebuie să aibă conectat între bornele H și L câte un rezistor de aproximativ 200 Ohm. Acesta este prezent și pe placă, putând fi conectat prin plasarea unui jumper la ieșirea J1. Dacă aveți eroare la detectrea modulului, verificați integritatea cablului care conectează pin-ul CS și setarea acestuia din cod.
Pentru a conecta puntea H la Arduino, Pinii IN1 și IN2 (care definesc direcția de rotație) și EN (care definește viteza de rotație) trebuie conectați la pini digitali ai microcontrollerului. De asemenea, este important ca GND să fie comun. Placa arduino se poate alimenta prin intermediul punții H. În acest caz se va conecta 5V de la modulul L298 la Vin a microcontrollerului. În acest proiect am folosit.
Arduino - L298
Vin – 5V
GND – GND
D6 – IN1
D9 – IN2
D8 – EN
Motorul se va conecta la ieșirea din puntea H. Schema de conectare este disponibilă mai jos:
Pasul 4. Verificarea modulului. Pentru modificarea modulului va fi necesar să asamblăm un alt modul constituit dintr-un Arduino și un modul MCP2515. Conexiunea dintre cele două componente va fi realizată în mod similar primului modul. De asemenea, modulul de CAN va avea conectat jumper-ul J1 și cele două cabluri de conexiune la rețea (H și L), răsucite. Pentru simplitate, vom trimite pe rețea un mesaj în continuu, care să solicite mișcarea motorului înainte cu viteza 9:
#include <SPI.h>
#include "mcp2515_can.h"
const int SPI_CS_PIN = 10;
mcp2515_can CAN(SPI_CS_PIN);
void setup() {
Serial.begin(9600);
while (CAN_OK != CAN.begin(CAN_500KBPS)) {
Serial.println("CAN init fail, retry...");
delay(100);
}
Serial.println("CAN init ok!");
delay(100);
}
void loop() {
unsigned char msg[2] ={'F', '9'}; // front
CAN.sendMsgBuf(0x01, 0, 2, msg);
}
Acest fragment de cod poate fi găsit în același repozitoriu, în fișierul test.cpp. Totuși, pentru a fi încărcat pe modulul pentru test, trebuie să creați un proiect nou pe PlatformIO și să-l configurați corespunzător.
Comments