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
Diff: MX12.cpp
- Revision:
- 5:0cf54586a4be
- Parent:
- 3:add8b050eb86
- Child:
- 8:e74ef93ae660
--- a/MX12.cpp Thu Nov 04 07:32:20 2021 +0000 +++ b/MX12.cpp Thu Nov 04 11:48:53 2021 +0000 @@ -1,11 +1,14 @@ #include "MX12.h" MX12::MX12(PinName tx, PinName rx, int baud) : _mx12(tx, rx) { - _baud = baud; - _mx12.baud(_baud); + // Serial configuration + _mx12.baud(baud); _mx12.format(8, SerialBase::None, 1); _mx12.attach(callback(this, &MX12::_ReadCallback), SerialBase::RxIrq); - _state = State::Available; + + // Internal defaults + _sstate = SerialState::Idle; + _pstate = ParsingState::Header; } void MX12::SetSpeed(unsigned char mot_id, float speed) { @@ -22,17 +25,215 @@ data[0] = goal & 0xff; data[1] = goal >> 8; - // Enter writing state - _state = State::Writing; - // Send instruction - rw(mot_id, 0x20, 2, data); + _sstate = SerialState::Writing; + rw(mot_id, CONTROL_TABLE_MOVING_SPEED, 2, data); } char MX12::IsAvailable(void) { - return _state == State::Available; + 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); + + /* 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; + //_res[_res_count] = c; + //_res_count++; + _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 = Idle; + _answer = 1; + break; + } + } +} + +/* + void MX12::ReadPosition(unsigned char mot_id) { // Make a request, interrupt takes care of everything else _state = State::ReadingPosition; @@ -43,192 +244,4 @@ return _angle[mot_id]; } -MX12::Status MX12::GetStatus(void) { - return _status; -} - -// Debug function to print Serial read -void MX12::PrintAnswer() { - for(char i = 0; i < MX12_ANSWER_MAX_SIZE; i++) { - printf("%x ", _res[i]); - } - - printf("\r\n"); -} - -void MX12::rw(unsigned char mot_id, char address, char len, char *data) { - _res_count = 0; - memset(_res, 0, MX12_ANSWER_MAX_SIZE); - - /* Forge instruction packet */ - char cmd[16]; - char checksum = 0x00; - - /* Instruction Packet is the command data sent to the Device. - * - * |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]... |(2 bytes)| - * \_ _/ \__ __/ - * | \/ \/ | - * | address data | - * | (len = N-1) | - * \__________________ _________________/ - * \/ - * Length ( cmd[3] ) - */ - - /* header 1 = 0xFF (dynamixel protocol 1.0) */ - cmd[0] = 0xff; - - /* header 2 = 0xFF (dynamixel protocol 1.0) */ - cmd[1] = 0xff; - - /* packet ID i.e. servomotor id (dynamixel protocol 1.0) */ - cmd[2] = mot_id; - checksum += cmd[2]; - - /* Length indicates the byte size of the instruction, - parameter and Checksum field */ - - - /* 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 */ - cmd[3] = 4; - checksum += cmd[3]; - - /* set write instruction */ - cmd[4] = PROTOCOL_INSTRUCTION_READ; - checksum += cmd[4]; - - /* Param 1: address to read in the Control Table of RAM Area */ - cmd[5] = address; - checksum += cmd[5]; - - /* Param 2: number of bytes to read in the Control Table of RAM Area */ - cmd[6] = len; - checksum += cmd[6]; - - /* Checksum */ - /* Checksum = ~( ID + Length + Instruction + Param1 + … Param N ) */ - cmd[7] = ~checksum; - cmd[7] = 0xFF - (mot_id + 4 + 2 + address + len); - - } - 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 */ - cmd[3] = 3 + len; - checksum += cmd[3]; - - /* set read instruction */ - cmd[4] = PROTOCOL_INSTRUCTION_WRITE; - checksum += cmd[4]; - - /* Param 1: address to write in the "Control Table of RAM Area" */ - cmd[5] = address; - checksum += cmd[5]; - } - - //cmd[4] = 0x02 + (data != NULL); // original code from Titouan - - - // Compute checksum - if(data == NULL) { - cmd[6] = len; - cmd[7] = 0xFF - (mot_id + 4 + 2 + address + len); - - // [XXX] Force length to one to force send - len = 1; - } else { - char cs = mot_id + len + address + 6; - - for(char i = 0; i < len; i++) { - cmd[6 + i] = data[i]; - cs += data[i]; - } - - cmd[6 + len] = 0xFF - cs; - } - - // Send packet - if(mot_id != 0xFE) { - for(char i = 0; i < (7 + len); i++) { - _mx12.write(&cmd[i], 1); - } - } -} - -void MX12::_ReadCallback() { - char c; - - // Loop on reading serial - if(_mx12.read(&c, 1)) { - _res[_res_count] = c; - _res_count++; - if(_res_count >= MX12_ANSWER_MAX_SIZE) _res_count = 0; - - // Find answer in buffer - char ans_i = 2; - for(; (_res[ans_i] != 0xFF) && (ans_i <= MX12_ANSWER_MAX_SIZE - 1); ans_i++); - if(ans_i >= MX12_ANSWER_MAX_SIZE) return; - - ans_i += 2; - char mot_id = _res[ans_i++]; - char len = _res[ans_i++]; - _chksm = _res[ans_i + len - 1]; - - // [TODO] Verify checksum - if(len != 0 && _chksm != 0) { - // Interpret answer depending on state - switch(_state) { - case State::ReadingPosition: - _angle[mot_id] = (((uint16_t) _res[ans_i + 1] << 8) | (uint16_t) _res[ans_i]) * 0.088; - _state = State::Available; - break; - case State::Writing: - // Return the corresponding status code - switch(_res[ans_i]) { - case 0: - _status = Status::Ok; - break; - case 1 << 0: - _status = Status::InputVoltageError; - break; - case 1 << 1: - _status = Status::AngleLimitError; - break; - case 1 << 2: - _status = Status::OverheatingError; - break; - case 1 << 3: - _status = Status::RangeError; - break; - case 1 << 4: - _status = Status::ChecksumError; - break; - case 1 << 5: - _status = Status::OverloadError; - break; - case 1 << 6: - _status = Status::InstructionError; - break; - default: - _status = Status::Unknown; - } - - _state = State::Available; - break; - default: - _status = Status::Unknown; - } - } - } -} \ No newline at end of file +*/