Programme d'utilisation des AX12 avec rajout de l'MX12

Fork of test_carteAToutFaire_PR by CRAC Team

AX12/AX12.cpp

Committer:
R66Y
Date:
2017-05-20
Revision:
3:1bb26049bdd1
Parent:
1:f3f702086a30

File content as of revision 3:1bb26049bdd1:

/* mbed AX-12+ Servo Library
 *
 * Copyright (c) 2010, cstyles (http://mbed.org)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "mbed.h"
#include "AX12.h"

#define MAX_TIMEOUT 500

extern Timer t;

typedef struct 
{
    unsigned short Model_Number;
    unsigned char Firmware;
    unsigned char ID;
    unsigned char Baud_Rate;
    unsigned char Return_Delay_Time;
    unsigned short CW_Angle_Limit;
    unsigned short CCW_Angle_Limit;
    unsigned char Reserved1;
    unsigned char Highest_Limit_Temperature;
    unsigned char Lowest_Limit_voltage;
    unsigned char Highest_Limit_voltage;
    unsigned short Max_Torque;
    unsigned char Status_Return_Level;
    unsigned char Alarm_LED;
    unsigned char Alarm_Shutdown;
    unsigned char Reserved2;
    unsigned short Down_Calibration;
    unsigned short Up_Calibration;
    unsigned char Torque_Enable;
    unsigned char LED;
    unsigned char CW_Compliance_Margin;
    unsigned char CCW_Compliance_Margin;
    unsigned char CW_Compliance_Slope;
    unsigned char CCW_Compliance_Slope;
    unsigned short Goal_Position;
    unsigned short Moving_Speed;
    unsigned short Torque_Limit;
    unsigned short Present_Position;
    unsigned short Present_Speed;
    unsigned short Present_Load;
    unsigned char Present_Voltage;
    unsigned char Present_Temperature;
    unsigned char Registered_Instruction;
    unsigned char Reserved3;
    unsigned char Moving;    
    unsigned char Lock;
    unsigned short Punch;
} T_AX12;


AX12::AX12(PinName tx, PinName rx, int ID, int baud)
    : _ax12(tx,rx)
{
    _baud = baud;
    _ID = ID;
    _ax12.baud(_baud);
    

}

int AX12::Set_Secure_Goal(int degres)
{
    int error = 0;
    int position = 0;
    int difference = 0;
    int timeout_secure = 0;
    int autorisation = 0;
    
    position = Get_Position();
    error = Set_Goal(degres);
    
    while ((autorisation == 0) && (timeout_secure < 100) ) 
    {
        position = Get_Position();
        //printf("position : %d", position );
        error = Set_Goal(degres);
        //printf("degres : %d", degres);
        difference = degres - position;
        //printf ("difference : %d", difference );
        if (((difference < 2) && (difference > (-2) )))
        autorisation = 1;
        
        timeout_secure++;
    }
    
    if ( timeout_secure == 100)
    {
        #ifdef AX12_DEBUG
        printf (" timeout secure error ");
        #endif
        return(-1);    
    }
    return(error);
}


int AX12::Get_Return_Delay_Time(void)
{
    char data[1];
    int ErrorCode = read(_ID, AX12_REG_DELAY_TIME, 1, data);
    int time = data[0];
    time = 2.0 * time;
    return(time);
}


int AX12::Get_Baud_Rate(void)
{
    char data[1];
    int ErrorCode = read(_ID, AX12_REG_BAUD, 1, data);
    int baud = data[0];
    baud = 2000000 / ( baud + 1 );
    return(baud);
}


/** Reglage du courant minimum necessaire au bon fonctionnement de l'actionneur 
//  minimum >>  Ox000    >>  decimal  0
//  maximum >>  0x3FF    >>  decimal  1023
//  deflaut >>  0x20     >>  decimal  32
*/
int AX12::Set_Punch(int punch)
{
    char data[2];

    data[0] = punch & 0xff; // bottom 8 bits
    data[1] = punch >> 8;   // top 8 bits

    // write the packet, return the error code
    return (write(_ID, AX12_REG_PUNCH, 2, data));

}

/** Reset
*/
int AX12::Reset(int punch)
{
    char data[2];

    data[0] = punch & 0xff; // bottom 8 bits
    data[1] = punch >> 8;   // top 8 bits

    // write the packet, return the error code
    return (write(_ID, 0x06, 1,data));

}

int AX12::Get_Punch (void)
{
    char data[2];
    int ErrorCode = read(_ID, AX12_REG_PUNCH, 2, data);
    int punch = data[0] | (data[1]<<8);
    return(punch);
}


int AX12::Get_Load_Direction (void)
{
    char data[2];
    int ErrorCode = read(_ID, AX12_REG_PRESENT_LOAD, 2, data);
    int direction = (data[1]>>2) & 0x01;
    return(direction);
}


int AX12::Get_Load_Value (void)
{
    char data[2];
    int ErrorCode = read(_ID, AX12_REG_PRESENT_LOAD, 2, data);
    int Load = (data[0] | (data[1]<<8)) & 0x3FF;
    return(Load);
}


