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:
- denis2nis
- Date:
- 2021-11-06
- Revision:
- 11:9bc7f5e2ccee
- Parent:
- 10:ca9afe156ee1
- Child:
- 13:ccda9a56fef1
File content as of revision 11:9bc7f5e2ccee:
/** * @file MX12.ccp * @brief this file will contain methods to manage au bus of servomotor * Dynaminel MX12 * */ #include "MX12.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::_ReadCallback), SerialBase::RxIrq); // variable used for message reception _frame_pointer = 0; _current_frame = { .motorId = 0, .length = 0, .data="", .valid=0}; // Internal defaults states _sstate = SerialState::Idle; _pstate = ParsingState::Header; } 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 _sstate = SerialState::Writing; rw(mot_id, CONTROL_TABLE_MOVING_SPEED, 2, data); } char MX12::IsAvailable(void) { return (_sstate == SerialState::Idle); } void MX12::rw(unsigned char mot_id, char address, char len, char *data) { /* Set variables for reception from servovotor */ _answer = 0; //memset(_current_frame.data, 0, MX12_DATA_MAX_SIZE); _scontext.checksum = 0; _pstate = Header; _scontext = {.headingCount = 0, .dataCount = 0, .checksum = 0}; _current_frame = { .motorId = 0, .length = 0, .data="", .valid=0}; _frame_pointer = 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 < _frame_pointer; i++) { printf("%x.", _stored_frame[i]); } printf("\n"); } MX12::Status MX12::GetStatus() { // Return the corresponding status code switch(_current_frame.data[0]) { 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::_ReadCallback() { char c; // Try to read serial if(_mx12.read(&c, 1)) { _stored_frame[_frame_pointer++] = c; /* Include all characters in the checksum calculation, * even those that shouldn't, such as header characters. * They will be subtracted later (B. Denis remark) */ _scontext.checksum += c; // State-machine parsing switch(_pstate) { case Header: if(++(_scontext.headingCount) >= 2) { //_scontext.headingCount = 0; _pstate = Id; } _scontext.checksum -= c; break; case Id: _current_frame.motorId = c; _pstate = Length; break; case Length: _current_frame.length = c - 1; _pstate = Data; break; case Data: _current_frame.data[_scontext.dataCount] = c; if(++(_scontext.dataCount) >= _current_frame.length) { _scontext.dataCount = 0; _pstate = Checksum; } break; case Checksum: _current_frame.valid = (_scontext.checksum == 0xFF); _scontext.checksum = 0; _pstate = Header; if(_answer) { _sstate = SerialState::Idle; } _answer = 1; 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]; } */