Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of CRAC-Strat_copy by
AX12-V2/AX12-V2.cpp
- Committer:
- antbig
- Date:
- 2016-04-23
- Revision:
- 5:dcd817534b57
- Parent:
- 1:116040d14164
- Child:
- 8:0edc7dfb7f7e
File content as of revision 5:dcd817534b57:
#include "AX12-V2.h" struct S_AX12 AX12_data[MAX_AX12];//La liste de tous les AX12 du robot possible, aussi bien par CAN que en local SerialHalfDuplex AX12_Serial1 = SerialHalfDuplex(p9,p10); SerialHalfDuplex AX12_Serial2 = SerialHalfDuplex(p28,p27); int lastAX12Use = 0; FunctionPointer AX12_CallbackEnd;//Fonction de callback lors de la fin d'un mouvement d'un AX12 /****************************************************************************************/ /* FUNCTION NAME: AX12_register */ /* DESCRIPTION : Indiquer qu'un AX12 est connecté à la carte */ /****************************************************************************************/ void AX12_register(unsigned char id, unsigned char serial, unsigned short speed) { int localID = AX12_getLocalID(id); char data[2]; AX12_data[localID].isUsingCAN = 0;//On indique que l'AX12 est connecté localement if(speed > 0x3FF) speed = 0x3FF;//La vitesse ne doit pas depasser 1023 AX12_data[lastAX12Use].speed = speed; AX12_data[lastAX12Use].serial = serial; AX12_Serial1.baud(1000000);//On indique la vitesse de transmission des AX12 AX12_Serial2.baud(1000000);//On indique la vitesse de transmission des AX12 } /****************************************************************************************/ /* FUNCTION NAME: AX12_setGoal */ /* DESCRIPTION : Definir la position d'un ax12, !!Ne déclanche pas le mouvement */ /****************************************************************************************/ void AX12_setGoal(unsigned char id, unsigned short goal, unsigned short speed) { int localID = AX12_getLocalID(id);//On récupère les info sur l'AX12 CANMessage msgTx=CANMessage(); AX12_data[localID].needToUpdate = 1; AX12_data[localID].goal = goal; if(speed > 0x3FF) speed = 0x3FF;//La vitesse ne doit pas depasser 1023 if(speed != 0x3FF) AX12_data[localID].speed = speed; if(AX12_data[localID].isUsingCAN != 0) {//Il faut envoyer la trame CAN car l'AX12 est sur une autre carte msgTx.id=SERVO_AX12_SETGOAL; msgTx.len=5; msgTx.format=CANStandard; msgTx.type=CANData; // id de l'AX12 sur 1 octet msgTx.data[0]=(unsigned char)id; // Position de l'AX12 sur 2 octet msgTx.data[1]=(unsigned char)goal; msgTx.data[2]=(unsigned char)(goal>>8); //Vitesse de l'AX12 sur 2 octet msgTx.data[3]=(unsigned char)AX12_data[localID].speed; msgTx.data[4]=(unsigned char)(AX12_data[localID].speed>>8); can1.write(msgTx); } } /****************************************************************************************/ /* FUNCTION NAME: AX12_isLocal */ /* DESCRIPTION : Savoir si un AX12 est enregistré sur la carte */ /****************************************************************************************/ unsigned char AX12_isLocal(unsigned char id) { int i=0; for(i=0;i<MAX_AX12;i++) { if(AX12_data[i].id == id && AX12_data[i].isUsingCAN == 0) return 1; } return 0; } /****************************************************************************************/ /* FUNCTION NAME: AX12_getLocalID */ /* DESCRIPTION : Obtenir les info sur un AX12 ou l'initialiser si non présent */ /****************************************************************************************/ int AX12_getLocalID(unsigned char id) { int i=0; for(i=0;i<MAX_AX12;i++) { if(AX12_data[i].id == id) return i; } //Si l'AX12 n'est pas déjà initialisé, on l'initialise AX12_data[lastAX12Use].id = id;// AX12_data[lastAX12Use].goal = 0;// AX12_data[lastAX12Use].speed = 0x320;// AX12_data[lastAX12Use].isUsingCAN = 1;//Indique qu'il faut envoyer le message via CAN AX12_data[lastAX12Use].needToUpdate = 0;// lastAX12Use++; return lastAX12Use-1; } /****************************************************************************************/ /* FUNCTION NAME: AX12_notifyCANEnd */ /* DESCRIPTION : indiquer qu'un mouvement d'AX12 CAN est terminé */ /****************************************************************************************/ void AX12_notifyCANEnd(unsigned char id) { if(waitingAckFrom == SERVO_AX12_DONE) { waitingAckFrom = 0; waitingAckID = 0; } } /****************************************************************************************/ /* FUNCTION NAME: AX12_doLoop */ /* DESCRIPTION : Boucle de vérification de la position des AX12 */ /****************************************************************************************/ void AX12_doLoop(void) { int i=0; CANMessage msgTx=CANMessage(); for(i=0;i<MAX_AX12;i++) { if(AX12_data[i].isUsingCAN == 0 && AX12_data[i].needCheckMoving == 1)//Il faut vérifier si l'AX12 a terminé de bouger { if(AX12_isMoving(i) == 0) {//L'AX12 a terminé de bouger AX12_data[i].needCheckMoving = 0; msgTx.id=SERVO_AX12_DONE; msgTx.len=1; msgTx.format=CANStandard; msgTx.type=CANData; // id de l'AX12 sur 1 octet msgTx.data[0]=(unsigned char)AX12_data[i].id; can1.write(msgTx); AX12_notifyCANEnd(AX12_data[i].id); } } } } /****************************************************************************************/ /* FUNCTION NAME: AX12_processChange */ /* DESCRIPTION : Permet de prendre en compte les changement d'instruction des AX12 */ /* Début du mouvement à partir de l'appel de cette fonction */ /****************************************************************************************/ void AX12_processChange(unsigned char fromCan) { int i=0; int dataToSendLength = 0; char dataToSend[100]; for(i=0;i<MAX_AX12;i++) { if(AX12_data[i].needToUpdate == 1) //Il faut mettre à jour la position de l'AX12 { if(AX12_data[i].isUsingCAN == 0)//Il faut envoyer la trame en local { if(dataToSendLength == 0) dataToSend[dataToSendLength++] = 4;//length data dataToSend[dataToSendLength++] = AX12_data[i].id;//ID servo1 dataToSend[dataToSendLength++] = ((1023 * AX12_data[i].goal) / 300) & 0xff;// bottom 8 bits dataToSend[dataToSendLength++] = ((1023 * AX12_data[i].goal) / 300) >> 8; // top 8 bits dataToSend[dataToSendLength++] = (AX12_data[i].speed) & 0xff;// bottom 8 bits dataToSend[dataToSendLength++] = (AX12_data[i].speed) >> 8; // top 8 bits AX12_data[i].needCheckMoving = 1; } AX12_data[i].needToUpdate = 0;//Remise à 0 de l'indicatif de mise à jour } } if(fromCan == 0) SendRawId(SERVO_AX12_PROCESS);//On indique par CAN qu'il faut bouger les AX12 if(dataToSendLength > 0)//Il y a des données à envoyer en local { AX12_syncWrite(AX12_Serial1, AX12_REG_GOAL_POSITION, dataToSendLength, dataToSend); AX12_syncWrite(AX12_Serial2, AX12_REG_GOAL_POSITION, dataToSendLength, dataToSend); } } /****************************************************************************************/ /* FUNCTION NAME: AX12_isMoving */ /* DESCRIPTION : Fonction pour savoir si un AX12 local est entrain de bouger */ /****************************************************************************************/ int AX12_isMoving(unsigned char id) { char data[1]; if(AX12_data[id].serial == 0) AX12_read(AX12_Serial1,AX12_data[id].id,AX12_REG_MOVING,1,data); else AX12_read(AX12_Serial2,AX12_data[id].id,AX12_REG_MOVING,1,data); return(data[0]); } /****************************************************************************************/ /* FUNCTION NAME: AX12_syncWrite */ /* DESCRIPTION : Fonction pour envoyer des trames aux AX12 en mode syncWrite */ /****************************************************************************************/ int AX12_syncWrite(SerialHalfDuplex& AX12_Serial, int start, int bytes, char* data) { //0 : 0xff //1 : 0xff //2 : ID de l'AX12 ou 0xFE pour le broadcast //3 : Length => longueur de la trame //4 : Intruction(write) => id de l'instruction 0x83 pour le syncwrite //5 : Address => addresse du registre à modifier //6+ : Data => les données à transmettre //last : Checksum int ID = 0xFE;//Toujours 0xFE dans le cas d'un broadcast char TxBuf[60]; char sum = 0; int timeout_transmit = 0; int i = 0; printf("Start sending moving trame\n"); // Build the TxPacket first in RAM, then we'll send in one go TxBuf[0] = 0xff; TxBuf[1] = 0xff; // ID TxBuf[2] = ID; sum += TxBuf[2]; // packet Length TxBuf[3] = 3+bytes; sum += TxBuf[3]; // Instruction TxBuf[4]=0x83;//toujours 0x83 dans le cas d'un syncwrite sum += TxBuf[4]; // Start Address TxBuf[5] = start;//addresse du registre à modifier sum += TxBuf[5]; // data for (char i=0; i<bytes ; i++) { TxBuf[6+i] = data[i]; sum += TxBuf[6+i]; printf(" Data : 0x%x\n",TxBuf[6+i]); } // checksum TxBuf[6+bytes] = 0xFF - sum; /* Transmission de la trame construite precedemment dans le tableau TxBuf */ while ((timeout_transmit<100) && (i < (7+bytes))) { if (AX12_Serial.writeable()) { AX12_Serial.putc(TxBuf[i]); i++; timeout_transmit = 0; } else timeout_transmit++; } if (timeout_transmit == 100 ) { // dans le cas d'une sortie en timeout pour ne pas rester bloquer ! return(-1); } // Wait for data to transmit wait (0.005); return(0);//OK trame envoyé } /****************************************************************************************/ /* FUNCTION NAME: AX12_write */ /* DESCRIPTION : Fonction pour envoyer des trames aux AX12 */ /****************************************************************************************/ int AX12_write(SerialHalfDuplex& AX12_Serial, int ID, int start, int bytes, char* data, int flag) { // 0xff, 0xff, ID, Length, Intruction(write), Address, Param(s), Checksum // = AX12_Serial1; char TxBuf[16]; char sum = 0; char Status[6]; int timeout = 0; int plen = 0; int flag_out = 0; int timeout_transmit = 0; int i = 0; /*int poubelle = 0; int count = 0; char vidage[50];*/ typedef enum {Header1, Header2, ident, length, erreur, checksum} type_etat; type_etat etat = Header1; // Build the TxPacket first in RAM, then we'll send in one go TxBuf[0] = 0xff; TxBuf[1] = 0xff; // ID TxBuf[2] = ID; sum += TxBuf[2]; // packet Length TxBuf[3] = 3+bytes; sum += TxBuf[3]; // Instruction if (flag == 1) { TxBuf[4]=0x04; sum += TxBuf[4]; } else { TxBuf[4]=0x03; sum += TxBuf[4]; } // Start Address TxBuf[5] = start; sum += TxBuf[5]; // data for (char i=0; i<bytes ; i++) { TxBuf[6+i] = data[i]; sum += TxBuf[6+i]; } // checksum TxBuf[6+bytes] = 0xFF - sum; /* Transmission de la trame construite precedemment dans le tableau TxBuf */ while ((timeout_transmit<100) && (i < (7+bytes))) { if (AX12_Serial.writeable()) { AX12_Serial.putc(TxBuf[i]); i++; timeout_transmit = 0; } else timeout_transmit++; } if (timeout_transmit == 100 ) { // dans le cas d'une sortie en timeout pour ne pas rester bloquer ! return(-1); } /* Transmission effectuée on va ensuite récuperer la trame de retour renvoyer par le servomoteur */ // Wait for data to transmit wait (0.005); // make sure we have a valid return Status[4]=0x00; // we'll only get a reply if it was not broadcast if (ID!=0xFE) { /* Partie de reception de la trame de retour */ while ((flag_out != 1) && (timeout < MAX_TIMEOUT)) { // Les differents etats de l'automate on été créés au debut de la fonction write ! switch (etat) { case Header1: if (AX12_Serial.readable()) { // reception du premier Header ( 0xFF ) Status[plen] = AX12_Serial.getc(); timeout = 0; if (Status[plen] == 0xFF ) { etat = Header2; plen++; } else etat = Header1; } else timeout++; break; case Header2: if (AX12_Serial.readable()) { // reception du second Header ( 0xFF ) Status[plen] = AX12_Serial.getc(); timeout = 0; if (Status[plen] == 0xFF ) { etat = ident; plen++; } else { etat = Header1; plen = 0; } } else timeout++; break; case ident: if (AX12_Serial.readable()) { // reception de l'octet correspondant à l'ID du servomoteur Status[plen] = AX12_Serial.getc(); timeout = 0; if (Status[plen] == ID ) { etat = length; plen++; } else { etat = Header1; plen = 0; } } else timeout++; break; case length: if (AX12_Serial.readable()) { // reception de l'octet correspondant à la taille ( taille = 2 + nombre de paramètres ) Status[plen] = AX12_Serial.getc(); timeout = 0; if (Status[plen] == 2 ) { // dans la trame de retour d'un write il n'y a pas de paramètre la taille vaudra donc 2!! etat = erreur; plen++; } else { etat = Header1; plen = 0; } } else timeout++; break; case erreur: if (AX12_Serial.readable()) { //reception de l'octet correspondant au code d'erreurs eventuels ( 0 = pas d'erreur ) Status[plen] = AX12_Serial.getc(); timeout = 0; plen++; etat = checksum; } else timeout++; case checksum: if (AX12_Serial.readable()) { // recpetion du dernier octet ( Checksum ) >>> checksum = NOT ( ID + length ) >>>> dans le cas de la reception d'un write Status[plen] = AX12_Serial.getc(); timeout = 0; flag_out = 1; etat = Header1; } else timeout++; break; } } if (timeout == MAX_TIMEOUT ) { // permet d'afficher si il y a une erreur de timeout et de ne pas rester bloquer si il y a des erreurs de trames return(-1); } // Build the TxPacket first in RAM, then we'll send in one go } return(Status[4]); // retourne le code d'erreur ( octect 5 de la trame de retour ) } /****************************************************************************************/ /* FUNCTION NAME: AX12_read */ /* DESCRIPTION : Lire des données dans un registre de l'AX12 */ /****************************************************************************************/ int AX12_read(SerialHalfDuplex& AX12_Serial, int ID, int start, int bytes, char* data) { //SerialHalfDuplex AX12_Serial = AX12_Serial1; char PacketLength = 0x3; char TxBuf[16]; char sum = 0; char Status[16]; int timeout = 0; int plen = 0; int flag_out = 0; int timeout_transmit = 0; int i = 0; int enable = 0; // int poubelle = 0; // int count = 0; // char vidage[50]; typedef enum {Header1, Header2, ident, length, erreur, reception, checksum} type_etat; type_etat etat = Header1; Status[4] = 0xFE; // return code /*********************************** CREATION DE LA TRAME A EVOYER *****************************************/ // Build the TxPacket first in RAM, then we'll send in one go TxBuf[0] = 0xff; TxBuf[1] = 0xff; // ID TxBuf[2] = ID; sum += TxBuf[2]; // Packet Length TxBuf[3] = PacketLength+bytes; // Length = 4 ; 2 + 1 (start) = 1 (bytes) sum += TxBuf[3]; // Accululate the packet sum // Instruction - Read TxBuf[4] = 0x2; sum += TxBuf[4]; // Start Address TxBuf[5] = start; sum += TxBuf[5]; // Bytes to read TxBuf[6] = bytes; sum += TxBuf[6]; // Checksum TxBuf[7] = 0xFF - sum; /********************************************TRAME CONSTRUITE DANS TxBuf***************************************/ /* Transmission de la trame construite precedemment dans le tableau TxBuf */ while ((timeout_transmit<1000) && (i < (7+bytes))) { if (AX12_Serial.writeable()) { AX12_Serial.putc(TxBuf[i]); i++; timeout_transmit = 0; } else timeout_transmit++; } if (timeout_transmit == 1000 ) { // dans le cas d'une sortie en timeout pour ne pas rester bloquer ! return(-1); } /* Transmission effectuée on va ensuite récuperer la trame de retour renvoyer par le servomoteur */ // Wait for the bytes to be transmitted wait (0.001); // Skip if the read was to the broadcast address if (ID != 0xFE) { /* Partie de reception de la trame de retour */ while ((flag_out != 1) && (timeout < (1000*bytes))) { // Les differents etats de l'automate on été créés au debut de la fonction write ! switch (etat) { case Header1: if (AX12_Serial.readable()) { // reception du premier Header ( 0xFF ) Status[plen] = AX12_Serial.getc(); timeout = 0; if (Status[plen] == 0xFF ) { etat = Header2; plen++; } else etat = Header1; } else timeout++; break; case Header2: if (AX12_Serial.readable()) { // reception du second Header ( 0xFF ) Status[plen] = AX12_Serial.getc(); timeout = 0; if (Status[plen] == 0xFF ) { etat = ident; plen++; } else if (Status[plen] == ID ) { // PERMET D'EVITER CERTAINES ERREUR LORSQU'ON LIT PLUSIEURS REGISTRES !!!! Status[plen] = 0; plen++; Status[plen] = ID; etat = length; plen++; } else { etat = Header1; plen = 0; } } else timeout++; break; case ident: if (AX12_Serial.readable()) { // reception de l'octet correspondant à l'ID du servomoteur Status[plen] = AX12_Serial.getc(); timeout = 0; if (Status[plen] == ID ) { etat = length; plen++; } else { etat = Header1; plen = 0; } } else timeout++; break; case length: if (AX12_Serial.readable()) { // reception de l'octet correspondant à la taille ( taille = 2 + nombre de paramètres ) Status[plen] = AX12_Serial.getc(); timeout = 0; if (Status[plen] == (bytes+2) ) { etat = erreur; plen++; } else { etat = Header1; plen = 0; } } else timeout++; break; case erreur: if (AX12_Serial.readable()) { //reception de l'octet correspondant au code d'erreurs eventuels ( 0 = pas d'erreur ) Status[plen] = AX12_Serial.getc(); timeout = 0; plen++; etat = reception; } else timeout++; case reception: while ( enable < bytes ) { // reception du ou des octect(s) de donnés ( suivant la valeur de la variable length ) if (AX12_Serial.readable()) { Status[plen] = AX12_Serial.getc(); timeout = 0; plen++; enable++; } else timeout++; } etat = checksum; break; case checksum: if (AX12_Serial.readable()) { // reception du dernier octet ( Checksum ) >>> checksum = NOT ( ID + length + somme des données ) >>>> dans le cas d'un retour d'un read!! Status[plen] = AX12_Serial.getc(); timeout = 0; flag_out = 1; etat = Header1; } else timeout++; break; default: break; } } if (timeout == (1000*bytes) ) { // permet d'afficher si il y a une erreur de timeout et de ne pas rester bloquer si il y a des erreurs de trames return(-1); } // copie des données dans le tableau data for (int i=0; i < Status[3]-2 ; i++) { data[i] = Status[5+i]; } } // toute la partie precedente ne s'effectue pas dans le cas d'un appel avec un broadcast ID (ID!=0xFE) return(Status[4]); // retourne le code d'erreur ( octect 5 de la trame de retour ) }