int AX12::Get_Present_Speed (void)
{
    char data[2];
    int ErrorCode = read(_ID, AX12_REG_PRESENT_SPEED, 2, data);
    int speed = data[0] | (data[1]<<8);
    return(speed);
}


int AX12::Get_CCW_Angle_Limit (void)
{
    char data[2];
    int ErrorCode = read(_ID, AX12_REG_CCW_LIMIT, 2, data);
    int angle = data[0] | (data[1]<<8);
    angle = (angle * 300) / 1023;
    return(angle);
}


int AX12::Get_CW_Angle_Limit (void)
{
    char data[2];
    int ErrorCode = read(_ID, AX12_REG_CW_LIMIT, 2, data);
    int angle = data[0] | (data[1]<<8);
    angle = (angle * 300) / 1023;
    return(angle);
}



int AX12::Get_Torque_Enable(void)
{
    char data[1];
    int ErrorCode = read(_ID, AX12_REG_TORQUE_ENABLE, 1, data);
    int enable = data[0];
    return(enable);
}


int AX12::Set_Torque_Enable(int etat) 
{
    char data[1];
    data [0] = etat;
    
    int error = write(_ID, AX12_REG_TORQUE_ENABLE, 1, data);
    return (error);
}



int AX12::Get_Up_Calibration (void)
{
    char data[1];
    int ErrorCode = read(_ID, AX12_REG_UP_CALIBRATION, 2, data);
    int Up_calibration = data[0] | (data[1]<<8);
    return(Up_calibration);
}



int AX12::Get_Down_Calibration (void)
{
    char data[1];
    int ErrorCode = read(_ID, AX12_REG_DOWN_CALIBRATION, 2, data);
    int Dowm_calibration = data[0] | (data[1]<<8);
    return(Dowm_calibration);
}



int AX12::Get_ID(void)
{

    char data[1]={-1};
    int ErrorCode = read(_ID, AX12_REG_ID, 1, data);
    int id = data[0];
    return(id);
}


// Lecture du couple maximum ( retourne la valeur du registre Max Torque de l'AX12 ) 
int AX12::Get_Max_Torque (void)
{
    char data[2];
    int ErrorCode = read(_ID, AX12_REG_MAX_TORQUE, 2, data);
    int torque = data[0] | (data[1]<<8);
    return(torque);
}



/** Reglage du couple maximum de l'actionneur 
//  minimum >>  Ox000    >>  decimal  0
//  maximum >>  0x3FF    >>  decimal  1023
//  deflaut >>           >>  decimal  
*/
int AX12::Set_Max_Torque(int torque)
{
    char data[2];

    data[0] = torque & 0xff; // bottom 8 bits
    data[1] = torque >> 8;   // top 8 bits

    // write the packet, return the error code
    return (write(_ID, AX12_REG_MAX_TORQUE, 2, data));

}




/** Reglage de la desactivation des actionneurs si une erreur le concernant se produit 
Bit                 Function
Bit 7               0
Bit 6               If set to 1, torque off when an Instruction Error occurs 
Bit 5               If set to 1, torque off when an Overload Error occurs 
Bit 4               If set to 1, torque off when a Checksum Error occurs 
Bit 3               If set to 1, torque off when a Range Error occurs 
Bit 2               If set to 1, torque off when an Overheating Error occurs 
Bit 1               If set to 1, torque off when an Angle Limit Error occurs 
Bit 0               If set to 1, torque off when an Input Voltage Error occurs
*/
int AX12::Set_Alarm_Shutdown(int valeur) 
{
    char data[1];
    data [0] = valeur;
    
    int val_alarm_shutdown = write(_ID, AX12_REG_ALARM_SHUTDOWN, 1, data);
    return (val_alarm_shutdown);
}



/** Reglage de l'activation de l'alarme
Bit                 Function
Bit 7               0
Bit 6               If set to 1, the LED blinks when an Instruction Error occurs
Bit 5               If set to 1, the LED blinks when an Overload Error occurs
Bit 4               If set to 1, the LED blinks when a Checksum Error occurs
Bit 3               If set to 1, the LED blinks when a Range Error occurs
Bit 2               If set to 1, the LED blinks when an Overheating Error occurs
Bit 1               If set to 1, the LED blinks when an Angle Limit Error occurs
Bit 0               If set to 1, the LED blinks when an Input Voltage Error occurs
*/
int AX12::Set_Alarm_LED(int valeur) 
{
    char data[1];
    data [0] = valeur;
    
    int val_alarmLED = write(_ID, AX12_REG_ALARM_LED, 1, data);
    return (val_alarmLED);
}




// Reglage de la réponse à une instruction  
//  0   >>  ne repond a aucune instructions
//  1   >>  repond seulement aux instructions READ_DATA 
//  2   >>  repond à toutes les instructions 
int AX12::Set_Status_Return_Level(int etat) 
{
    char data[1];
    data [0] = etat;
    
    int val_return_lvl = write(_ID, AX12_REG_SATUS_RETURN, 1, data);
    return (val_return_lvl);
}


