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.
MX12.cpp
- Committer:
- denis2nis
- Date:
- 2021-11-06
- Revision:
- 9:b4a5187fdec6
- Parent:
- 8:e74ef93ae660
- Child:
- 10:ca9afe156ee1
File content as of revision 9:b4a5187fdec6:
/**
* @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 = Idle;
_answer = 1;
break;
}
}
}
/*
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];
}
*/