PageRenderTime 52ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/player-3.0.2/server/drivers/position/motionmind/motionmind.cc

#
C++ | 709 lines | 441 code | 72 blank | 196 comment | 36 complexity | 723aed24717f24e5866e8a50393bd1b3 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, BSD-3-Clause
  1. /*
  2. * Player - One Hell of a Robot Server
  3. * Copyright (C) 2000
  4. * Brian Gerkey, Kasper Stoy, Richard Vaughan, & Andrew Howard
  5. *
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. *
  21. */
  22. /*
  23. * mmdriver.cpp
  24. * motionminddriver
  25. *
  26. * Created by Chris Chambers on 31/03/08.
  27. *
  28. */
  29. /** @ingroup drivers Drivers */
  30. /** @{ */
  31. /** @defgroup driver_motionmind motionmind
  32. * @brief Solutions Cubed motor controller
  33. The motionmind driver is for communicating with a Solutions Cubed "Motion Mind" PID motor controller while it is in serial PID mode.
  34. Multiple boards can be daisy chained together and different drivers used for each one by simply giving each driver the address
  35. of the board that it is commanding. This driver allows for simple absolute position commands and publishes the position of the device as well.
  36. @par Compile-time dependencies
  37. - none
  38. @par Provides
  39. - @ref interface_position1d : publishes the position of the motor and allows for absolute position commands to be sent
  40. @par Requires
  41. - @ref interface_opaque : used to get the serial information form the motion mind control boards
  42. @par Configuration requests
  43. - none
  44. @par Supported commands
  45. - PLAYER_POSITION_1D_CMD_POS: The absolute position to send the actuator to
  46. - @todo : add support for PLAYER_POSITON_1D_CMD_VEL
  47. @par Configuration file options
  48. - address (int)
  49. - Default 1
  50. - Address of the motionmind board that you wish to control
  51. - cpr (int)
  52. - Default 500
  53. - counts per motor rotation
  54. - gear_ratio
  55. - Default 1.0
  56. - n:1 gear_ratio - robot position in m or rad:motor rotation
  57. - divide the gear_ratio by 2*PI for rotational actuators
  58. @par Example
  59. @verbatim
  60. # Board number 1
  61. driver(
  62. name "motionmind"
  63. provides ["position1d:0"]
  64. requires ["opaque:0"]
  65. address 1
  66. )
  67. #Board Number 2
  68. driver(
  69. name "motionmind"
  70. provides ["position1d:1"]
  71. requires ["opaque:0"]
  72. address 2
  73. cpr 500
  74. gear_ratio 2.0
  75. )
  76. driver(
  77. name "serialstream"
  78. port "/dev/ttyS0"
  79. transfer_rate 19200
  80. parity "none"
  81. provides ["opaque:0"]
  82. alwayson 1
  83. # IF ATTACHED TO MORE THAN ONE MOTIONMIND BOARD YOU MUST HAVE A WAIT TIME OR THINGS TIMEOUT
  84. wait_time 40000
  85. )
  86. @endverbatim
  87. @author Chris Chambers
  88. */
  89. /** @} */
  90. #if !defined (WIN32)
  91. #include <unistd.h>
  92. #endif
  93. #include <string.h>
  94. #include <time.h>
  95. #include <libplayercore/playercore.h>
  96. #define DEFAULT_RX_BUFFER_SIZE 128
  97. #define DEFAULT_ADDRESS 1
  98. #define MESSAGE_LENGTH 7
  99. #define MM_WRITE_MESSAGE_LENGTH 8
  100. #define MM_MSG_WAIT 20000 //microseconds to wait before sending another command
  101. // s/b 1250 according documentation but had comm errors below 20000
  102. #define MSG_TIMEOUT 250000 //microseconds before it sends another read request if it hasn't yet got a reply
  103. #define MM_DATA_WAIT 2500 //microseconds to wait before checking for response data
  104. #define MM_CPU_WAIT 10000 //microseconds to wait before checking for missing response data and to prevent CPU overloading
  105. #define MM_DEFAULT_CPR 500
  106. #define MM_DEFAULT_GEAR_RATIO 1.0
  107. #define MM_READ_POSITION 0x01 // Data0
  108. #define MM_READ_STATUS 0x01 // Data2
  109. #define MM_WRITE_REG 0x18
  110. // Status register bit packing
  111. #define MM_STATUS_NEGLIMIT 0x0001
  112. #define MM_STATUS_POSLIMIT 0x0002
  113. #define MM_STATUS_BRAKE 0x0004
  114. #define MM_STATUS_INDEX 0x0008
  115. #define MM_STATUS_BADRC 0x0010
  116. #define MM_STATUS_VNLIMIT 0x0020
  117. #define MM_STATUS_VPLIMIT 0x0040
  118. #define MM_STATUS_CURRENTLIMIT 0x0080
  119. #define MM_STATUS_PWMLIMIT 0x0100
  120. #define MM_STATUS_INPOSITION 0x0200
  121. // Register indexes for WRITE and WRITE STORE commands
  122. #define MM_REG_POSITION 0x00
  123. ///////////////////////////////////////////////////////////////////////////////
  124. // The class for the driver
  125. class MotionMind : public ThreadedDriver
  126. {
  127. public:
  128. // Constructor; need that
  129. MotionMind(ConfigFile* cf, int section);
  130. ~MotionMind();
  131. // Must implement the following methods.
  132. virtual int MainSetup();
  133. virtual void MainQuit();
  134. // This method will be invoked on each incoming message
  135. virtual int ProcessMessage(QueuePointer & resp_queue,
  136. player_msghdr* hdr,
  137. void* data);
  138. private:
  139. // Main function for device thread.
  140. virtual void Main();
  141. //Requests the pos of the robot if it hasnt been already
  142. void FindCurrentPos();
  143. //Requests the status register of the robot if it hasn't been already
  144. void FindCurrentStatus();
  145. // Checks whether or not you have sent a request for the position
  146. bool pos_request_sent;
  147. bool status_request_sent;
  148. struct timeval msg_sent;
  149. struct timeval time_sent_pos;
  150. struct timeval time_sent_status;
  151. int MsgWait();
  152. //Makes a command to be sent to the opaque driver
  153. void makeAbsolutePositionCommand(uint8_t* buffer, unsigned int address, float position);
  154. //Makes a command which requests the current osition bback from the motor ocntroller
  155. void makeReadPositionCommand(uint8_t* buffer, unsigned int address);
  156. //Makes a command which requests the current status back from the motor controller
  157. void makeReadStatusCommand(uint8_t* buffer, unsigned int address);
  158. //Makes a command which sets the odometry to the given value
  159. void makeSetOdomReq(uint8_t* buffer, unsigned int address, const float position);
  160. //Converts robot positions to absolute motionmind positions
  161. int robot2abspos(const float position);
  162. // The function to do stuff here
  163. void DoStuff();
  164. // Opaque Driver info
  165. Device *opaque;
  166. player_devaddr_t opaque_id;
  167. // The address of the board being addressed
  168. uint8_t address;
  169. // rx buffer
  170. uint8_t * rx_buffer;
  171. unsigned int rx_buffer_size;
  172. unsigned int rx_count;
  173. // player position1 data odometric pose, velocity and motor stall info
  174. player_position1d_data_t pos_data;
  175. // counts per rotation
  176. int cpr;
  177. // gear ratio robot:motor
  178. double gear_ratio;
  179. };
  180. ////////////////////////////////////////////////////////////////////////////////
  181. // Now the driver
  182. // A factory creation function, declared outside of the class so that it
  183. // can be invoked without any object context (alternatively, you can
  184. // declare it static in the class). In this function, we create and return
  185. // (as a generic Driver*) a pointer to a new instance of this driver.
  186. Driver*
  187. MotionMind_Init(ConfigFile* cf, int section)
  188. {
  189. // Create and return a new instance of this driver
  190. return ((Driver*)(new MotionMind(cf, section)));
  191. }
  192. // A driver registration function, again declared outside of the class so
  193. // that it can be invoked without object context. In this function, we add
  194. // the driver into the given driver table, indicating which interface the
  195. // driver can support and how to create a driver instance.
  196. void motionmind_Register(DriverTable* table)
  197. {
  198. table->AddDriver("motionmind", MotionMind_Init);
  199. }
  200. ////////////////////////////////////////////////////////////////////////////////
  201. // Constructor. Retrieve options from the configuration file and do any
  202. // pre-Setup() setup.
  203. MotionMind::MotionMind(ConfigFile* cf, int section)
  204. : ThreadedDriver(cf, section, false, PLAYER_MSGQUEUE_DEFAULT_MAXLEN, PLAYER_POSITION1D_CODE)
  205. {
  206. this->opaque = NULL;
  207. // Must have an opaque device
  208. if (cf->ReadDeviceAddr(&this->opaque_id, section, "requires",
  209. PLAYER_OPAQUE_CODE, -1, NULL) != 0)
  210. {
  211. puts ("No Opaque driver specified");
  212. this->SetError(-1);
  213. return;
  214. }
  215. // Read options from the configuration file
  216. address = cf->ReadInt(section, "address", DEFAULT_ADDRESS);
  217. rx_count = 0;
  218. rx_buffer_size = cf->ReadInt(section, "buffer_size", DEFAULT_RX_BUFFER_SIZE);
  219. rx_buffer = new uint8_t[rx_buffer_size];
  220. assert(rx_buffer);
  221. cpr = cf->ReadInt(section, "cpr", MM_DEFAULT_CPR);
  222. this->gear_ratio = cf->ReadFloat(section, "gear_ratio", MM_DEFAULT_GEAR_RATIO);
  223. if (this->gear_ratio == 0.0) fprintf (stderr,"gear_ratio cannot be 0.0: adjust your gear_ratio value");
  224. assert(this->gear_ratio != 0.0);
  225. this->pos_request_sent = false;
  226. this->status_request_sent = false;
  227. GlobalTime->GetTime(&(this->msg_sent));
  228. return;
  229. }
  230. MotionMind::~MotionMind()
  231. {
  232. delete [] rx_buffer;
  233. }
  234. ////////////////////////////////////////////////////////////////////////////////
  235. // Set up the device. Return 0 if things go well, and -1 otherwise.
  236. int MotionMind::MainSetup()
  237. {
  238. puts("Setting up MotionMind driver");
  239. if(Device::MatchDeviceAddress(this->opaque_id, this->device_addr))
  240. {
  241. PLAYER_ERROR("attempt to subscribe to self");
  242. return(-1);
  243. }
  244. if(!(this->opaque = deviceTable->GetDevice(this->opaque_id)))
  245. {
  246. PLAYER_ERROR("unable to locate suitable opaque device");
  247. return(-1);
  248. }
  249. if(this->opaque->Subscribe(this->InQueue) != 0)
  250. {
  251. PLAYER_ERROR("unable to subscribe to opaque device");
  252. return(-1);
  253. }
  254. puts("MotionMind driver ready");
  255. return(0);
  256. }
  257. ////////////////////////////////////////////////////////////////////////////////
  258. // Shutdown the device
  259. void MotionMind::MainQuit()
  260. {
  261. puts("MotionMind driver down");
  262. opaque->Unsubscribe(InQueue);
  263. puts("MotionMind driver has been shutdown");
  264. }
  265. // Process an incoming message
  266. int MotionMind::ProcessMessage(QueuePointer & resp_queue,
  267. player_msghdr* hdr,
  268. void* data)
  269. {
  270. assert(hdr);
  271. assert(data);
  272. if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_DATA, PLAYER_OPAQUE_DATA_STATE, opaque_id))
  273. {
  274. player_opaque_data_t * recv = reinterpret_cast<player_opaque_data_t * > (data);
  275. unsigned int messageOffset = rx_count;
  276. rx_count += recv->data_count;
  277. if (rx_count > rx_buffer_size)
  278. {
  279. PLAYER_WARN("MotionMind driver Buffer Full");
  280. rx_count = 0;
  281. }
  282. else
  283. {
  284. memcpy(&rx_buffer[messageOffset], recv->data, recv->data_count);
  285. }
  286. return 0;
  287. }
  288. if(Message::MatchMessage(hdr, PLAYER_MSGTYPE_CMD,
  289. PLAYER_POSITION1D_CMD_POS,
  290. this->device_addr))
  291. {
  292. assert(hdr->size == sizeof(player_position1d_cmd_pos_t));
  293. player_position1d_cmd_pos_t * recv = reinterpret_cast<player_position1d_cmd_pos_t *> (data);
  294. uint8_t * buffer = new uint8_t[MESSAGE_LENGTH];
  295. this->makeAbsolutePositionCommand(buffer, this->address, recv->pos);
  296. player_opaque_data_t mData;
  297. mData.data_count = MESSAGE_LENGTH;
  298. mData.data = buffer;
  299. this->MsgWait();
  300. opaque->PutMsg(this->InQueue, PLAYER_MSGTYPE_CMD, PLAYER_OPAQUE_CMD_DATA, reinterpret_cast<void*>(&mData),0,NULL);
  301. GlobalTime->GetTime(&(this->msg_sent));
  302. delete [] buffer;
  303. return(0);
  304. }
  305. if(Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ,
  306. PLAYER_POSITION1D_REQ_SET_ODOM,
  307. this->device_addr))
  308. {
  309. assert(hdr->size == sizeof(player_position1d_set_odom_req_t));
  310. player_position1d_set_odom_req_t* req = reinterpret_cast<player_position1d_set_odom_req_t*> (data);
  311. uint8_t* buffer = new uint8_t[MM_WRITE_MESSAGE_LENGTH];
  312. this->makeSetOdomReq(buffer, this->address, req->pos);
  313. player_opaque_data_t mData;
  314. mData.data_count = MM_WRITE_MESSAGE_LENGTH;
  315. mData.data = buffer;
  316. this->MsgWait();
  317. opaque->PutMsg(this->InQueue, PLAYER_MSGTYPE_CMD, PLAYER_OPAQUE_CMD_DATA, reinterpret_cast<void*>(&mData),0,NULL);
  318. GlobalTime->GetTime(&(this->msg_sent));
  319. delete [] buffer;
  320. return(0);
  321. }
  322. return -1;
  323. }
  324. ////////////////////////////////////////////////////////////////////////////////
  325. // Main function for device thread
  326. void MotionMind::Main()
  327. {
  328. // The main loop; interact with the device here
  329. for(;;)
  330. {
  331. // test if we are supposed to cancel
  332. pthread_testcancel();
  333. // Process incoming messages
  334. ProcessMessages();
  335. // Ask for the current position
  336. FindCurrentPos();
  337. // Ask for the current position status
  338. FindCurrentStatus();
  339. // Publish position data
  340. this->Publish(this->device_addr, PLAYER_MSGTYPE_DATA, PLAYER_POSITION1D_DATA_STATE, (void*)&pos_data);
  341. usleep(MM_CPU_WAIT);
  342. }
  343. return;
  344. }
  345. // Makes the required serial packet to command a position or request the position
  346. void MotionMind::makeAbsolutePositionCommand(uint8_t* buffer, unsigned int address, float position)
  347. {
  348. unsigned int checksum = 0;
  349. int posInt = robot2abspos(position);
  350. char* pos = (char*)&posInt;
  351. buffer[0] = 0x15;
  352. checksum += buffer[0];
  353. buffer[1] = address;
  354. checksum += buffer[1];
  355. buffer[2] = pos[0];
  356. checksum += buffer[2];
  357. buffer[3] = pos[1];
  358. checksum += buffer[3];
  359. buffer[4] = pos[2];
  360. checksum += buffer[4];
  361. buffer[5] = pos[3];
  362. checksum += buffer[5];
  363. buffer[6] = checksum;
  364. }
  365. void MotionMind::makeReadPositionCommand(uint8_t* buffer, unsigned int address)
  366. {
  367. unsigned int checksum = 0;
  368. // Command
  369. buffer[0] = 0x1A;
  370. checksum += buffer[0];
  371. // Address
  372. buffer[1] = address;
  373. checksum += buffer[1];
  374. // Data0
  375. buffer[2] = MM_READ_POSITION;
  376. checksum += buffer[2];
  377. // Data1
  378. buffer[3] = 0x00;
  379. checksum += buffer[3];
  380. // Data2
  381. buffer[4] = 0x00;
  382. checksum += buffer[4];
  383. // Data3
  384. buffer[5] = 0x00;
  385. checksum += buffer[5];
  386. //Checksum
  387. buffer[6] = checksum;
  388. }
  389. void MotionMind::makeReadStatusCommand(uint8_t* buffer, unsigned int address)
  390. {
  391. unsigned int checksum = 0;
  392. // Command
  393. buffer[0] = 0x1A;
  394. checksum += buffer[0];
  395. // Address
  396. buffer[1] = address;
  397. checksum += buffer[1];
  398. // Data0
  399. buffer[2] = 0x00;
  400. checksum += buffer[2];
  401. // Data1
  402. buffer[3] = 0x00;
  403. checksum += buffer[3];
  404. // Data2
  405. buffer[4] = MM_READ_STATUS;
  406. checksum += buffer[4];
  407. // Data3
  408. buffer[5] = 0x00;
  409. checksum += buffer[5];
  410. //Checksum
  411. buffer[6] = checksum;
  412. }
  413. void MotionMind::makeSetOdomReq(uint8_t* buffer, unsigned int address, float position)
  414. {
  415. unsigned int checksum = 0;
  416. uint32_t posInt = robot2abspos(position);
  417. printf("Setting position register to %0.6f : %d\n",position,posInt);
  418. char* pos = (char*)&posInt;
  419. // Command
  420. buffer[0] = MM_WRITE_REG;
  421. checksum += buffer[0];
  422. // Address
  423. buffer[1] = address;
  424. checksum += buffer[1];
  425. // Index
  426. buffer[2] = MM_REG_POSITION;
  427. checksum += buffer[2];
  428. // Data0
  429. buffer[3] = pos[0];
  430. checksum += buffer[3];
  431. // Data1
  432. buffer[4] = pos[1];
  433. checksum += buffer[4];
  434. // Data2
  435. buffer[5] = pos[2];
  436. checksum += buffer[5];
  437. // Data3
  438. buffer[6] = pos[3];
  439. checksum += buffer[6];
  440. //Checksum
  441. buffer[7] = checksum;
  442. }
  443. int MotionMind::robot2abspos(const float position)
  444. {
  445. assert(this->gear_ratio != 0.0);
  446. int abspos = static_cast<int> ((double)position*(double)this->cpr*this->gear_ratio);
  447. return abspos;
  448. }
  449. // Currently this alternates between reading the pedal position and reading the steering position
  450. void MotionMind::FindCurrentPos()
  451. {
  452. long elapsed;
  453. struct timeval curr;
  454. if (!this->pos_request_sent)
  455. {
  456. uint8_t * buffer = new uint8_t[MESSAGE_LENGTH];
  457. makeReadPositionCommand(buffer, this->address);
  458. player_opaque_data_t mData;
  459. mData.data_count = MESSAGE_LENGTH;
  460. mData.data = buffer;
  461. this->MsgWait();
  462. opaque->PutMsg(this->InQueue, PLAYER_MSGTYPE_CMD, PLAYER_OPAQUE_CMD_DATA, reinterpret_cast<void*>(&mData),0,NULL);
  463. GlobalTime->GetTime(&(this->msg_sent));
  464. delete [] buffer;
  465. this->pos_request_sent = true;
  466. GlobalTime->GetTime(&(this->time_sent_pos));
  467. usleep(MM_DATA_WAIT);
  468. }
  469. while (this->pos_request_sent)
  470. {
  471. ProcessMessages();
  472. GlobalTime->GetTime(&curr);
  473. elapsed = (curr.tv_sec - this->time_sent_pos.tv_sec)*1e6 + (curr.tv_usec - this->time_sent_pos.tv_usec);
  474. if ((curr.tv_sec - this->time_sent_pos.tv_sec)*1e6 + (curr.tv_usec - this->time_sent_pos.tv_usec) > MSG_TIMEOUT)
  475. {
  476. printf("%d %ld mm pos request message timeout triggered\n",opaque_id.index,elapsed);
  477. this->pos_request_sent = false;
  478. break;
  479. }
  480. // Ensures that you are reading from the right point in the stream
  481. while( (rx_count > 0) && (rx_buffer[0] != this->address))
  482. {
  483. memmove(rx_buffer, rx_buffer+1, rx_count - 1);
  484. rx_count--;
  485. }
  486. if (rx_count >= 6)
  487. {
  488. assert (rx_buffer[0] == this->address);
  489. int position;
  490. unsigned char* pos = (unsigned char*)&position;
  491. unsigned int checksum = rx_buffer[0];
  492. unsigned char* csum = (unsigned char*)&checksum;
  493. pos[0] = rx_buffer[1];
  494. checksum += rx_buffer[1];
  495. pos[1] = rx_buffer[2];
  496. checksum += rx_buffer[2];
  497. pos[2] = rx_buffer[3];
  498. checksum += rx_buffer[3];
  499. pos[3] = rx_buffer[4];
  500. checksum += rx_buffer[4];
  501. if (csum[0] != rx_buffer[5])
  502. {
  503. // Checksums don't match - not necessarily bad as it can be due to the address header being in the middle of a responce
  504. // to another driver with a different address e.g. the responce is 02 01 xx xx xx xx, the data being sent to device 2
  505. // with the info 01 xx xx xx.
  506. memmove(rx_buffer, rx_buffer+1, rx_count - 1);
  507. rx_count--;
  508. }
  509. else
  510. {
  511. GlobalTime->GetTime(&curr);
  512. float robot_pos = (float)((double)position/(this->gear_ratio*((double)cpr)));
  513. this->pos_data.pos = robot_pos;
  514. rx_count -= 6;
  515. memmove(rx_buffer+6, rx_buffer, rx_count);
  516. this->pos_request_sent = false;
  517. }
  518. }
  519. else
  520. {
  521. // Prevents the CPU from becoming overloaded
  522. usleep(MM_CPU_WAIT);
  523. }
  524. }
  525. GlobalTime->GetTime(&curr);
  526. elapsed = (curr.tv_sec - this->time_sent_pos.tv_sec)*1e6 + (curr.tv_usec - this->time_sent_pos.tv_usec);
  527. }
  528. void MotionMind::FindCurrentStatus()
  529. {
  530. long elapsed;
  531. struct timeval curr;
  532. if (!this->status_request_sent)
  533. {
  534. // printf("%d MotionMind FindCurrentStatus sending status request\n",opaque_id.index);
  535. uint8_t * buffer = new uint8_t[MESSAGE_LENGTH];
  536. makeReadStatusCommand(buffer, this->address);
  537. player_opaque_data_t mData;
  538. mData.data_count = MESSAGE_LENGTH;
  539. mData.data = buffer;
  540. this->MsgWait();
  541. opaque->PutMsg(this->InQueue, PLAYER_MSGTYPE_CMD, PLAYER_OPAQUE_CMD_DATA, reinterpret_cast<void*>(&mData),0,NULL);
  542. GlobalTime->GetTime(&(this->msg_sent));
  543. delete [] buffer;
  544. this->status_request_sent = true;
  545. GlobalTime->GetTime(&(this->time_sent_status));
  546. usleep(MM_DATA_WAIT);
  547. }
  548. while (this->status_request_sent)
  549. {
  550. ProcessMessages();
  551. GlobalTime->GetTime(&curr);
  552. elapsed = (curr.tv_sec - this->time_sent_status.tv_sec)*1e6 + (curr.tv_usec - this->time_sent_status.tv_usec);
  553. if ((curr.tv_sec - this->time_sent_status.tv_sec)*1e6 + (curr.tv_usec - this->time_sent_status.tv_usec) > MSG_TIMEOUT)
  554. {
  555. printf("%d %ld mm status message request timeout triggered\n",opaque_id.index,elapsed);
  556. this->status_request_sent = false;
  557. break;
  558. }
  559. // Ensures that you are reading from the right point in the stream
  560. while( (rx_count > 0) && (rx_buffer[0] != this->address))
  561. {
  562. memmove(rx_buffer, rx_buffer+1, rx_count - 1);
  563. rx_count--;
  564. }
  565. if (rx_count >= 4)
  566. {
  567. assert (rx_buffer[0] == this->address);
  568. int32_t status = 0;
  569. unsigned char* stat = (unsigned char*)&status;
  570. unsigned int checksum = rx_buffer[0];
  571. unsigned char* csum = (unsigned char*)&checksum;
  572. stat[0] = rx_buffer[1];
  573. checksum += rx_buffer[1];
  574. stat[1] = rx_buffer[2];
  575. checksum += rx_buffer[2];
  576. if (csum[0] != rx_buffer[3])
  577. {
  578. // Checksums don't match - not necessarily bad as it can be due to the address header being in the middle of a responce
  579. // to another driver with a different address e.g. the responce is 02 01 xx xx xx xx, the data being sent to device 2
  580. // with the info 01 xx xx xx.
  581. memmove(rx_buffer, rx_buffer+1, rx_count - 1);
  582. rx_count--;
  583. }
  584. else
  585. {
  586. this->pos_data.status =
  587. (status & MM_STATUS_NEGLIMIT ? 0x01 : 0x00) // NEGLIMIT -> lim min
  588. | (status & MM_STATUS_POSLIMIT ? 0x04 : 0x00) // POSLIMIT -> lim max
  589. | (status & MM_STATUS_CURRENTLIMIT ? 0x08 : 0x00) // CURRENTLIMIT -> over current
  590. | (status & MM_STATUS_INPOSITION ? 0x10 : 0x00) // INPOSITION -> trajectory complete
  591. | (status & MM_STATUS_BRAKE ? 0x00 : 0x20); // BRAKE -> is enabled (inverted)
  592. rx_count -= 4;
  593. memmove(rx_buffer+4, rx_buffer, rx_count);
  594. status_request_sent = false;
  595. }
  596. }
  597. else
  598. {
  599. // Prevents the CPU from becoming overloaded
  600. usleep(MM_CPU_WAIT);
  601. }
  602. }
  603. elapsed = (curr.tv_sec - this->time_sent_status.tv_sec)*1e6 + (curr.tv_usec - this->time_sent_status.tv_usec);
  604. }
  605. int MotionMind::MsgWait()
  606. {
  607. struct timeval curr;
  608. long elapsed;
  609. GlobalTime->GetTime(&curr);
  610. elapsed = (curr.tv_sec - this->msg_sent.tv_sec)*1e6 + (curr.tv_usec - this->msg_sent.tv_usec);
  611. while (elapsed < MM_MSG_WAIT)
  612. {
  613. usleep(MM_MSG_WAIT-elapsed);
  614. GlobalTime->GetTime(&curr);
  615. elapsed = (curr.tv_sec - this->msg_sent.tv_sec)*1e6 + (curr.tv_usec - this->msg_sent.tv_usec);
  616. }
  617. return 0;
  618. }