// Reglage de la tension minimale 
//  minimum >>  Ox32    >>  decimal  50
//  maximum >>  0xFA    >>  decimal  250
//  deflaut >>  0x3C    >>  decimal  60
int AX12::Set_Lowest_Voltage(int val_lowest_voltage) 
{
    char data[1];
    data [0] = val_lowest_voltage;
    
    int val_lowvolt = write(_ID, AX12_REG_LOWEST_VOLTAGE, 1, data);
    return (val_lowvolt);
}


// Reglage de la tension maximale
//  minimum >>  Ox32    >>  decimal  50
//  maximum >>  0xFA    >>  decimal  250
//  deflaut >>  0xBE    >>  decimal  190
int AX12::Set_Highest_Voltage(int val_highest_voltage) 
{
    char data[1];
    data [0] = val_highest_voltage;
    
    int val_highvolt = write(_ID, AX12_REG_HIGHEST_VOLTAGE, 1, data);
    return (val_highvolt);
}


// Reglage du return time delay  EN MICRO SECONDE              2uSec * val_delay_time
//  minimum >>  0       us 
//  maximum >>  508     us
//  deflaut >>  125     us
int AX12::Set_Delay_Time (int val_delay_time )
 {
    char data[1];
    data [0] = val_delay_time/2.0;
    
    int valdelay_time = write(_ID, AX12_REG_DELAY_TIME, 1, data);          
    return (valdelay_time );
 }


// Reglage de la température max du cervo 
//  minimum >>  Ox00    >>  decimal  0
//  maximum >>  0x96    >>  decimal  150
int AX12::Set_Temperature_Max (int val_temperature )
 {
    char data[1];
    data [0] = val_temperature;
    
    int valtemp_max = write(_ID, AX12_REG_TEMP_MAX, 1, data);          
    return (valtemp_max );
 }

// Etat LED 
//  0 = off
//  1 = on 
int AX12::Set_Etat_LED(int etat) 
{
    char data[1];
    data [0] = etat;
    
    int valLED = write(_ID, AX12_REG_LED, 1, data);
    return (valLED);
}

// Set the mode of the servo
//  0 = Positional (0-300 degrees)
//  1 = Rotational -1 to 1 speed
int AX12::Set_Mode(int mode)
{

    if (mode == 1) { // set CR
        //wait(0.001);
        Set_CW_Angle_Limit(0);
        //wait(0.001);
        Set_CCW_Angle_Limit(0);
        //wait(0.001);
        Set_CR_Speed(0.0);
        //wait(0.001);
    } else {
        //wait(0.001);
        Set_CW_Angle_Limit(0);
        //wait(0.001);
        Set_CCW_Angle_Limit(300);
        //wait(0.001);
        Set_CR_Speed(0.0);
        //wait(0.001);
    }
    return(0);
}

int AX12::Set_Goal_speed(int speed, int flags)
{

     char reg_flag = 0;
    char data[2];

    // set the flag is only the register bit is set in the flag
    if (flags == 0x2) {
        reg_flag = 1;
    }

    data[0] = speed & 0xff; // bottom 8 bits
    data[1] = speed >> 8;   // top 8 bits

    // write the packet, return the error code
    int rVal = write(_ID, AX12_REG_MOVING_SPEED, 2, data, reg_flag);

    /*if (flags == 1) {
        // block until it comes to a halt
        while (isMoving()) 
            {
            }
    
    }*/
    return(rVal);
}


// if flag[0] is set, were blocking
// if flag[1] is set, we're registering
// they are mutually exclusive operations
int AX12::Set_Goal(int degrees, int flags)
{

    char reg_flag = 0;
    char data[2];

    // set the flag is only the register bit is set in the flag
    if (flags == 0x2) {
        reg_flag = 1;
    }

    // 1023 / 300 * degrees
    short goal = (1023 * degrees) / 300;
#ifdef AX12_DEBUG
    printf("SetGoal to 0x%x\n",goal);
#endif

    data[0] = goal & 0xff; // bottom 8 bits
    data[1] = goal >> 8;   // top 8 bits

    // write the packet, return the error code
    int rVal = write(_ID, AX12_REG_GOAL_POSITION, 2, data, reg_flag);

    /*if (flags == 1) {
        // block until it comes to a halt
        while (isMoving()) 
            {
            }
    
    }*/
    return(rVal);
}


// Set continuous rotation speed from -1 to 1
int AX12::Set_CR_Speed(float speed)
{

    // bit 10     = direction, 0 = CCW, 1=CW
    // bits 9-0   = Speed
    char data[2];

    int goal = (0x3ff * abs(speed));

    // Set direction CW if we have a negative speed
    if (speed < 0) {
        goal |= (0x1 << 10);
    }

    data[0] = goal & 0xff; // bottom 8 bits
    data[1] = goal >> 8;   // top 8 bits

    // write the packet, return the error code
    int rVal = write(_ID, 0x20, 2, data);

    return(rVal);
}


