|
|
@ -3,7 +3,7 @@ using namespace iflytop; |
|
|
|
using namespace std; |
|
|
|
using namespace feite; |
|
|
|
#define TAG "FeiTeServoMotor"
|
|
|
|
#define OVERTIME 5
|
|
|
|
#define OVERTIME 30
|
|
|
|
#define DO(func) \
|
|
|
|
if (!(func)) { \ |
|
|
|
ZLOGE(TAG, "motor[%d] do %s fail", id, #func); \ |
|
|
@ -67,13 +67,12 @@ bool FeiTeServoMotor::write16(uint8_t id, feite::reg_add_e add, uint16_t regval) |
|
|
|
return tx_and_rx((uint8_t*)&write16_cmd, sizeof(write16_cmd_t), (uint8_t*)&write16_resp, sizeof(write16_resp_t), OVERTIME); |
|
|
|
} |
|
|
|
|
|
|
|
bool FeiTeServoMotor::read_s16(uint8_t id, feite::reg_add_e add, int16_t& regval) { |
|
|
|
bool FeiTeServoMotor::read_s16(uint8_t id, feite::reg_add_e add, uint8_t signbitoff, int16_t& regval) { |
|
|
|
uint16_t val = 0; |
|
|
|
bool ret = read16(id, add, val); |
|
|
|
if (!ret) return false; |
|
|
|
|
|
|
|
uint8_t sign = val >> 15; |
|
|
|
uint16_t realval = val & 0x7fff; |
|
|
|
uint8_t sign = (val >> signbitoff) & 0x01; |
|
|
|
uint16_t realval = val & (~(1 << signbitoff)); |
|
|
|
if (sign == 0) { |
|
|
|
regval = realval; |
|
|
|
} else { |
|
|
@ -82,13 +81,13 @@ bool FeiTeServoMotor::read_s16(uint8_t id, feite::reg_add_e add, int16_t& regval |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
bool FeiTeServoMotor::write_s16(uint8_t id, feite::reg_add_e add, int16_t regval) { |
|
|
|
bool FeiTeServoMotor::write_s16(uint8_t id, feite::reg_add_e add, uint8_t signbitoff, int16_t regval) { |
|
|
|
uint16_t val = 0; |
|
|
|
if (regval >= 0) { |
|
|
|
val = regval; |
|
|
|
} else { |
|
|
|
val = -regval; |
|
|
|
val |= 0x8000; |
|
|
|
val |= (1 << signbitoff); |
|
|
|
} |
|
|
|
return write16(id, add, val); |
|
|
|
} |
|
|
@ -136,7 +135,7 @@ bool FeiTeServoMotor::async_write16(uint8_t id, feite::reg_add_e add, uint16_t r |
|
|
|
} |
|
|
|
|
|
|
|
static int16_t getcalibrate(int16_t nowpos, int16_t aftercalibratepos) { |
|
|
|
int16_t calibrate = aftercalibratepos - nowpos; |
|
|
|
int16_t calibrate = nowpos - aftercalibratepos; |
|
|
|
while (true) { |
|
|
|
if (calibrate > 2047) { |
|
|
|
calibrate -= 4094; |
|
|
@ -149,41 +148,78 @@ static int16_t getcalibrate(int16_t nowpos, int16_t aftercalibratepos) { |
|
|
|
return calibrate; |
|
|
|
} |
|
|
|
|
|
|
|
bool FeiTeServoMotor::setcurpos(int id, int16_t pos) { |
|
|
|
/**
|
|
|
|
* @brief |
|
|
|
* 1. 记录当前模式 |
|
|
|
* 2. 切换到位置模式 |
|
|
|
* 3. 读取当前位置 |
|
|
|
* 4. 读取当前位置校准数值 |
|
|
|
* 5. 计算新的校准值 |
|
|
|
* 6. 切换到速度模式(速度模式下不会因为位置的变化而导致舵机运动) |
|
|
|
* 解锁写入 |
|
|
|
* 6. 写入新的校准值 |
|
|
|
* 锁定写入 |
|
|
|
* 7. 切换回原来的模式 |
|
|
|
*/ |
|
|
|
bool FeiTeServoMotor::write_reg(uint8_t id, uint8_t add, uint8_t* data, uint8_t len) { //
|
|
|
|
|
|
|
|
return false; |
|
|
|
} |
|
|
|
bool FeiTeServoMotor::read_reg(uint8_t id, uint8_t add, uint8_t* data, uint8_t len) { return false; } |
|
|
|
bool FeiTeServoMotor::setmode(uint8_t id, run_mode_e runmode) { return write8(id, kRegServoRunMode, (uint8_t)runmode); } |
|
|
|
|
|
|
|
bool FeiTeServoMotor::getServoCalibration(uint8_t id, int16_t& poscalibration) { return read_s16(id, kRegServoCalibration, 11, poscalibration); } |
|
|
|
|
|
|
|
run_mode_e FeiTeServoMotor::getmode(uint8_t id) { |
|
|
|
uint8_t data = 0; |
|
|
|
bool suc = read8(id, kRegServoRunMode, data); |
|
|
|
if (suc) { |
|
|
|
return (run_mode_e)data; |
|
|
|
} else { |
|
|
|
return kMotorMode; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
bool FeiTeServoMotor::getmode(uint8_t id, run_mode_e& runmode) { |
|
|
|
uint8_t data = 0; |
|
|
|
bool suc = read8(id, kRegServoRunMode, data); |
|
|
|
runmode = (run_mode_e)data; |
|
|
|
return suc; |
|
|
|
} |
|
|
|
|
|
|
|
bool FeiTeServoMotor::setTorqueSwitch(uint8_t id, bool on) { return write8(id, kRegServoTorqueSwitch, on ? 1 : 0); } |
|
|
|
bool FeiTeServoMotor::getTorqueSwitch(uint8_t id, bool& on) { |
|
|
|
uint8_t data = 0; |
|
|
|
bool suc = read8(id, kRegServoTorqueSwitch, data); |
|
|
|
on = data; |
|
|
|
return suc; |
|
|
|
} |
|
|
|
|
|
|
|
bool FeiTeServoMotor::getNowPos(uint8_t id, int16_t& pos) { return read_s16(id, kRegServoCurrentPos, 15, pos); } |
|
|
|
bool FeiTeServoMotor::setTargetPos(uint8_t id, int16_t pos) { return write_s16(id, kRegServoTargetPos, 15, pos); } |
|
|
|
|
|
|
|
bool FeiTeServoMotor::reCalibration(int id, int16_t pos) { |
|
|
|
if (pos < 0 || pos > 4095) { |
|
|
|
ZLOGE(TAG, "setcurpos pos:%d out of range", pos); |
|
|
|
ZLOGE(TAG, "reCalibration pos:%d out of range", pos); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
run_mode_e nowmode = getmode(id); |
|
|
|
/**
|
|
|
|
* @brief 关闭扭矩快关,防止舵机运动 |
|
|
|
*/ |
|
|
|
setTorqueSwitch(id, false); |
|
|
|
/**
|
|
|
|
* @brief 设置当前模式为位置模式 |
|
|
|
*/ |
|
|
|
DO(setmode(id, kServoMode)); |
|
|
|
uint16_t curpos; |
|
|
|
DO(read16(id, kRegServoCurrentPos, curpos)); |
|
|
|
int16_t curcalibrate; |
|
|
|
DO(read_s16(id, kRegServoCalibration, curcalibrate)); |
|
|
|
|
|
|
|
int16_t realpos = curpos - curcalibrate; |
|
|
|
int16_t curpos; |
|
|
|
DO(getNowPos(id, curpos)); |
|
|
|
int16_t curcalibrate; |
|
|
|
DO(getServoCalibration(id, curcalibrate)); |
|
|
|
int16_t realpos = curpos + curcalibrate; |
|
|
|
int16_t newcalibrate = getcalibrate(realpos, pos); |
|
|
|
|
|
|
|
DO(setmode(id, kMotorMode)); |
|
|
|
ZLOGI(TAG, "reCalibration id:%d curpos:%d curcalibrate:%d realpos:%d newcalibrate:%d", id, curpos, curcalibrate, realpos, newcalibrate); |
|
|
|
/**
|
|
|
|
* @brief 写入新的校准值 |
|
|
|
*/ |
|
|
|
DO(write8(id, kRegServoLockFlag, 0)); |
|
|
|
DO(write_s16(id, kRegServoCalibration, newcalibrate)); |
|
|
|
DO(write_s16(id, kRegServoCalibration, 11, newcalibrate)); |
|
|
|
DO(write8(id, kRegServoLockFlag, 1)); |
|
|
|
|
|
|
|
DO(setmode(id, nowmode)); |
|
|
|
/**
|
|
|
|
* @brief 重新设置目标位置为当前这个位置 |
|
|
|
*/ |
|
|
|
int16_t nowpos; |
|
|
|
DO(getNowPos(id, nowpos)); |
|
|
|
ZLOGI(TAG, "reCalibration id:%d nowpos:%d:%d", id, nowpos, pos); |
|
|
|
DO(setTargetPos(id, pos)); |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
@ -193,21 +229,28 @@ bool FeiTeServoMotor::setcurpos(int id, int16_t pos) { |
|
|
|
return false; \ |
|
|
|
} |
|
|
|
|
|
|
|
static void dumphex(char* tag, uint8_t* data, uint8_t len) { |
|
|
|
printf("%s:", tag); |
|
|
|
for (int i = 0; i < len; i++) { |
|
|
|
printf("%02x ", data[i]); |
|
|
|
} |
|
|
|
printf("\n"); |
|
|
|
} |
|
|
|
|
|
|
|
bool FeiTeServoMotor::tx_and_rx(uint8_t* tx, uint8_t txdatalen, uint8_t* rx, uint8_t expectrxsize, uint16_t overtimems) { |
|
|
|
uint32_t enter_ticket = HAL_GetTick(); |
|
|
|
dumphex("tx:", tx, txdatalen); |
|
|
|
|
|
|
|
HAL_UART_Transmit_DMA(m_uart, tx, txdatalen); |
|
|
|
while (HAL_UART_GetState(m_uart) == HAL_UART_STATE_BUSY_TX) { |
|
|
|
; |
|
|
|
} |
|
|
|
HAL_UART_Receive_DMA(m_uart, (uint8_t*)rx, expectrxsize); |
|
|
|
HAL_UART_Transmit(m_uart, tx, txdatalen, 1000); |
|
|
|
|
|
|
|
bool overtime_flag = false; |
|
|
|
while (HAL_UART_GetState(m_uart) == HAL_UART_STATE_BUSY_RX || //
|
|
|
|
HAL_UART_GetState(m_uart) == HAL_UART_STATE_BUSY_TX_RX) { |
|
|
|
osDelay(5); |
|
|
|
osDelay(1); |
|
|
|
int rxsize = expectrxsize - __HAL_DMA_GET_COUNTER(m_hdma_rx); |
|
|
|
if (rxsize == expectrxsize) { |
|
|
|
dumphex("rx:", rx, expectrxsize); |
|
|
|
break; |
|
|
|
} |
|
|
|
if (zos_haspassedms(enter_ticket) > overtimems) { |
|
|
@ -237,9 +280,6 @@ bool FeiTeServoMotor::readversion(uint8_t id, uint8_t& mainversion, uint8_t& sub |
|
|
|
miniserv_subversion = data; |
|
|
|
return true; |
|
|
|
} |
|
|
|
bool FeiTeServoMotor::readposcalibration(uint8_t id, int16_t& poscalibration) { |
|
|
|
return read_s16(id, kRegServoCalibration, poscalibration); |
|
|
|
} |
|
|
|
|
|
|
|
uint8_t FeiTeServoMotor::checksum_packet(uint8_t* data, uint8_t len) { return checksum(&data[2], len - 3); } |
|
|
|
uint8_t FeiTeServoMotor::checksum(uint8_t* data, uint8_t len) { |
|
|
|