正点原子开发板 alientek_develop_board cancmder
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

370 lines
13 KiB

2 years ago
  1. #include "feite_servo_motor.hpp"
  2. #include <stdint.h>
  3. #include <string.h>
  4. // #include "board.h"
  5. // #include "port.h"
  6. using namespace iflytop;
  7. using namespace std;
  8. using namespace feite;
  9. #define TAG "FeiTeServoMotor"
  10. #define OVERTIME 30
  11. #define DO(func) \
  12. if (!(func)) { \
  13. ZLOGE(TAG, "motor[%d] do %s fail", id, #func); \
  14. return false; \
  15. }
  16. static void dumphex(const char* tag, uint8_t* data, uint8_t len) {
  17. printf("%s:", tag);
  18. for (int i = 0; i < len; i++) {
  19. printf("%02x ", data[i]);
  20. }
  21. printf("\n");
  22. }
  23. void FeiTeServoMotor::initialize(UART_HandleTypeDef* uart, DMA_HandleTypeDef* hdma_rx, DMA_HandleTypeDef* hdma_tx) {
  24. m_uart = uart;
  25. m_hdma_rx = hdma_rx;
  26. m_hdma_tx = hdma_tx;
  27. }
  28. bool FeiTeServoMotor::ping(uint8_t id) {
  29. ping_cmd_t ping_cmd;
  30. ping_resp_t ping_resp;
  31. ping_cmd.header = 0xffff;
  32. ping_cmd.id = id;
  33. ping_cmd.len = 2;
  34. ping_cmd.cmd = kping;
  35. ping_cmd.checksum = checksum_packet((uint8_t*)&ping_cmd, sizeof(ping_cmd_t));
  36. return tx_and_rx((uint8_t*)&ping_cmd, sizeof(ping_cmd_t), (uint8_t*)&ping_resp, sizeof(ping_resp_t), OVERTIME);
  37. }
  38. static int16_t getcalibrate(int16_t nowpos, int16_t aftercalibratepos) {
  39. int16_t calibrate = nowpos - aftercalibratepos;
  40. while (true) {
  41. if (calibrate > 2047) {
  42. calibrate -= 4094;
  43. } else if (calibrate < -2047) {
  44. calibrate += 4094;
  45. } else {
  46. break;
  47. }
  48. }
  49. return calibrate;
  50. }
  51. bool FeiTeServoMotor::setmode(uint8_t id, run_mode_e runmode) { return write_u8(id, kRegServoRunMode, (uint8_t)runmode); }
  52. bool FeiTeServoMotor::getServoCalibration(uint8_t id, int16_t& poscalibration) { return read_s16(id, kRegServoCalibration, 11, poscalibration); }
  53. run_mode_e FeiTeServoMotor::getmode(uint8_t id) {
  54. uint8_t data = 0;
  55. bool suc = read_u8(id, kRegServoRunMode, data);
  56. if (suc) {
  57. return (run_mode_e)data;
  58. } else {
  59. return kMotorMode;
  60. }
  61. }
  62. bool FeiTeServoMotor::getmode(uint8_t id, run_mode_e& runmode) {
  63. uint8_t data = 0;
  64. bool suc = read_u8(id, kRegServoRunMode, data);
  65. runmode = (run_mode_e)data;
  66. return suc;
  67. }
  68. bool FeiTeServoMotor::setTorqueSwitch(uint8_t id, bool on) { return write_u8(id, kRegServoTorqueSwitch, on ? 1 : 0); }
  69. bool FeiTeServoMotor::getTorqueSwitch(uint8_t id, bool& on) {
  70. uint8_t data = 0;
  71. bool suc = read_u8(id, kRegServoTorqueSwitch, data);
  72. on = data;
  73. return suc;
  74. }
  75. bool FeiTeServoMotor::getNowPos(uint8_t id, int16_t& pos) { return read_s16(id, kRegServoCurrentPos, 15, pos); }
  76. bool FeiTeServoMotor::setTargetPos(uint8_t id, int16_t pos) { return write_s16(id, kRegServoTargetPos, 15, pos); }
  77. bool FeiTeServoMotor::triggerAysncWrite(uint8_t id) {
  78. cmd_header_t* cmd_header = (cmd_header_t*)m_txbuf;
  79. cmd_header->header = 0xffff;
  80. cmd_header->id = id;
  81. cmd_header->len = 2;
  82. cmd_header->cmd = 5;
  83. cmd_header->data[0] = checksum((uint8_t*)cmd_header, sizeof(cmd_header_t) + 1);
  84. // HAL_UART_Transmit(m_uart, m_txbuf, sizeof(cmd_header_t) + 1, 1000);
  85. return true;
  86. }
  87. bool FeiTeServoMotor::rotate(uint8_t id, int16_t speed, uint16_t torque) {
  88. DO(setmode(id, kMotorMode));
  89. if (torque == 0) torque = 1000;
  90. DO(write_u16(id, kRegServoTorqueLimit, torque));
  91. DO(write_s16(id, kRegServoRunSpeed, 15, speed));
  92. return true;
  93. }
  94. bool FeiTeServoMotor::moveTo(uint8_t id, int16_t pos, int16_t speed, uint16_t torque) {
  95. /**
  96. * @brief Ť
  97. */
  98. DO(setmode(id, kServoMode));
  99. if (torque == 0) torque = 1000;
  100. DO(write_u16(id, kRegServoTorqueLimit, torque));
  101. DO(write_s16(id, kRegServoRunSpeed, 15, speed));
  102. DO(setTargetPos(id, pos));
  103. return true;
  104. }
  105. uint16_t abs16(int16_t val) {
  106. if (val < 0) {
  107. return -val;
  108. } else {
  109. return val;
  110. }
  111. }
  112. bool FeiTeServoMotor::moveWithTorque(uint8_t id, int16_t torque) {
  113. DO(setmode(id, kOpenMotorMode));
  114. if (torque == 0) torque = 1000;
  115. DO(write_u16(id, kRegServoTorqueLimit, abs16(torque)));
  116. DO(write_s16(id, kRegServoRunTime, 15, torque));
  117. return true;
  118. }
  119. static int16_t tosign16(uint16_t* d, int signoff) {
  120. uint16_t sign = (*d >> signoff) & 0x01;
  121. uint16_t val = *d & (~(1 << signoff));
  122. if (sign == 0) {
  123. return val;
  124. } else {
  125. return -val;
  126. }
  127. }
  128. bool FeiTeServoMotor::read_status(uint8_t id, status_t* status) {
  129. // kRegServoCurrentPos
  130. bool suc = read_reg(id, kRegServoCurrentPos, (uint8_t*)status, sizeof(status_t));
  131. status->vel = tosign16((uint16_t*)&status->vel, 15);
  132. if (!suc) return false;
  133. return true;
  134. }
  135. bool FeiTeServoMotor::read_detailed_status(uint8_t id, detailed_status_t* detailed_status) {
  136. bool suc = read_reg(id, kRegServoCurrentPos, (uint8_t*)detailed_status, sizeof(*detailed_status));
  137. if (!suc) return false;
  138. detailed_status->vel = tosign16((uint16_t*)&detailed_status->vel, 15);
  139. detailed_status->torque = tosign16((uint16_t*)&detailed_status->torque, 10);
  140. return true;
  141. }
  142. void FeiTeServoMotor::dump_status(status_t* status) {
  143. ZLOGI(TAG, "===========status===========");
  144. ZLOGI(TAG, "= status->pos :%d", status->pos);
  145. ZLOGI(TAG, "= status->vel :%d", status->vel);
  146. ZLOGI(TAG, "= status->torque :%d", status->torque);
  147. ZLOGI(TAG, "=");
  148. }
  149. #define BIT_IN_BYTE(byte, off) ((byte >> off) & 0x01)
  150. void FeiTeServoMotor::dump_detailed_status(detailed_status_t* detailed_status) {
  151. ZLOGI(TAG, "===========detailed_status===========");
  152. ZLOGI(TAG, "= detailed_status->pos :%d", detailed_status->pos);
  153. ZLOGI(TAG, "= detailed_status->vel :%d", detailed_status->vel);
  154. ZLOGI(TAG, "= detailed_status->torque :%d", detailed_status->torque);
  155. ZLOGI(TAG, "= detailed_status->voltage :%d", detailed_status->voltage);
  156. ZLOGI(TAG, "= detailed_status->temperature:%d", detailed_status->temperature);
  157. ZLOGI(TAG, "= detailed_status->state :%d:%d:%d:%d:%d:%d", BIT_IN_BYTE(detailed_status->state, 0), BIT_IN_BYTE(detailed_status->state, 1), BIT_IN_BYTE(detailed_status->state, 2),
  158. BIT_IN_BYTE(detailed_status->state, 3), BIT_IN_BYTE(detailed_status->state, 4), BIT_IN_BYTE(detailed_status->state, 5));
  159. ZLOGI(TAG, "= detailed_status->moveflag :%d", detailed_status->moveflag);
  160. ZLOGI(TAG, "= detailed_status->current :%d", detailed_status->current);
  161. ZLOGI(TAG, "=");
  162. }
  163. bool FeiTeServoMotor::getMoveFlag(uint8_t id, uint8_t& moveflag) { return read_u8(id, kRegServoMoveFlag, moveflag); }
  164. bool FeiTeServoMotor::reCalibration(int id, int16_t pos) {
  165. if (pos < 0 || pos > 4095) {
  166. ZLOGE(TAG, "reCalibration pos:%d out of range", pos);
  167. return false;
  168. }
  169. /**
  170. * @brief رŤؿأֹ˶
  171. */
  172. setTorqueSwitch(id, false);
  173. /**
  174. * @brief õǰģʽΪλģʽ
  175. */
  176. DO(setmode(id, kServoMode));
  177. int16_t curpos;
  178. DO(getNowPos(id, curpos));
  179. int16_t curcalibrate;
  180. DO(getServoCalibration(id, curcalibrate));
  181. int16_t realpos = curpos + curcalibrate;
  182. int16_t newcalibrate = getcalibrate(realpos, pos);
  183. ZLOGI(TAG, "reCalibration id:%d curpos:%d curcalibrate:%d realpos:%d newcalibrate:%d", id, curpos, curcalibrate, realpos, newcalibrate);
  184. /**
  185. * @brief дµУ׼ֵ
  186. */
  187. DO(write_u8(id, kRegServoLockFlag, 0));
  188. DO(write_s16(id, kRegServoCalibration, 11, newcalibrate));
  189. DO(write_u8(id, kRegServoLockFlag, 1));
  190. /**
  191. * @brief ĿλΪǰλ
  192. */
  193. int16_t nowpos;
  194. DO(getNowPos(id, nowpos));
  195. ZLOGI(TAG, "reCalibration id:%d nowpos:%d:%d", id, nowpos, pos);
  196. DO(setTargetPos(id, pos));
  197. return true;
  198. }
  199. /*******************************************************************************
  200. * BASEFUNC *
  201. *******************************************************************************/
  202. bool FeiTeServoMotor::write_u8(uint8_t id, feite::reg_add_e add, uint8_t regval) { return write_reg(id, false, add, &regval, 1); }
  203. bool FeiTeServoMotor::read_u8(uint8_t id, feite::reg_add_e add, uint8_t& regval) { return read_reg(id, add, &regval, 1); }
  204. bool FeiTeServoMotor::write_u16(uint8_t id, feite::reg_add_e add, uint16_t regval) { return write_reg(id, false, add, (uint8_t*)&regval, 2); }
  205. bool FeiTeServoMotor::read_u16(uint8_t id, feite::reg_add_e add, uint16_t& regval) { return read_reg(id, add, (uint8_t*)&regval, 2); }
  206. bool FeiTeServoMotor::async_write_u8(uint8_t id, feite::reg_add_e add, uint8_t regval) { return write_reg(id, true, add, &regval, 1); }
  207. bool FeiTeServoMotor::async_write_u16(uint8_t id, feite::reg_add_e add, uint16_t regval) { return write_reg(id, true, add, (uint8_t*)&regval, 2); }
  208. bool FeiTeServoMotor::async_write_s16(uint8_t id, feite::reg_add_e add, uint8_t signbitoff, int16_t regval) {
  209. uint16_t val = 0;
  210. if (regval >= 0) {
  211. val = regval;
  212. } else {
  213. val = -regval;
  214. val |= (1 << signbitoff);
  215. }
  216. return async_write_u16(id, add, val);
  217. }
  218. bool FeiTeServoMotor::read_s16(uint8_t id, feite::reg_add_e add, uint8_t signbitoff, int16_t& regval) {
  219. uint16_t val = 0;
  220. bool ret = read_u16(id, add, val);
  221. if (!ret) return false;
  222. uint8_t sign = (val >> signbitoff) & 0x01;
  223. uint16_t realval = val & (~(1 << signbitoff));
  224. if (sign == 0) {
  225. regval = realval;
  226. } else {
  227. regval = -realval;
  228. }
  229. return true;
  230. }
  231. bool FeiTeServoMotor::write_s16(uint8_t id, feite::reg_add_e add, uint8_t signbitoff, int16_t regval) {
  232. uint16_t val = 0;
  233. if (regval >= 0) {
  234. val = regval;
  235. } else {
  236. val = -regval;
  237. val |= (1 << signbitoff);
  238. }
  239. return write_u16(id, add, val);
  240. }
  241. bool FeiTeServoMotor::write_reg(uint8_t id, bool async, uint8_t add, uint8_t* data, uint8_t len) { //
  242. ZLOGI(TAG, "write_reg id:%d add:%d len:%d", id, add, len);
  243. cmd_header_t* cmd_header = (cmd_header_t*)m_txbuf;
  244. receipt_header_t* receipt_header = (receipt_header_t*)m_rxbuf;
  245. cmd_header->header = 0xffff;
  246. cmd_header->id = id;
  247. cmd_header->len = 3 + len; // 3 == cmd + add + checksum
  248. cmd_header->cmd = async ? kasyncWrite : kwrite;
  249. cmd_header->data[0] = add;
  250. memcpy(&cmd_header->data[1], data, len);
  251. int txpacketlen = sizeof(cmd_header_t) + 1 + len + 1;
  252. int rxpacketlen = sizeof(receipt_header_t) + 1;
  253. uint8_t checksum = checksum_packet((uint8_t*)cmd_header, txpacketlen);
  254. m_txbuf[txpacketlen - 1] = checksum;
  255. if (!tx_and_rx(m_txbuf, txpacketlen, m_rxbuf, rxpacketlen, OVERTIME)) {
  256. ZLOGE(TAG, "write_reg fail,overtime");
  257. return false;
  258. }
  259. if (!(receipt_header->header == 0xffff && receipt_header->id == id)) {
  260. ZLOGE(TAG, "write_reg fail,receipt header error");
  261. return false;
  262. }
  263. return true;
  264. }
  265. bool FeiTeServoMotor::read_reg(uint8_t id, uint8_t add, uint8_t* data, uint8_t len) {
  266. // return false;
  267. cmd_header_t* cmd_header = (cmd_header_t*)m_txbuf;
  268. receipt_header_t* receipt_header = (receipt_header_t*)m_rxbuf;
  269. cmd_header->header = 0xffff;
  270. cmd_header->id = id;
  271. cmd_header->len = 3 + 1; // 4 == cmd + add + checksum + readlen
  272. cmd_header->cmd = kread;
  273. cmd_header->data[0] = add;
  274. cmd_header->data[1] = len;
  275. int txpacketlen = sizeof(cmd_header_t) + 3;
  276. int rxpacketlen = sizeof(receipt_header_t) + 1 + len;
  277. uint8_t checksum = checksum_packet((uint8_t*)cmd_header, txpacketlen);
  278. m_txbuf[txpacketlen - 1] = checksum;
  279. if (!tx_and_rx(m_txbuf, txpacketlen, m_rxbuf, rxpacketlen, OVERTIME)) {
  280. return false;
  281. }
  282. if (!(receipt_header->header == 0xffff && receipt_header->id == id)) {
  283. ZLOGE(TAG, "read_reg fail,receipt header error");
  284. return false;
  285. }
  286. memcpy(data, receipt_header->data, len);
  287. return true;
  288. }
  289. bool FeiTeServoMotor::tx_and_rx(uint8_t* tx, uint8_t txdatalen, uint8_t* rx, uint8_t expectrxsize, uint16_t overtimems) {
  290. uint32_t enter_ticket = HAL_GetTick();
  291. dumphex("tx:", tx, txdatalen);
  292. HAL_UART_Transmit(m_uart, tx, txdatalen, 1000);
  293. HAL_UART_Receive_DMA(m_uart, (uint8_t*)rx, expectrxsize);
  294. bool overtime_flag = false;
  295. while (HAL_UART_GetState(m_uart) == HAL_UART_STATE_BUSY_RX || //
  296. HAL_UART_GetState(m_uart) == HAL_UART_STATE_BUSY_TX_RX) {
  297. osDelay(1);
  298. int rxsize = expectrxsize - __HAL_DMA_GET_COUNTER(m_hdma_rx);
  299. if (rxsize == expectrxsize) {
  300. dumphex("rx:", rx, expectrxsize);
  301. break;
  302. }
  303. if (zos_haspassedms(enter_ticket) > overtimems) {
  304. if (expectrxsize != 0 && rxsize != 0) {
  305. ZLOGW(TAG, "txandrx overtime rxsize:%d != expect_size:%d", rxsize, expectrxsize);
  306. }
  307. overtime_flag = true;
  308. break;
  309. }
  310. }
  311. HAL_UART_DMAStop(m_uart);
  312. if (overtime_flag) {
  313. return false;
  314. }
  315. return true;
  316. }
  317. bool FeiTeServoMotor::readversion(uint8_t id, uint8_t& mainversion, uint8_t& subversion, uint8_t& miniserv_mainversion, uint8_t& miniserv_subversion) {
  318. uint8_t data = 0;
  319. DO(read_u8(id, kRegFirmwareMainVersion, data));
  320. mainversion = data;
  321. DO(read_u8(id, kRegFirmwareSubVersion, data));
  322. subversion = data;
  323. DO(read_u8(id, kRegServoMainVersion, data));
  324. miniserv_mainversion = data;
  325. DO(read_u8(id, kRegServoSubVersion, data));
  326. miniserv_subversion = data;
  327. return true;
  328. }
  329. uint8_t FeiTeServoMotor::checksum_packet(uint8_t* data, uint8_t len) { return checksum(&data[2], len - 3); }
  330. uint8_t FeiTeServoMotor::checksum(uint8_t* data, uint8_t len) {
  331. // CheckSum=~(ID+Length+Instruction+Parameter1+...ParameterN
  332. uint16_t sum = 0;
  333. for (int i = 0; i < len; i++) {
  334. sum += data[i];
  335. }
  336. return ~(sum & 0xff);
  337. }