int AX12::Set_CW_Angle_Limit (int degrees)
{

    char data[2];

    // 1023 / 300 * degrees
    short limit = (1023 * degrees) / 300;

#ifdef AX12_DEBUG
    printf("SetCWLimit to 0x%x\n",limit);
#endif

    data[0] = limit & 0xff; // bottom 8 bits
    data[1] = limit >> 8;   // top 8 bits

    // write the packet, return the error code
    return (write(_ID, AX12_REG_CW_LIMIT, 2, data));

}

int AX12::Set_CCW_Angle_Limit (int degrees)
{

    char data[2];

    // 1023 / 300 * degrees
    short limit = (1023 * degrees) / 300;

#ifdef AX12_DEBUG
    printf("SetCCWLimit to 0x%x\n",limit);
#endif

    data[0] = limit & 0xff; // bottom 8 bits
    data[1] = limit >> 8;   // top 8 bits

    // write the packet, return the error code
    return (write(_ID, AX12_REG_CCW_LIMIT, 2, data));
}


int AX12::Set_ID (int CurrentID, int NewID)
{

    char data[1];
    data[0] = NewID;

#ifdef AX12_DEBUG
    printf("Setting ID from 0x%x to 0x%x\n",CurrentID,NewID);
#endif

    return (write(CurrentID, AX12_REG_ID, 1, data));

}


int AX12::Set_Baud (int baud)
{

    char data[1];
    data[0] = baud;

#ifdef AX12_DEBUG
    printf("Setting Baud rate to %d\n",baud);
#endif

    return (write(_ID, AX12_REG_BAUD, 1, data));

}



// return 1 is the servo is still in flight
int AX12::isMoving(void)
{

    char data[1];
    read(_ID,AX12_REG_MOVING,1,data);
    return(data[0]);
}

void AX12::reset()
{

    unsigned char TxBuf[16];
    unsigned char sum = 0;
    unsigned long debut=0;

#ifdef AX12_TRIGGER_DEBUG
    // Build the TxPacket first in RAM, then we'll send in one go
    printf("\nreset\n");
    printf("\nreset Packet\n  Header : 0xFF, 0xFF\n");
#endif

    TxBuf[0] = 0xFF;
    TxBuf[1] = 0xFF;

    // ID - Broadcast
    TxBuf[2] =_ID;
    sum += TxBuf[2];

#ifdef AX12_TRIGGER_DEBUG
    printf("  ID : %d\n",TxBuf[2]);
#endif

    // Length
    TxBuf[3] = 0x02;
    sum += TxBuf[3];

#ifdef AX12_TRIGGER_DEBUG
    printf("  Length %d\n",TxBuf[3]);
#endif

    // Instruction - ACTION
    TxBuf[4] = 0x06;  //reset
    sum += TxBuf[4];

#ifdef AX12_TRIGGER_DEBUG
    printf("  Instruction 0x%X\n",TxBuf[5]);
#endif

    // Checksum
    TxBuf[5] = 0xFF - sum;
//#ifdef AX12_TRIGGER_DEBUG
    printf("  Checksum 0x%X\n",TxBuf[5]);
//#endif

    // Transmit the packet in one burst with no pausing
    for (int i = 0; i < 6 ; i++) 
    {
        while(_ax12.writeable()==0); 
            _ax12.putc(TxBuf[i]);
            
    }
    wait(0.001);
    debut=t.read_ms();
    
        do
        {
            if (_ax12.readable()==-1)       // reception du premier Header ( 0xFF )
                printf("%02x",_ax12.getc());
        }
        while((t.read_ms()-debut)<500);
    
    printf("\n");
    return;
}

void AX12::read_all_info(unsigned char start, unsigned char longueur)
{

    unsigned char TxBuf[16];
    unsigned char sum = 0;
    unsigned long debut=0;

#ifdef AX12_TRIGGER_DEBUG
    // Build the TxPacket first in RAM, then we'll send in one go
    printf("\nreset\n");
    printf("\nreset Packet\n  Header : 0xFF, 0xFF\n");
#endif

    TxBuf[0] = 0xFF;
    TxBuf[1] = 0xFF;

    // ID - Broadcast
    TxBuf[2] =_ID;
    sum += TxBuf[2];

#ifdef AX12_TRIGGER_DEBUG
    printf("  ID : %d\n",TxBuf[2]);
#endif

    // Length
    TxBuf[3] = 0x04;
    sum += TxBuf[3];

#ifdef AX12_TRIGGER_DEBUG
    printf("  Length %d\n",TxBuf[3]);
#endif

    // Instruction - ACTION
    TxBuf[4] = INST_READ;  //reset
    sum += TxBuf[4];

#ifdef AX12_TRIGGER_DEBUG
    printf("  Instruction 0x%X\n",TxBuf[4]);
#endif

    TxBuf[5] = start;  //reset
    sum += TxBuf[5];

    TxBuf[6] = longueur;  //reset
    sum += TxBuf[6];


    // Checksum
    TxBuf[7] = 0xFF - sum;
//#ifdef AX12_TRIGGER_DEBUG
    //printf("  Checksum 0x%X\n\r",TxBuf[7]);
//#endif

    // Transmit the packet in one burst with no pausing
    for (int i = 0; i < 8 ; i++) 
    {
        while(_ax12.writeable()==0); 
            _ax12.putc(TxBuf[i]);
            
    }
    
    debut=t.read_ms();
    int i=0;
        do
        {
            if (_ax12.readable())
            {       // reception du premier Header ( 0xFF )
                printf("%02d:%02x ",start+i,_ax12.getc());
                i++;
            }
        }
        while((t.read_ms()-debut)<5000);
    
    printf("\n");
    return;
}


