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-04
- Revision:
- 3:add8b050eb86
- Parent:
- 2:02f3323a107d
- Child:
- 5:0cf54586a4be
File content as of revision 3:add8b050eb86:
#include "MX12.h" MX12::MX12(PinName tx, PinName rx, int baud) : _mx12(tx, rx) { _baud = baud; _mx12.baud(_baud); _mx12.format(8, SerialBase::None, 1); _mx12.attach(callback(this, &MX12::_ReadCallback), SerialBase::RxIrq); _state = State::Available; } 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; // Enter writing state _state = State::Writing; // Send instruction rw(mot_id, 0x20, 2, data); } char MX12::IsAvailable(void) { return _state == State::Available; } 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]; } 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; } } } }