Keyboard firmwares for Atmel AVR and Cortex-M
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.

AX12.cpp 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. /* mbed AX-12+ Servo Library
  2. *
  3. * Copyright (c) 2010, cstyles (http://mbed.org)
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a copy
  6. * of this software and associated documentation files (the "Software"), to deal
  7. * in the Software without restriction, including without limitation the rights
  8. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. * copies of the Software, and to permit persons to whom the Software is
  10. * furnished to do so, subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be included in
  13. * all copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. * THE SOFTWARE.
  22. */
  23. #include "AX12.h"
  24. #include "mbed.h"
  25. AX12::AX12(PinName tx, PinName rx, int ID, int baud)
  26. : _ax12(tx,rx) {
  27. _baud = baud;
  28. _ID = ID;
  29. _ax12.baud(_baud);
  30. }
  31. // Set the mode of the servo
  32. // 0 = Positional (0-300 degrees)
  33. // 1 = Rotational -1 to 1 speed
  34. int AX12::SetMode(int mode) {
  35. if (mode == 1) { // set CR
  36. SetCWLimit(0);
  37. SetCCWLimit(0);
  38. SetCRSpeed(0.0);
  39. } else {
  40. SetCWLimit(0);
  41. SetCCWLimit(300);
  42. SetCRSpeed(0.0);
  43. }
  44. return(0);
  45. }
  46. // if flag[0] is set, were blocking
  47. // if flag[1] is set, we're registering
  48. // they are mutually exclusive operations
  49. int AX12::SetGoal(int degrees, int flags) {
  50. char reg_flag = 0;
  51. char data[2];
  52. // set the flag is only the register bit is set in the flag
  53. if (flags == 0x2) {
  54. reg_flag = 1;
  55. }
  56. // 1023 / 300 * degrees
  57. short goal = (1023 * degrees) / 300;
  58. #ifdef AX12_DEBUG
  59. printf("SetGoal to 0x%x\n",goal);
  60. #endif
  61. data[0] = goal & 0xff; // bottom 8 bits
  62. data[1] = goal >> 8; // top 8 bits
  63. // write the packet, return the error code
  64. int rVal = write(_ID, AX12_REG_GOAL_POSITION, 2, data, reg_flag);
  65. if (flags == 1) {
  66. // block until it comes to a halt
  67. while (isMoving()) {}
  68. }
  69. return(rVal);
  70. }
  71. // Set continuous rotation speed from -1 to 1
  72. int AX12::SetCRSpeed(float speed) {
  73. // bit 10 = direction, 0 = CCW, 1=CW
  74. // bits 9-0 = Speed
  75. char data[2];
  76. int goal = (0x3ff * abs(speed));
  77. // Set direction CW if we have a negative speed
  78. if (speed < 0) {
  79. goal |= (0x1 << 10);
  80. }
  81. data[0] = goal & 0xff; // bottom 8 bits
  82. data[1] = goal >> 8; // top 8 bits
  83. // write the packet, return the error code
  84. int rVal = write(_ID, 0x20, 2, data);
  85. return(rVal);
  86. }
  87. int AX12::SetCWLimit (int degrees) {
  88. char data[2];
  89. // 1023 / 300 * degrees
  90. short limit = (1023 * degrees) / 300;
  91. #ifdef AX12_DEBUG
  92. printf("SetCWLimit to 0x%x\n",limit);
  93. #endif
  94. data[0] = limit & 0xff; // bottom 8 bits
  95. data[1] = limit >> 8; // top 8 bits
  96. // write the packet, return the error code
  97. return (write(_ID, AX12_REG_CW_LIMIT, 2, data));
  98. }
  99. int AX12::SetCCWLimit (int degrees) {
  100. char data[2];
  101. // 1023 / 300 * degrees
  102. short limit = (1023 * degrees) / 300;
  103. #ifdef AX12_DEBUG
  104. printf("SetCCWLimit to 0x%x\n",limit);
  105. #endif
  106. data[0] = limit & 0xff; // bottom 8 bits
  107. data[1] = limit >> 8; // top 8 bits
  108. // write the packet, return the error code
  109. return (write(_ID, AX12_REG_CCW_LIMIT, 2, data));
  110. }
  111. int AX12::SetID (int CurrentID, int NewID) {
  112. char data[1];
  113. data[0] = NewID;
  114. #ifdef AX12_DEBUG
  115. printf("Setting ID from 0x%x to 0x%x\n",CurrentID,NewID);
  116. #endif
  117. return (write(CurrentID, AX12_REG_ID, 1, data));
  118. }
  119. int AX12::SetBaud (int baud) {
  120. char data[1];
  121. data[0] = baud;
  122. #ifdef AX12_DEBUG
  123. printf("Setting Baud rate to %d\n",baud);
  124. #endif
  125. return (write(0xFE, AX12_REG_BAUD, 1, data));
  126. }
  127. // return 1 is the servo is still in flight
  128. int AX12::isMoving(void) {
  129. char data[1];
  130. read(_ID,AX12_REG_MOVING,1,data);
  131. return(data[0]);
  132. }
  133. void AX12::trigger(void) {
  134. char TxBuf[16];
  135. char sum = 0;
  136. #ifdef AX12_TRIGGER_DEBUG
  137. // Build the TxPacket first in RAM, then we'll send in one go
  138. printf("\nTriggered\n");
  139. printf("\nTrigger Packet\n Header : 0xFF, 0xFF\n");
  140. #endif
  141. TxBuf[0] = 0xFF;
  142. TxBuf[1] = 0xFF;
  143. // ID - Broadcast
  144. TxBuf[2] = 0xFE;
  145. sum += TxBuf[2];
  146. #ifdef AX12_TRIGGER_DEBUG
  147. printf(" ID : %d\n",TxBuf[2]);
  148. #endif
  149. // Length
  150. TxBuf[3] = 0x02;
  151. sum += TxBuf[3];
  152. #ifdef AX12_TRIGGER_DEBUG
  153. printf(" Length %d\n",TxBuf[3]);
  154. #endif
  155. // Instruction - ACTION
  156. TxBuf[4] = 0x04;
  157. sum += TxBuf[4];
  158. #ifdef AX12_TRIGGER_DEBUG
  159. printf(" Instruction 0x%X\n",TxBuf[5]);
  160. #endif
  161. // Checksum
  162. TxBuf[5] = 0xFF - sum;
  163. #ifdef AX12_TRIGGER_DEBUG
  164. printf(" Checksum 0x%X\n",TxBuf[5]);
  165. #endif
  166. // Transmit the packet in one burst with no pausing
  167. for (int i = 0; i < 6 ; i++) {
  168. _ax12.putc(TxBuf[i]);
  169. }
  170. // This is a broadcast packet, so there will be no reply
  171. return;
  172. }
  173. float AX12::GetPosition(void) {
  174. #ifdef AX12_DEBUG
  175. printf("\nGetPosition(%d)",_ID);
  176. #endif
  177. char data[2];
  178. int ErrorCode = read(_ID, AX12_REG_POSITION, 2, data);
  179. short position = data[0] + (data[1] << 8);
  180. float angle = (position * 300)/1024;
  181. return (angle);
  182. }
  183. float AX12::GetTemp (void) {
  184. #ifdef AX12_DEBUG
  185. printf("\nGetTemp(%d)",_ID);
  186. #endif
  187. char data[1];
  188. int ErrorCode = read(_ID, AX12_REG_TEMP, 1, data);
  189. float temp = data[0];
  190. return(temp);
  191. }
  192. float AX12::GetVolts (void) {
  193. #ifdef AX12_DEBUG
  194. printf("\nGetVolts(%d)",_ID);
  195. #endif
  196. char data[1];
  197. int ErrorCode = read(_ID, AX12_REG_VOLTS, 1, data);
  198. float volts = data[0]/10.0;
  199. return(volts);
  200. }
  201. int AX12::read(int ID, int start, int bytes, char* data) {
  202. char PacketLength = 0x4;
  203. char TxBuf[16];
  204. char sum = 0;
  205. char Status[16];
  206. Status[4] = 0xFE; // return code
  207. #ifdef AX12_READ_DEBUG
  208. printf("\nread(%d,0x%x,%d,data)\n",ID,start,bytes);
  209. #endif
  210. // Build the TxPacket first in RAM, then we'll send in one go
  211. #ifdef AX12_READ_DEBUG
  212. printf("\nInstruction Packet\n Header : 0xFF, 0xFF\n");
  213. #endif
  214. TxBuf[0] = 0xff;
  215. TxBuf[1] = 0xff;
  216. // ID
  217. TxBuf[2] = ID;
  218. sum += TxBuf[2];
  219. #ifdef AX12_READ_DEBUG
  220. printf(" ID : %d\n",TxBuf[2]);
  221. #endif
  222. // Packet Length
  223. TxBuf[3] = PacketLength; // Length = 4 ; 2 + 1 (start) = 1 (bytes)
  224. sum += TxBuf[3]; // Accululate the packet sum
  225. #ifdef AX12_READ_DEBUG
  226. printf(" Length : 0x%x\n",TxBuf[3]);
  227. #endif
  228. // Instruction - Read
  229. TxBuf[4] = 0x2;
  230. sum += TxBuf[4];
  231. #ifdef AX12_READ_DEBUG
  232. printf(" Instruction : 0x%x\n",TxBuf[4]);
  233. #endif
  234. // Start Address
  235. TxBuf[5] = start;
  236. sum += TxBuf[5];
  237. #ifdef AX12_READ_DEBUG
  238. printf(" Start Address : 0x%x\n",TxBuf[5]);
  239. #endif
  240. // Bytes to read
  241. TxBuf[6] = bytes;
  242. sum += TxBuf[6];
  243. #ifdef AX12_READ_DEBUG
  244. printf(" No bytes : 0x%x\n",TxBuf[6]);
  245. #endif
  246. // Checksum
  247. TxBuf[7] = 0xFF - sum;
  248. #ifdef AX12_READ_DEBUG
  249. printf(" Checksum : 0x%x\n",TxBuf[7]);
  250. #endif
  251. // Transmit the packet in one burst with no pausing
  252. for (int i = 0; i<8 ; i++) {
  253. _ax12.putc(TxBuf[i]);
  254. }
  255. // Wait for the bytes to be transmitted
  256. wait (0.00002);
  257. // Skip if the read was to the broadcast address
  258. if (_ID != 0xFE) {
  259. // response packet is always 6 + bytes
  260. // 0xFF, 0xFF, ID, Length Error, Param(s) Checksum
  261. // timeout is a little more than the time to transmit
  262. // the packet back, i.e. (6+bytes)*10 bit periods
  263. int timeout = 0;
  264. int plen = 0;
  265. while ((timeout < ((6+bytes)*10)) && (plen<(6+bytes))) {
  266. if (_ax12.readable()) {
  267. Status[plen] = _ax12.getc();
  268. plen++;
  269. timeout = 0;
  270. }
  271. // wait for the bit period
  272. wait (1.0/_baud);
  273. timeout++;
  274. }
  275. if (timeout == ((6+bytes)*10) ) {
  276. return(-1);
  277. }
  278. // Copy the data from Status into data for return
  279. for (int i=0; i < Status[3]-2 ; i++) {
  280. data[i] = Status[5+i];
  281. }
  282. #ifdef AX12_READ_DEBUG
  283. printf("\nStatus Packet\n");
  284. printf(" Header : 0x%x\n",Status[0]);
  285. printf(" Header : 0x%x\n",Status[1]);
  286. printf(" ID : 0x%x\n",Status[2]);
  287. printf(" Length : 0x%x\n",Status[3]);
  288. printf(" Error Code : 0x%x\n",Status[4]);
  289. for (int i=0; i < Status[3]-2 ; i++) {
  290. printf(" Data : 0x%x\n",Status[5+i]);
  291. }
  292. printf(" Checksum : 0x%x\n",Status[5+(Status[3]-2)]);
  293. #endif
  294. } // if (ID!=0xFE)
  295. return(Status[4]);
  296. }
  297. int AX12::write(int ID, int start, int bytes, char* data, int flag) {
  298. // 0xff, 0xff, ID, Length, Intruction(write), Address, Param(s), Checksum
  299. char TxBuf[16];
  300. char sum = 0;
  301. char Status[6];
  302. #ifdef AX12_WRITE_DEBUG
  303. printf("\nwrite(%d,0x%x,%d,data,%d)\n",ID,start,bytes,flag);
  304. #endif
  305. // Build the TxPacket first in RAM, then we'll send in one go
  306. #ifdef AX12_WRITE_DEBUG
  307. printf("\nInstruction Packet\n Header : 0xFF, 0xFF\n");
  308. #endif
  309. TxBuf[0] = 0xff;
  310. TxBuf[1] = 0xff;
  311. // ID
  312. TxBuf[2] = ID;
  313. sum += TxBuf[2];
  314. #ifdef AX12_WRITE_DEBUG
  315. printf(" ID : %d\n",TxBuf[2]);
  316. #endif
  317. // packet Length
  318. TxBuf[3] = 3+bytes;
  319. sum += TxBuf[3];
  320. #ifdef AX12_WRITE_DEBUG
  321. printf(" Length : %d\n",TxBuf[3]);
  322. #endif
  323. // Instruction
  324. if (flag == 1) {
  325. TxBuf[4]=0x04;
  326. sum += TxBuf[4];
  327. } else {
  328. TxBuf[4]=0x03;
  329. sum += TxBuf[4];
  330. }
  331. #ifdef AX12_WRITE_DEBUG
  332. printf(" Instruction : 0x%x\n",TxBuf[4]);
  333. #endif
  334. // Start Address
  335. TxBuf[5] = start;
  336. sum += TxBuf[5];
  337. #ifdef AX12_WRITE_DEBUG
  338. printf(" Start : 0x%x\n",TxBuf[5]);
  339. #endif
  340. // data
  341. for (char i=0; i<bytes ; i++) {
  342. TxBuf[6+i] = data[i];
  343. sum += TxBuf[6+i];
  344. #ifdef AX12_WRITE_DEBUG
  345. printf(" Data : 0x%x\n",TxBuf[6+i]);
  346. #endif
  347. }
  348. // checksum
  349. TxBuf[6+bytes] = 0xFF - sum;
  350. #ifdef AX12_WRITE_DEBUG
  351. printf(" Checksum : 0x%x\n",TxBuf[6+bytes]);
  352. #endif
  353. // Transmit the packet in one burst with no pausing
  354. for (int i = 0; i < (7 + bytes) ; i++) {
  355. _ax12.putc(TxBuf[i]);
  356. }
  357. // Wait for data to transmit
  358. wait (0.00002);
  359. // make sure we have a valid return
  360. Status[4]=0x00;
  361. // we'll only get a reply if it was not broadcast
  362. if (_ID!=0xFE) {
  363. // response packet is always 6 bytes
  364. // 0xFF, 0xFF, ID, Length Error, Param(s) Checksum
  365. // timeout is a little more than the time to transmit
  366. // the packet back, i.e. 60 bit periods, round up to 100
  367. int timeout = 0;
  368. int plen = 0;
  369. while ((timeout < 100) && (plen<6)) {
  370. if (_ax12.readable()) {
  371. Status[plen] = _ax12.getc();
  372. plen++;
  373. timeout = 0;
  374. }
  375. // wait for the bit period
  376. wait (1.0/_baud);
  377. timeout++;
  378. }
  379. // Build the TxPacket first in RAM, then we'll send in one go
  380. #ifdef AX12_WRITE_DEBUG
  381. printf("\nStatus Packet\n Header : 0x%X, 0x%X\n",Status[0],Status[1]);
  382. printf(" ID : %d\n",Status[2]);
  383. printf(" Length : %d\n",Status[3]);
  384. printf(" Error : 0x%x\n",Status[4]);
  385. printf(" Checksum : 0x%x\n",Status[5]);
  386. #endif
  387. }
  388. return(Status[4]); // return error code
  389. }