void AX12::trigger(void)
{

    char TxBuf[16];
    char sum = 0;

#ifdef AX12_TRIGGER_DEBUG
    // Build the TxPacket first in RAM, then we'll send in one go
    printf("\nTriggered\n");
    printf("\nTrigger Packet\n  Header : 0xFF, 0xFF\n");
#endif

    TxBuf[0] = 0xFF;
    TxBuf[1] = 0xFF;

    // ID - Broadcast
    TxBuf[2] = 0xFE;
    sum += TxBuf[2];

#ifdef AX12_TRIGGER_DEBUG
    printf("  ID : %d\n",TxBuf[2]);
#endif

    // Length
    TxBuf[3] = 0x02;
    sum += TxBuf[3];

#ifdef AX12_TRIGGER_DEBUG
    printf("  Length %d\n",TxBuf[3]);
#endif

    // Instruction - ACTION
    TxBuf[4] = 0x04;
    sum += TxBuf[4];

#ifdef AX12_TRIGGER_DEBUG
    printf("  Instruction 0x%X\n",TxBuf[5]);
#endif

    // Checksum
    TxBuf[5] = 0xFF - sum;
#ifdef AX12_TRIGGER_DEBUG
    printf("  Checksum 0x%X\n",TxBuf[5]);
#endif

    // Transmit the packet in one burst with no pausing
    for (int i = 0; i < 6 ; i++) {
        _ax12.putc(TxBuf[i]);
    }

    // This is a broadcast packet, so there will be no reply
    return;
}


float AX12::Get_Position(void)
{

    #ifdef AX12_DEBUG
    printf("\nGetPositionID(%d)",_ID);
    #endif

    char data[2];

    int ErrorCode = read(_ID, AX12_REG_POSITION, 2, data);
    int position = data[0] | (data[1] << 8);
    float angle = ((float)position * 300.0)/1023.0;

    return (angle);
}


float AX12::Get_Temp ()
{

#ifdef AX12_DEBUG
    printf("\nGetTemp(%d)",_ID);
#endif

    char data[1];
    int ErrorCode = read(_ID, AX12_REG_TEMP, 1, data);
    float temp = data[0];
    return(temp);
}


float AX12::Get_Volts (void)
{

#ifdef AX12_DEBUG
    printf("\nGetVolts(%d)",_ID);
#endif

    char data[1];
    int ErrorCode = read(_ID, AX12_REG_VOLTS, 1, data);
    float volts = data[0]/10.0;
    return(volts);
}


