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.
Dependents: PSL_ROBOT_lorenzo robot_lorenzo recepteur_mbed_os_6
MX12.cpp
- Committer:
- martinr
- Date:
- 2022-06-15
- Revision:
- 33:67e5482f83dd
- Parent:
- 31:e48d21e28023
File content as of revision 33:67e5482f83dd:
/** * @file MX12.ccp * @brief This file contains all the methods of the MX12 class * whose prototypes are in the MX12.h header file */ #include "MX12.h" #include "math.h" MX12::MX12(PinName tx, PinName rx, int baud) : _mx12(tx, rx) // initializes UnbufferedSerial object { /* Serial bus setup */ // // Set desired properties (baud-8-N-1) _mx12.baud(baud); /* modulation speed */ _mx12.format( 8, /* bits */ SerialBase::None, /* parity */ 1 /* stop bit */ ); // Register a callback to process a Rx (receive) interrupt. _mx12.attach(callback(this, &MX12::_Rx_interrupt), SerialBase::RxIrq); // variable used for message reception _status_pck = {.raw = "", .n_byte = 0, .servo_id = 0, .length = 0, .error = 0, .n_param = 0, .param = "", .received_checksum = 0, .calculated_checksum = 0, .parsed = false, .valid = false }; _parser_state = {.expected_field = PacketField::Header1, .byte_index = 0, .param_index = 0 }; // Internal defaults states _bus_state = SerialState::Idle; } void MX12::SetSpeed(unsigned char mot_id, float speed) { char data[2]; // Speed absolute value int goal = (0x3ff * abs(speed)); // Spin direction (CW is negative) if (speed < 0) { goal |= (0x1 << 10); } data[0] = goal & 0xff; data[1] = goal >> 8; // Send instruction _bus_state = SerialState::Writing; rw(mot_id, CONTROL_TABLE_MOVING_SPEED, 2, data); } void MX12::SetSpeed_rad_s(unsigned char mot_id, float speed) { if (speed > MX12_ABSOLUTE_MAX_SPEED_RAD_S) { SetSpeed(mot_id, 1); } else if (speed < -MX12_ABSOLUTE_MAX_SPEED_RAD_S) { SetSpeed(mot_id, -1); } else { SetSpeed(mot_id, speed / MX12_ABSOLUTE_MAX_SPEED_RAD_S); } } char MX12::IsAvailable(void) { return (_bus_state == SerialState::Idle); } void MX12::rw(unsigned char mot_id, char address, char len, char *data) { /* Set variables for reception from servovotor */ _answer = 0; _status_pck = {.raw = "", .n_byte = 0, .servo_id = 0, .length = 0, .error = 0, .n_param = 0, .param = "", .received_checksum = 0, .calculated_checksum = 0, .parsed = false, .valid = false }; _parser_state = {.expected_field = PacketField::Header1, .byte_index = 0, .param_index = 0 }; /* Initialise instruction packet to forge. * Instruction Packet is the command data sent to the servomotor. * * |Header1|Header2|Packet ID|Length|Instruction|Param1...ParamN|Checksum| * |-------|-------|---------|------|-----------|---------------|--------| * | 0xFF | 0xFF |Packet ID|Length|Instruction|Param1...ParamN| CHKSUM | * | cmd[0]| cmd[1]| cmd[2] |cmd[3]| cmd[4] |cmd[5]... | | * \__ ___/ \_ _/ \__ __/ * \/ | \/ \/ | * mot_id | address data | * | (len = N-1) | * \__________________ ________________/ * \/ * Length ( cmd[3] ) */ char packet[16]; unsigned char packet_length; /* Initialise checksum to calculate * It is used to check if packet is damaged during communication. * Status Checksum is calculated according to the following formula: * * Status Checksum = ~( ID + Length + Error + Parameter1 + … Parameter N ) */ char checksum = 0x00; /* header 1 = 0xFF (dynamixel protocol 1.0) */ packet[0] = 0xff; /* header 2 = 0xFF (dynamixel protocol 1.0) */ packet[1] = 0xff; /* packet ID i.e. servomotor id (dynamixel protocol 1.0) */ packet[2] = mot_id; checksum += packet[2]; /* Guess instruction type. NULL for read, not NULL for write */ if(data == NULL) { // read instruction /* byte length of the instruction: parameter and checksum field. */ /* for read instruction: 1 INSTR + */ /* 2 PARAM (starting address, length of data) + 1 CHKSUM */ packet[3] = 4; checksum += packet[3]; /* set write instruction */ packet[4] = PROTOCOL_INSTRUCTION_READ; checksum += packet[4]; /* Param 1: address to read in the Control Table of RAM Area */ packet[5] = address; checksum += packet[5]; /* Param 2: number of bytes to read in the Control Table of RAM Area */ packet[6] = len; checksum += packet[6]; /* Checksum = ~( ID + Length + Instruction + Param1 + … Param N ) */ packet[7] = ~checksum; packet_length = 8; } else { // write instruction /* byte length of the instruction: parameter and checksum field */ /* For write instruction: 1 INSTR + */ /* (1+len)PARAM (starting Address, bytes to write) + 1 CHKSUM */ packet[3] = 3 + len; checksum += packet[3]; /* set read instruction */ packet[4] = PROTOCOL_INSTRUCTION_WRITE; checksum += packet[4]; /* Param 1: address to write in the "Control Table of RAM Area" */ packet[5] = address; checksum += packet[5]; /* Param 2 to N: data to write in the Control Table of RAM Area */ for(char i = 0; i < len; i++) { packet[6 + i] = data[i]; checksum += data[i]; } /* Checksum = ~( ID + Length + Instruction + Param1 + … Param N ) */ packet[6 + len] = ~checksum; packet_length = 7 + len; } // Send packet if(mot_id != 0xFE) { for(char i = 0; i < packet_length; i++) { _mx12.write(&packet[i], 1); } } } // Debug function to print Serial read void MX12::PrintSerial() { for(int i = 0; i < _status_pck.n_byte; i++) { printf("%x ", _status_pck.raw[i]); } printf("\n"); } char MX12::ReadSerial() { char data; for(int i = 0; i < _status_pck.n_byte; i++) { } return data; } MX12::Status MX12::GetStatus() { // Return the corresponding status code switch(_status_pck.error) { case 0: return Ok; break; case 1 << 0: return InputVoltageError; break; case 1 << 1: return AngleLimitError; break; case 1 << 2: return OverheatingError; break; case 1 << 3: return RangeError; break; case 1 << 4: return ChecksumError; break; case 1 << 5: return OverloadError; break; case 1 << 6: return InstructionError; break; default: return Unknown; } } void MX12::_Rx_interrupt() { char c; // Try to read serial if(_mx12.read(&c, 1)) { _status_pck.raw[(_parser_state.byte_index)++] = c; // State-machine parsing switch(_parser_state.expected_field) { /* c char is interpreted as a Header1 field */ case PacketField::Header1: /* do nothing and set next state to Header2 */ _parser_state.expected_field = PacketField::Header2; break; /* c char is interpreted as a Header2 field */ case PacketField::Header2: /* do nothing and set next state to Id */ _parser_state.expected_field = PacketField::Id; break; /* c char is interpreted as ID field */ case PacketField::Id: /* store ID, update checksum and set next state to Length */ _status_pck.servo_id = c; _status_pck.calculated_checksum += c; _parser_state.expected_field = PacketField::Length; break; /* c char is interpreted as length of message data field * Length = number of Parameters + 2 * where 2 stands for Length field (1 byte) + Error filed (1 byte) */ case PacketField::Length: /* store number of param into _status_pck.n_param, * update calculated_checksum and set next state to Error */ _status_pck.n_param = c - 2; _status_pck.calculated_checksum += c; _parser_state.expected_field = PacketField::Error; break; /* c char is interpreted as error status field */ case PacketField::Error: /* store error status, update checksum * and set next state to Data */ _status_pck.error = c; _status_pck.calculated_checksum += c; _parser_state.expected_field = PacketField::Data; break; /* c char is interpreted as a param field */ case PacketField::Data: /* store current param, increase param_index * and update checksum */ _status_pck.param[(_parser_state.param_index)++] = c; _status_pck.received_checksum += c; /* increase param index (_parser_state.dataCount) * and test if it is the last param to read */ if(_parser_state.param_index > _status_pck.n_param) { /* reset param index and set next state to Checksum */ _parser_state.param_index = 0; _parser_state.expected_field = PacketField::Checksum; } break; /* c char is interpreted as Checksum field */ case PacketField::Checksum: /* store received_checksum, set parsed, store n_byte, * evalutate valid and set next state to Header1 */ _status_pck.received_checksum = c; _status_pck.parsed = true; _status_pck.n_byte = _parser_state.byte_index; _status_pck.valid = (_status_pck.received_checksum == c); _parser_state.expected_field = PacketField::Header1; /* set seriel state to Idle */ _bus_state = SerialState::Idle; break; default: /* unexpected case. If it occurs it would be due to a * code error of this class */ break; } } } /* Code from previous version of the class */ /* void MX12::ReadPosition(unsigned char mot_id) { // Make a request, interrupt takes care of everything else _state = State::ReadingPosition; rw(mot_id, 0x24, 2, NULL); } float MX12::GetPosition(unsigned char mot_id) { return _angle[mot_id]; } */ void MX12::cmd_moteur(float Vavance, float Vlat, float Wz) { // mettre en mode wh char data[2]; data[1] = 0; data[0] = 0; float W1; float W2; float W3; float Rc; float R; float x1; float x2; float x3; float y1; float y2; float y3; float a1; float a2; float a3; Rc=0.08; // rayon du chassis*10 R=0.019; // rayon de la roue*10 W1=0; W2=0; W3=0; a1 = 3.74 ; a2 = 1.57; a3 = 5.86; x1 = -6.87; x2 = -0.58; x3 = 7.78; y1 = -5.09; y2 = 8.22; y3 = -4.2; //Vtm_smax=0.8; //sert pour calculer valeurs -999->999 //Vnm_smax=0.9; //Wcrd_smax=2.9; //if (Vtm_s>Vtm_smax) // {Vtm_s=Vtm_smax;} //if (Vnm_s>Vnm_smax) // {Vnm_s=Vnm_smax;} //if (Wcrd_s>Wcrd_smax) // {Wcrd_s=Wcrd_smax;} //if (Wcrd_s<-Wcrd_smax) // {Wcrd_s=-Wcrd_smax;} W1=1/R*(-cosf(a1)*Vavance + sinf(a1)*y1*Wz - sinf(a1)*Vlat + cosf(a1)*x1*Wz); //loi de commande moteur 1 W2=1/R*(-cosf(a2)*Vavance + sinf(a2)*y2*Wz - sinf(a2)*Vlat + cosf(a2)*x2*Wz); W3=1/R*(-cosf(a3)*Vavance + sinf(a3)*y3*Wz - sinf(a3)*Vlat + cosf(a3)*x3*Wz); printf("%d %d %dn\r",(int)(1000*W1),(int)(1000*W2),(int)(1000*W3)); SetSpeed_rad_s(1,W1); // impose la vitesse au moteur 1 SetSpeed_rad_s(2,W2); SetSpeed_rad_s(3,W3); } void MX12::cmd_moteur_rampe_unitaire(int id_moteur, float w_moteur, int step, float time) { } void MX12::eteindre_moteurs() { char data[1]; data[0] = 0; // Send instruction _bus_state = SerialState::Writing; rw(1, CONTROL_TABLE_TORQUE_ENABLE, 1, data); _bus_state = SerialState::Writing; rw(2, CONTROL_TABLE_TORQUE_ENABLE, 1, data); _bus_state = SerialState::Writing; rw(3, CONTROL_TABLE_TORQUE_ENABLE, 1, data); } void MX12::cmd_moteur_multiturn(float pos1, float pos2, float pos3) { // eteindre les moteurs eteindre_moteurs(); // mettre en mode multiturn char data[2]; data[1] = 255; data[0] = 15; _bus_state = SerialState::Writing; rw(1, CONTROL_TABLE_CW_ANGLE_LIMIT, 2, data); rw(2, CONTROL_TABLE_CW_ANGLE_LIMIT, 2, data); rw(3, CONTROL_TABLE_CW_ANGLE_LIMIT, 2, data); _bus_state = SerialState::Writing; rw(1, CONTROL_TABLE_CCW_ANGLE_LIMIT, 2, data); rw(2, CONTROL_TABLE_CCW_ANGLE_LIMIT, 2, data); rw(3, CONTROL_TABLE_CCW_ANGLE_LIMIT, 2, data); //relever la position int pas1 = pos1-28672/60; int pas2 = pos2-28672/60; int pas3 = pos3-28672/60; for (int i = 0; i < 61; i++) { int goal_position1 = i * pas1 - 28672; if (goal_position1 < 0) { goal_position1 = goal_position1 + 28627 + 36864; } char data1[2]; data1[1] = goal_position1%256; data1[0] = goal_position1/256; int goal_position2 = i * pas2 - 28672; if (goal_position2 < 0) { goal_position2 = goal_position2 + 28627 + 36864; } char data2[2]; data2[1] = goal_position2%256; data2[0] = goal_position2/256; int goal_position3 = i * pas3 - 28672; if (goal_position3 < 0) { goal_position3 = goal_position3 + 28627 + 36864; } char data3[2]; data3[1] = goal_position3%256; data3[0] = goal_position3/256; rw(1, CONTROL_TABLE_GOAL_POSITION, 2, data1); thread_sleep_for(60); rw(2, CONTROL_TABLE_GOAL_POSITION, 2, data2); thread_sleep_for(60); rw(3, CONTROL_TABLE_GOAL_POSITION, 2, data3); thread_sleep_for(60); thread_sleep_for(1000); } }