int AX12::read(int ID, int start, int bytes, char* data) {


    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 *****************************************/
 
#ifdef AX12_READ_DEBUG
    printf("\nread(%d,0x%x,%d,data)\n",ID,start,bytes);
#endif
 
    // Build the TxPacket first in RAM, then we'll send in one go
#ifdef AX12_READ_DEBUG
    printf("\nInstruction Packet\n  Header : 0xFF, 0xFF\n");
#endif
 
    TxBuf[0] = 0xff;
    TxBuf[1] = 0xff;
 
    // ID
    TxBuf[2] = ID;
    sum += TxBuf[2];
 
#ifdef AX12_READ_DEBUG
    printf("  ID : %d\n",TxBuf[2]);
#endif
 
    // Packet Length
    TxBuf[3] = 4;//PacketLength+bytes;    // Length = 4 ; 2 + 1 (start) = 1 (bytes)
    sum += TxBuf[3];            // Accululate the packet sum
 
#ifdef AX12_READ_DEBUG
    printf("  Length : 0x%x\n",TxBuf[3]);
#endif
 
    // Instruction - Read
    TxBuf[4] = 0x2;
    sum += TxBuf[4];
 
#ifdef AX12_READ_DEBUG
    printf("  Instruction : 0x%x\n",TxBuf[4]);
#endif
 
    // Start Address
    TxBuf[5] = start;
    sum += TxBuf[5];
 
#ifdef AX12_READ_DEBUG
    printf("  Start Address : 0x%x\n",TxBuf[5]);
#endif
 
    // Bytes to read
    TxBuf[6] = bytes;
    sum += TxBuf[6];
 
#ifdef AX12_READ_DEBUG
    printf("  No bytes : 0x%x\n",TxBuf[6]);
#endif
 
    // Checksum
    TxBuf[7] = 0xFF - sum;
#ifdef AX12_READ_DEBUG
    printf("  Checksum : 0x%x\n",TxBuf[7]);
#endif
/********************************************TRAME CONSTRUITE DANS TxBuf***************************************/



    
    /* Transmission de la trame construite precedemment dans le tableau TxBuf 
    */
    while ((timeout_transmit<5000) && (i < (7+bytes)))
    {
        if (_ax12.writeable())  
        {
            _ax12.putc(TxBuf[i]);
            i++;
            timeout_transmit = 0;
        }
        else timeout_transmit++;
    }
    
    if (timeout_transmit == 5000 )   // dans le cas d'une sortie en timeout pour ne pas rester bloquer !
        {
            #ifdef AX12_DEBUG
            printf ("timeout transmit erreur\r\n");
            #endif
            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.readable())       // reception du premier Header ( 0xFF )
                        { 
                        Status[plen] = _ax12.getc();
                        timeout = 0;
                            if (Status[plen] == 0xFF )
                            {
                                etat = Header2;
                                #ifdef AX12_DEBUG_READ
                                    printf("data[%d]  : %d\r\n", plen, (int)Status[plen]);
                                #endif
                                plen++; 
                                
                            }
                            else etat = Header1;
                        }
                        else timeout++;
                        break;
                    
     
     case Header2:      if (_ax12.readable())       // reception du second Header ( 0xFF )
                        { 
                            Status[plen] = _ax12.getc();
                            timeout = 0;
                            if (Status[plen] == 0xFF )
                            {
                                etat = ident;
                                #ifdef AX12_DEBUG_READ
                                    printf("data[%d]  : %d\r\n", plen, (int)Status[plen]);
                                #endif
                                plen++; 
                                
                            }
                            else if (Status[plen] == ID )  // PERMET D'EVITER CERTAINES ERREUR LORSQU'ON LIT PLUSIEURS REGISTRES !!!!
                            {   
                                Status[plen] = 0;
                                #ifdef AX12_DEBUG_READ
                                    printf("data[%d]  : %d\r\n", plen, (int)Status[plen]);
                                #endif
                                plen++;
                                Status[plen] = ID;
                                etat = length;
                                #ifdef AX12_DEBUG_READ
                                    printf("data[%d]  : %d\r\n", plen, (int)Status[plen]);
                                #endif
                                plen++; 
                                
                            }
                            else 
                            {
                                
                                etat = Header1;
                                plen = 0;
                            }
                        }
                        else timeout++;
                        break;
     
     case ident:        if (_ax12.readable())       // reception de l'octet correspondant à l'ID du servomoteur
                        {
                            Status[plen] = _ax12.getc();
                            timeout = 0;
                            if (Status[plen] == ID )
                            {
                                etat = length;
                                #ifdef AX12_DEBUG_READ
                                    printf("data[%d]  : %d\r\n", plen, (int)Status[plen]);
                                #endif
                                plen++; 
                                
                            }
                            else 
                            {
                                etat = Header1;
                                plen = 0;
                            }
                        }
                        else timeout++;
                        break;
     
     case length:       if (_ax12.readable())          // reception de l'octet correspondant à la taille ( taille = 2 + nombre de paramètres )
                        {
                            Status[plen] = _ax12.getc();
                            timeout = 0;
                            if (Status[plen] == (bytes+2) )
                            {
                                etat = erreur;
                                #ifdef AX12_DEBUG_READ
                                    printf("data[%d]  : %d\r\n", plen, (int)Status[plen]);
                                #endif
                                plen++; 
                                
                            }
                            else 
                            {
                                etat = Header1;
                                plen = 0;
                            }
                        }
                        else timeout++;
                        break;
    
     case erreur:       if (_ax12.readable())       //reception de l'octet correspondant au code d'erreurs eventuels ( 0 = pas d'erreur ) 
                        {
                            Status[plen] = _ax12.getc();
                            timeout = 0; 
                            #ifdef AX12_DEBUG_READ
                                printf("data[%d]  : %d\r\n", plen, (int)Status[plen]);
                            #endif
                            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.readable())  
                            {
                                Status[plen] = _ax12.getc();
                                timeout = 0; 
                                #ifdef AX12_DEBUG_READ
                                    printf("data[%d]  : %d\r\n", plen, (int)Status[plen]);
                                #endif
                                plen++;
                                enable++;
                                
                            }
                            else timeout++;
                        }
                        etat = checksum;
                        break;
                        
     case checksum:     if (_ax12.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.getc();
                                timeout = 0;
                                flag_out = 1;
                                etat = Header1;
                                
                                #ifdef AX12_DEBUG_READ
                                    printf("data[%d]  : %d\r\n\n", plen, (int)Status[plen]);
                                #endif
                            } 
                        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
        {
            #ifdef AX12_DEBUG
            printf ("timeout erreur\n");
            #endif
            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 )
}

void AX12::multiple_goal_and_speed(int number_ax12,char* tab)
{
    char TxBuf[50];
    char sum = 0;      
    int timeout_transmit =0;
    int i=0, k=0, j=0;
    int L=4;                                                                // nombre instructions par paquets
    int bytes= ((L+1)*number_ax12)+4;
    
    typedef enum {Header1, Header2, ident, length, erreur, checksum} type_etat;
    type_etat etat= Header1;
    
    for(j=0; j<50; j++)
    {
      TxBuf[i]=0;  
    }
    
   #ifdef AX12_WRITE_DEBUG
    //printf(" MULTIPLE_GOAL_AND_SPEED \n ");
    #endif  

// Build the TxPacket first in RAM, then we'll send in one go
    #ifdef AX12_WRITE_DEBUG
    //printf("\nInstruction Packet\n  Header :%d, %d\n",TxBuf[0], TxBuf[1]);
    #endif
    
    TxBuf[0]=0xFF;                                                          // bit de start
    TxBuf[1]=0xFF;                                                          // bit de start
    
    TxBuf[2] = 0xFE;                                                        //ID broadcast
    sum += TxBuf[2];
    
    #ifdef AX12_WRITE_DEBUG
    printf("  adresse de difusion : %d\n",TxBuf[2]);
    #endif
    
    TxBuf[3] =bytes;                                                        // longueur
    sum += TxBuf[3];
    
    #ifdef AX12_WRITE_DEBUG
    printf("  Longueur : %d\n",TxBuf[3]);
    #endif
    
    TxBuf[4]=0x83;                                                          //SYNC_WRITE
    sum += TxBuf[4];
    
    #ifdef AX12_WRITE_DEBUG
    printf("  Instruction : 0x%x\n",TxBuf[4]);
    #endif
    
    TxBuf[5] = 0x1E;                                                        // addresse "GOAL_POSITION"
    sum += TxBuf[5];
    
    #ifdef AX12_WRITE_DEBUG
    printf(" Adresse de debut : 0x%x\n",TxBuf[5]);
    #endif
    
    TxBuf[6]=L;                                                             // Nombre instruction par paquets
    sum += TxBuf[6];
    
     #ifdef AX12_WRITE_DEBUG
    printf("  nombre instruction/paquet : 0x%x\n",TxBuf[6]);
    #endif
    
    for(i=0; i<(number_ax12*5); i++)                                            // Copie des data de TAB sur TxBuf
    {         
       
         TxBuf[i+7]=tab[i];
         sum += TxBuf[i+7];            
        
    }
    
    #ifdef AX12_WRITE_DEBUG
    for(i=0; i<(number_ax12*5); i++)
    {
        
        printf("  Data : 0x%x\n",TxBuf[i+7]);
        
    }  
    #endif
    
   TxBuf[(number_ax12*5)+7] = 0xFF - sum ;                                             // CHECKSUM
   
   #ifdef AX12_WRITE_DEBUG
   printf("  Checksum : 0x%x\n",TxBuf[(number_ax12*5)+9]);
   #endif
     
   for(k=0;  k<((number_ax12*5)+8); k++)                                               // TRANSMISSION DE LA TRAME
    {
            _ax12.putc(TxBuf[k]);          
            #ifdef AX12_WRITE_DEBUG
                 printf("  transmission : 0x%x\n",TxBuf[k]);
             #endif         
    }
    

}

float AX12::read_and_test(float angle,char* Tab)
{
    int k=0;
    unsigned short val_angle=0, val_reche=0;
     
     #ifdef AX12_DEBUG
      printf("\nread_and_test");
      #endif
      
    if( _ID==0x12)                                                              
    { k=1;}
    else if( _ID==0x04)                                                      
    { k=6;}
    else if( _ID==0x07)                                                       
    { k=11;}
    else if( _ID==0x0F)                                                     
    { k=16;}
    
    val_angle = (unsigned short) (angle/0.3);
    val_reche = (unsigned short) Tab[k] + ((unsigned short)Tab[k+1]<<8);
     
    if((val_angle < (val_reche+(28))) && (val_angle > (val_reche-(28))))
    {
      #ifdef AX12_DEBUG
      printf("\nreturn1");
      #endif
      return 1;  
    }
    else 
    {
      #ifdef AX12_DEBUG
      printf("\nreturn0");
      #endif
      return 0;
    }
    
}

int AX12::write(int ID, int start, int bytes, char* data, int flag)
{
// 0xff, 0xff, ID, Length, Intruction(write), Address, Param(s), Checksum

    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;

#ifdef AX12_WRITE_DEBUG
    printf("\nwrite(%d,0x%x,%d,data,%d)\n",ID,start,bytes,flag);
#endif

    // Build the TxPacket first in RAM, then we'll send in one go
#ifdef AX12_WRITE_DEBUG
    printf("\nInstruction Packet\n  Header : 0xFF, 0xFF\n");
#endif

    TxBuf[0] = 0xff;
    TxBuf[1] = 0xff;

    // ID
    TxBuf[2] = ID;
    sum += TxBuf[2];

#ifdef AX12_WRITE_DEBUG
    printf("  ID : %d\n",TxBuf[2]);
#endif

    // packet Length
    TxBuf[3] = 3+bytes;
    sum += TxBuf[3];

#ifdef AX12_WRITE_DEBUG
    printf("  Length : %d\n",TxBuf[3]);
#endif

    // Instruction
    if (flag == 1) {
        TxBuf[4]=0x04;
        sum += TxBuf[4];  
    } else {
        TxBuf[4]=0x03;
        sum += TxBuf[4];
    }

#ifdef AX12_WRITE_DEBUG
    printf("  Instruction : 0x%x\n",TxBuf[4]);
#endif

    // Start Address
    TxBuf[5] = start;
    sum += TxBuf[5];

#ifdef AX12_WRITE_DEBUG
    printf("  Start : 0x%x\n",TxBuf[5]);
#endif

    // data
    for (char i=0; i<bytes ; i++) {
        TxBuf[6+i] = data[i];
        sum += TxBuf[6+i];

#ifdef AX12_WRITE_DEBUG
        printf("  Data : 0x%x\n",TxBuf[6+i]);
#endif

    }

    // checksum
    TxBuf[6+bytes] = 0xFF - sum;

#ifdef AX12_WRITE_DEBUG
    printf("  Checksum : 0x%x\n",TxBuf[6+bytes]);
#endif
    
    
    /* Transmission de la trame construite precedemment dans le tableau TxBuf 
    */
    while ((timeout_transmit<100) && (i < (7+bytes)))
    {
        if (_ax12.writeable())  
        {
            _ax12.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 !
        {
            #ifdef AX12_DEBUG
            printf ("TIMEOUT TRANSMIT ERROR\r\n");
            #endif
            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.readable())       // reception du premier Header ( 0xFF )
                        { 
                        Status[plen] = _ax12.getc();
                        timeout = 0;
                            if (Status[plen] == 0xFF )
                            {
                                etat = Header2;
                                #ifdef AX12_DEBUG_WRITE
                                    printf("data[%d]  : %d\r\n", plen, (int)Status[plen]);
                                #endif
                                plen++; 
                                
                            }
                            else etat = Header1;
                        }
                        else timeout++;
                        break;
                    
     
     case Header2:      if (_ax12.readable())        // reception du second Header ( 0xFF )                               
                        { 
                            Status[plen] = _ax12.getc();
                            timeout = 0;
                            if (Status[plen] == 0xFF )
                            {
                                etat = ident;
                                #ifdef AX12_DEBUG_WRITE
                                    printf("data[%d]  : %d\r\n", plen, (int)Status[plen]);
                                #endif
                                plen++;             
                            }   
                            else 
                            {
                                etat = Header1;
                                plen = 0;
                            }
                        }
                        else timeout++;
                        break;
     
     case ident:        if (_ax12.readable())                   // reception de l'octet correspondant à l'ID du servomoteur
                        {
                            Status[plen] = _ax12.getc();
                            timeout = 0;
                            if (Status[plen] == ID )
                            {
                                etat = length;
                                #ifdef AX12_DEBUG_WRITE
                                    printf("data[%d]  : %d\r\n", plen, (int)Status[plen]);
                                #endif
                                plen++; 
                            }
                            else 
                            {
                                etat = Header1;
                                plen = 0;
                            }
                        }
                        else timeout++;
                        break;
     
     case length:       if (_ax12.readable())       // reception de l'octet correspondant à la taille ( taille = 2 + nombre de paramètres )
                        {
                            Status[plen] = _ax12.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;
                                #ifdef AX12_DEBUG_WRITE
                                    printf("data[%d]  : %d\r\n", plen, (int)Status[plen]);
                                #endif
                                plen++; 
                            }
                            else 
                            {
                                etat = Header1;
                                plen = 0;
                            }
                        }
                        else timeout++;
                        break;
    
     case erreur:       if (_ax12.readable())           //reception de l'octet correspondant au code d'erreurs eventuels ( 0 = pas d'erreur ) 
                        {
                            Status[plen] = _ax12.getc();
                            timeout = 0;
                            #ifdef AX12_DEBUG_WRITE
                                    printf("data[%d]  : %d\r\n", plen, (int)Status[plen]);
                            #endif
                            plen++;
                            etat = checksum;
                        } 
                        else timeout++;
                        
     case checksum:     if (_ax12.readable())              // recpetion du dernier octet ( Checksum ) >>> checksum = NOT ( ID + length ) >>>> dans le cas de la reception d'un write 
                        {
                            Status[plen] = _ax12.getc();
                            timeout = 0;
                            flag_out = 1;
                            etat = Header1;
                            #ifdef AX12_DEBUG_WRITE
                                    printf("data[%d]  : %d\r\n\n", plen, (int)Status[plen]);
                            #endif
                        } 
                        else timeout++;
                        break;    
        }
    }
  
    
    if ( Status[4] != 0 )
    {
        #ifdef AX12_DEBUG
        printf ("erreur ! \r\n");
        #endif
        for (int i = 0; i<5; i++)
        {
            #ifdef AX12_DEBUG
            printf("data[%d]  : %d\r\n", plen, (int)Status[plen]);
            #endif
        }   
    }
    
    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
        {
            #ifdef AX12_DEBUG
            printf ("timeout erreur\n\r");
            #endif
            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 ) 
}