1 | #include "Arduino.h" |
2 | #include "RoboClaw.h" |
3 |
|
4 | #define MAXRETRY 2 |
5 | #define SetDWORDval(arg) (uint8_t)(((uint32_t)arg)>>24),(uint8_t)(((uint32_t)arg)>>16),(uint8_t)(((uint32_t)arg)>>8),(uint8_t)arg |
6 | #define SetWORDval(arg) (uint8_t)(((uint16_t)arg)>>8),(uint8_t)arg |
7 |
|
8 | // |
9 | // Constructor |
10 | // |
11 | RoboClaw::RoboClaw(HardwareSerial *serial, uint32_t tout) |
12 | { |
13 | timeout = tout; |
14 | hserial = serial; |
15 | #ifdef __AVR__ |
16 | sserial = 0; |
17 | #endif |
18 | } |
19 |
|
20 | #ifdef __AVR__ |
21 | RoboClaw::RoboClaw(SoftwareSerial *serial, uint32_t tout) |
22 | { |
23 | timeout = tout; |
24 | sserial = serial; |
25 | hserial = 0; |
26 | } |
27 | #endif |
28 |
|
29 | // |
30 | // Destructor |
31 | // |
32 | RoboClaw::~RoboClaw() |
33 | { |
34 | } |
35 |
|
36 | void RoboClaw::begin(long speed) |
37 | { |
38 | if(hserial){ |
39 | hserial->begin(speed); |
40 | } |
41 | #ifdef __AVR__ |
42 | else{ |
43 | sserial->begin(speed); |
44 | } |
45 | #endif |
46 | } |
47 |
|
48 | bool RoboClaw::listen() |
49 | { |
50 | #ifdef __AVR__ |
51 | if(sserial){ |
52 | return sserial->listen(); |
53 | } |
54 | #endif |
55 | return false; |
56 | } |
57 |
|
58 | bool RoboClaw::isListening() |
59 | { |
60 | #ifdef __AVR__ |
61 | if(sserial) |
62 | return sserial->isListening(); |
63 | #endif |
64 | return false; |
65 | } |
66 |
|
67 | bool RoboClaw::overflow() |
68 | { |
69 | #ifdef __AVR__ |
70 | if(sserial) |
71 | return sserial->overflow(); |
72 | #endif |
73 | return false; |
74 | } |
75 |
|
76 | int RoboClaw::peek() |
77 | { |
78 | if(hserial) |
79 | return hserial->peek(); |
80 | #ifdef __AVR__ |
81 | else |
82 | return sserial->peek(); |
83 | #endif |
84 | } |
85 |
|
86 | size_t RoboClaw::write(uint8_t byte) |
87 | { |
88 | if(hserial) |
89 | return hserial->write(byte); |
90 | #ifdef __AVR__ |
91 | else |
92 | return sserial->write(byte); |
93 | #endif |
94 | } |
95 |
|
96 | int RoboClaw::read() |
97 | { |
98 | if(hserial) |
99 | return hserial->read(); |
100 | #ifdef __AVR__ |
101 | else |
102 | return sserial->read(); |
103 | #endif |
104 | } |
105 |
|
106 | int RoboClaw::available() |
107 | { |
108 | if(hserial) |
109 | return hserial->available(); |
110 | #ifdef __AVR__ |
111 | else |
112 | return sserial->available(); |
113 | #endif |
114 | } |
115 |
|
116 | void RoboClaw::flush() |
117 | { |
118 | if(hserial) |
119 | hserial->flush(); |
120 | } |
121 |
|
122 | int RoboClaw::read(uint32_t timeout) |
123 | { |
124 | if(hserial){ |
125 | uint32_t start = micros(); |
126 | // Empty buffer? |
127 | while(!hserial->available()){ |
128 | if((micros()-start)>=timeout) |
129 | return -1; |
130 | } |
131 | return hserial->read(); |
132 | } |
133 | #ifdef __AVR__ |
134 | else{ |
135 | if(sserial->isListening()){ |
136 | uint32_t start = micros(); |
137 | // Empty buffer? |
138 | while(!sserial->available()){ |
139 | if((micros()-start)>=timeout) |
140 | return -1; |
141 | } |
142 | return sserial->read(); |
143 | } |
144 | } |
145 | #endif |
146 | } |
147 |
|
148 | void RoboClaw::clear() |
149 | { |
150 | if(hserial){ |
151 | while(hserial->available()) |
152 | hserial->read(); |
153 | } |
154 | #ifdef __AVR__ |
155 | else{ |
156 | while(sserial->available()) |
157 | sserial->read(); |
158 | } |
159 | #endif |
160 | } |
161 |
|
162 | void RoboClaw::crc_clear() |
163 | { |
164 | crc = 0; |
165 | } |
166 |
|
167 | void RoboClaw::crc_update (uint8_t data) |
168 | { |
169 | int i; |
170 | crc = crc ^ ((uint16_t)data << 8); |
171 | for (i=0; i<8; i++) |
172 | { |
173 | if (crc & 0x8000) |
174 | crc = (crc << 1) ^ 0x1021; |
175 | else |
176 | crc <<= 1; |
177 | } |
178 | } |
179 |
|
180 | uint16_t RoboClaw::crc_get() |
181 | { |
182 | return crc; |
183 | } |
184 |
|
185 | bool RoboClaw::write_n(uint8_t cnt, ... ) |
186 | { |
187 | uint8_t trys=MAXRETRY; |
188 | do{ |
189 | crc_clear(); |
190 | //send data with crc |
191 | va_list marker; |
192 | va_start( marker, cnt ); /* Initialize variable arguments. */ |
193 | for(uint8_t index=0;index<cnt;index++){ |
194 | uint8_t data = va_arg(marker, int); |
195 | crc_update(data); |
196 | write(data); |
197 | } |
198 | va_end( marker ); /* Reset variable arguments. */ |
199 | uint16_t crc = crc_get(); |
200 | write(crc>>8); |
201 | write(crc); |
202 | if(read(timeout)==0xFF) |
203 | return true; |
204 | }while(trys--); |
205 | return false; |
206 | } |
207 |
|
208 | bool RoboClaw::read_n(uint8_t cnt,uint8_t address,uint8_t cmd,...) |
209 | { |
210 | uint32_t value=0; |
211 | uint8_t trys=MAXRETRY; |
212 | int16_t data; |
213 | do{ |
214 | flush(); |
215 | |
216 | data=0; |
217 | crc_clear(); |
218 | write(address); |
219 | crc_update(address); |
220 | write(cmd); |
221 | crc_update(cmd); |
222 |
|
223 | //send data with crc |
224 | va_list marker; |
225 | va_start( marker, cmd ); /* Initialize variable arguments. */ |
226 | for(uint8_t index=0;index<cnt;index++){ |
227 | uint32_t *ptr = va_arg(marker, uint32_t *); |
228 |
|
229 | if(data!=-1){ |
230 | data = read(timeout); |
231 | crc_update(data); |
232 | value=(uint32_t)data<<24; |
233 | } |
234 | else{ |
235 | break; |
236 | } |
237 | |
238 | if(data!=-1){ |
239 | data = read(timeout); |
240 | crc_update(data); |
241 | value|=(uint32_t)data<<16; |
242 | } |
243 | else{ |
244 | break; |
245 | } |
246 |
|
247 | if(data!=-1){ |
248 | data = read(timeout); |
249 | crc_update(data); |
250 | value|=(uint32_t)data<<8; |
251 | } |
252 | else{ |
253 | break; |
254 | } |
255 |
|
256 | if(data!=-1){ |
257 | data = read(timeout); |
258 | crc_update(data); |
259 | value|=(uint32_t)data; |
260 | } |
261 | else{ |
262 | break; |
263 | } |
264 |
|
265 | *ptr = value; |
266 | } |
267 | va_end( marker ); /* Reset variable arguments. */ |
268 |
|
269 | if(data!=-1){ |
270 | uint16_t ccrc; |
271 | data = read(timeout); |
272 | if(data!=-1){ |
273 | ccrc = data << 8; |
274 | data = read(timeout); |
275 | if(data!=-1){ |
276 | ccrc |= data; |
277 | return crc_get()==ccrc; |
278 | } |
279 | } |
280 | } |
281 | }while(trys--); |
282 |
|
283 | return false; |
284 | } |
285 |
|
286 | uint8_t RoboClaw::Read1(uint8_t address,uint8_t cmd,bool *valid){ |
287 | uint8_t crc; |
288 |
|
289 | if(valid) |
290 | *valid = false; |
291 | |
292 | uint8_t value=0; |
293 | uint8_t trys=MAXRETRY; |
294 | int16_t data; |
295 | do{ |
296 | flush(); |
297 |
|
298 | crc_clear(); |
299 | write(address); |
300 | crc_update(address); |
301 | write(cmd); |
302 | crc_update(cmd); |
303 | |
304 | data = read(timeout); |
305 | crc_update(data); |
306 | value=data; |
307 |
|
308 | if(data!=-1){ |
309 | uint16_t ccrc; |
310 | data = read(timeout); |
311 | if(data!=-1){ |
312 | ccrc = data << 8; |
313 | data = read(timeout); |
314 | if(data!=-1){ |
315 | ccrc |= data; |
316 | if(crc_get()==ccrc){ |
317 | *valid = true; |
318 | return value; |
319 | } |
320 | } |
321 | } |
322 | } |
323 | }while(trys--); |
324 | |
325 | return false; |
326 | } |
327 |
|
328 | uint16_t RoboClaw::Read2(uint8_t address,uint8_t cmd,bool *valid){ |
329 | uint8_t crc; |
330 |
|
331 | if(valid) |
332 | *valid = false; |
333 | |
334 | uint16_t value=0; |
335 | uint8_t trys=MAXRETRY; |
336 | int16_t data; |
337 | do{ |
338 | flush(); |
339 |
|
340 | crc_clear(); |
341 | write(address); |
342 | crc_update(address); |
343 | write(cmd); |
344 | crc_update(cmd); |
345 | |
346 | data = read(timeout); |
347 | crc_update(data); |
348 | value=(uint16_t)data<<8; |
349 | |
350 | if(data!=-1){ |
351 | data = read(timeout); |
352 | crc_update(data); |
353 | value|=(uint16_t)data; |
354 | } |
355 | |
356 | if(data!=-1){ |
357 | uint16_t ccrc; |
358 | data = read(timeout); |
359 | if(data!=-1){ |
360 | ccrc = data << 8; |
361 | data = read(timeout); |
362 | if(data!=-1){ |
363 | ccrc |= data; |
364 | if(crc_get()==ccrc){ |
365 | *valid = true; |
366 | return value; |
367 | } |
368 | } |
369 | } |
370 | } |
371 | }while(trys--); |
372 | |
373 | return false; |
374 | } |
375 |
|
376 | uint32_t RoboClaw::Read4(uint8_t address, uint8_t cmd, bool *valid){ |
377 | uint8_t crc; |
378 | |
379 | if(valid) |
380 | *valid = false; |
381 | |
382 | uint32_t value=0; |
383 | uint8_t trys=MAXRETRY; |
384 | int16_t data; |
385 | do{ |
386 | flush(); |
387 |
|
388 | crc_clear(); |
389 | write(address); |
390 | crc_update(address); |
391 | write(cmd); |
392 | crc_update(cmd); |
393 |
|
394 | data = read(timeout); |
395 | crc_update(data); |
396 | value=(uint32_t)data<<24; |
397 |
|
398 | if(data!=-1){ |
399 | data = read(timeout); |
400 | crc_update(data); |
401 | value|=(uint32_t)data<<16; |
402 | } |
403 | |
404 | if(data!=-1){ |
405 | data = read(timeout); |
406 | crc_update(data); |
407 | value|=(uint32_t)data<<8; |
408 | } |
409 |
|
410 | if(data!=-1){ |
411 | data = read(timeout); |
412 | crc_update(data); |
413 | value|=(uint32_t)data; |
414 | } |
415 | |
416 | if(data!=-1){ |
417 | uint16_t ccrc; |
418 | data = read(timeout); |
419 | if(data!=-1){ |
420 | ccrc = data << 8; |
421 | data = read(timeout); |
422 | if(data!=-1){ |
423 | ccrc |= data; |
424 | if(crc_get()==ccrc){ |
425 | *valid = true; |
426 | return value; |
427 | } |
428 | } |
429 | } |
430 | } |
431 | }while(trys--); |
432 | |
433 | return false; |
434 | } |
435 |
|
436 | uint32_t RoboClaw::Read4_1(uint8_t address, uint8_t cmd, uint8_t *status, bool *valid){ |
437 | uint8_t crc; |
438 |
|
439 | if(valid) |
440 | *valid = false; |
441 | |
442 | uint32_t value=0; |
443 | uint8_t trys=MAXRETRY; |
444 | int16_t data; |
445 | do{ |
446 | flush(); |
447 |
|
448 | crc_clear(); |
449 | write(address); |
450 | crc_update(address); |
451 | write(cmd); |
452 | crc_update(cmd); |
453 |
|
454 | data = read(timeout); |
455 | crc_update(data); |
456 | value=(uint32_t)data<<24; |
457 |
|
458 | if(data!=-1){ |
459 | data = read(timeout); |
460 | crc_update(data); |
461 | value|=(uint32_t)data<<16; |
462 | } |
463 |
|
464 | if(data!=-1){ |
465 | data = read(timeout); |
466 | crc_update(data); |
467 | value|=(uint32_t)data<<8; |
468 | } |
469 |
|
470 | if(data!=-1){ |
471 | data = read(timeout); |
472 | crc_update(data); |
473 | value|=(uint32_t)data; |
474 | } |
475 | |
476 | if(data!=-1){ |
477 | data = read(timeout); |
478 | crc_update(data); |
479 | if(status) |
480 | *status = data; |
481 | } |
482 | |
483 | if(data!=-1){ |
484 | uint16_t ccrc; |
485 | data = read(timeout); |
486 | if(data!=-1){ |
487 | ccrc = data << 8; |
488 | data = read(timeout); |
489 | if(data!=-1){ |
490 | ccrc |= data; |
491 | if(crc_get()==ccrc){ |
492 | *valid = true; |
493 | return value; |
494 | } |
495 | } |
496 | } |
497 | } |
498 | }while(trys--); |
499 |
|
500 | return false; |
501 | } |
502 |
|
503 | bool RoboClaw::ForwardM1(uint8_t address, uint8_t speed){ |
504 | return write_n(3,address,M1FORWARD,speed); |
505 | } |
506 |
|
507 | bool RoboClaw::BackwardM1(uint8_t address, uint8_t speed){ |
508 | return write_n(3,address,M1BACKWARD,speed); |
509 | } |
510 |
|
511 | bool RoboClaw::SetMinVoltageMainBattery(uint8_t address, uint8_t voltage){ |
512 | return write_n(3,address,SETMINMB,voltage); |
513 | } |
514 |
|
515 | bool RoboClaw::SetMaxVoltageMainBattery(uint8_t address, uint8_t voltage){ |
516 | return write_n(3,address,SETMAXMB,voltage); |
517 | } |
518 |
|
519 | bool RoboClaw::ForwardM2(uint8_t address, uint8_t speed){ |
520 | return write_n(3,address,M2FORWARD,speed); |
521 | } |
522 |
|
523 | bool RoboClaw::BackwardM2(uint8_t address, uint8_t speed){ |
524 | return write_n(3,address,M2BACKWARD,speed); |
525 | } |
526 |
|
527 | bool RoboClaw::ForwardBackwardM1(uint8_t address, uint8_t speed){ |
528 | return write_n(3,address,M17BIT,speed); |
529 | } |
530 |
|
531 | bool RoboClaw::ForwardBackwardM2(uint8_t address, uint8_t speed){ |
532 | return write_n(3,address,M27BIT,speed); |
533 | } |
534 |
|
535 | bool RoboClaw::ForwardMixed(uint8_t address, uint8_t speed){ |
536 | return write_n(3,address,MIXEDFORWARD,speed); |
537 | } |
538 |
|
539 | bool RoboClaw::BackwardMixed(uint8_t address, uint8_t speed){ |
540 | return write_n(3,address,MIXEDBACKWARD,speed); |
541 | } |
542 |
|
543 | bool RoboClaw::TurnRightMixed(uint8_t address, uint8_t speed){ |
544 | return write_n(3,address,MIXEDRIGHT,speed); |
545 | } |
546 |
|
547 | bool RoboClaw::TurnLeftMixed(uint8_t address, uint8_t speed){ |
548 | return write_n(3,address,MIXEDLEFT,speed); |
549 | } |
550 |
|
551 | bool RoboClaw::ForwardBackwardMixed(uint8_t address, uint8_t speed){ |
552 | return write_n(3,address,MIXEDFB,speed); |
553 | } |
554 |
|
555 | bool RoboClaw::LeftRightMixed(uint8_t address, uint8_t speed){ |
556 | return write_n(3,address,MIXEDLR,speed); |
557 | } |
558 |
|
559 | uint32_t RoboClaw::ReadEncM1(uint8_t address, uint8_t *status,bool *valid){ |
560 | return Read4_1(address,GETM1ENC,status,valid); |
561 | } |
562 |
|
563 | uint32_t RoboClaw::ReadEncM2(uint8_t address, uint8_t *status,bool *valid){ |
564 | return Read4_1(address,GETM2ENC,status,valid); |
565 | } |
566 |
|
567 | uint32_t RoboClaw::ReadSpeedM1(uint8_t address, uint8_t *status,bool *valid){ |
568 | return Read4_1(address,GETM1SPEED,status,valid); |
569 | } |
570 |
|
571 | uint32_t RoboClaw::ReadSpeedM2(uint8_t address, uint8_t *status,bool *valid){ |
572 | return Read4_1(address,GETM2SPEED,status,valid); |
573 | } |
574 |
|
575 | bool RoboClaw::ResetEncoders(uint8_t address){ |
576 | return write_n(2,address,RESETENC); |
577 | } |
578 |
|
579 | bool RoboClaw::ReadVersion(uint8_t address,char *version){ |
580 | uint8_t data; |
581 | uint8_t trys=MAXRETRY; |
582 | do{ |
583 | flush(); |
584 |
|
585 | data = 0; |
586 | |
587 | crc_clear(); |
588 | write(address); |
589 | crc_update(address); |
590 | write(GETVERSION); |
591 | crc_update(GETVERSION); |
592 | |
593 | uint8_t i; |
594 | for(i=0;i<48;i++){ |
595 | if(data!=-1){ |
596 | data=read(timeout); |
597 | version[i] = data; |
598 | crc_update(version[i]); |
599 | if(version[i]==0){ |
600 | uint16_t ccrc; |
601 | data = read(timeout); |
602 | if(data!=-1){ |
603 | ccrc = data << 8; |
604 | data = read(timeout); |
605 | if(data!=-1){ |
606 | ccrc |= data; |
607 | return crc_get()==ccrc; |
608 | } |
609 | } |
610 | break; |
611 | } |
612 | } |
613 | else{ |
614 | break; |
615 | } |
616 | } |
617 | }while(trys--); |
618 | |
619 | return false; |
620 | } |
621 |
|
622 | bool RoboClaw::SetEncM1(uint8_t address, int32_t val){ |
623 | return write_n(6,address,SETM1ENCCOUNT,SetDWORDval(val)); |
624 | } |
625 |
|
626 | bool RoboClaw::SetEncM2(uint8_t address, int32_t val){ |
627 | return write_n(6,address,SETM2ENCCOUNT,SetDWORDval(val)); |
628 | } |
629 |
|
630 | uint16_t RoboClaw::ReadMainBatteryVoltage(uint8_t address,bool *valid){ |
631 | return Read2(address,GETMBATT,valid); |
632 | } |
633 |
|
634 | uint16_t RoboClaw::ReadLogicBatteryVoltage(uint8_t address,bool *valid){ |
635 | return Read2(address,GETLBATT,valid); |
636 | } |
637 |
|
638 | bool RoboClaw::SetMinVoltageLogicBattery(uint8_t address, uint8_t voltage){ |
639 | return write_n(3,address,SETMINLB,voltage); |
640 | } |
641 |
|
642 | bool RoboClaw::SetMaxVoltageLogicBattery(uint8_t address, uint8_t voltage){ |
643 | return write_n(3,address,SETMAXLB,voltage); |
644 | } |
645 |
|
646 | bool RoboClaw::SetM1VelocityPID(uint8_t address, float kp_fp, float ki_fp, float kd_fp, uint32_t qpps){ |
647 | uint32_t kp = kp_fp*65536; |
648 | uint32_t ki = ki_fp*65536; |
649 | uint32_t kd = kd_fp*65536; |
650 | return write_n(18,address,SETM1PID,SetDWORDval(kd),SetDWORDval(kp),SetDWORDval(ki),SetDWORDval(qpps)); |
651 | } |
652 |
|
653 | bool RoboClaw::SetM2VelocityPID(uint8_t address, float kp_fp, float ki_fp, float kd_fp, uint32_t qpps){ |
654 | uint32_t kp = kp_fp*65536; |
655 | uint32_t ki = ki_fp*65536; |
656 | uint32_t kd = kd_fp*65536; |
657 | return write_n(18,address,SETM2PID,SetDWORDval(kd),SetDWORDval(kp),SetDWORDval(ki),SetDWORDval(qpps)); |
658 | } |
659 |
|
660 | uint32_t RoboClaw::ReadISpeedM1(uint8_t address,uint8_t *status,bool *valid){ |
661 | return Read4_1(address,GETM1ISPEED,status,valid); |
662 | } |
663 |
|
664 | uint32_t RoboClaw::ReadISpeedM2(uint8_t address,uint8_t *status,bool *valid){ |
665 | return Read4_1(address,GETM2ISPEED,status,valid); |
666 | } |
667 |
|
668 | bool RoboClaw::DutyM1(uint8_t address, uint16_t duty){ |
669 | return write_n(4,address,M1DUTY,SetWORDval(duty)); |
670 | } |
671 |
|
672 | bool RoboClaw::DutyM2(uint8_t address, uint16_t duty){ |
673 | return write_n(4,address,M2DUTY,SetWORDval(duty)); |
674 | } |
675 |
|
676 | bool RoboClaw::DutyM1M2(uint8_t address, uint16_t duty1, uint16_t duty2){ |
677 | return write_n(6,address,MIXEDDUTY,SetWORDval(duty1),SetWORDval(duty2)); |
678 | } |
679 |
|
680 | bool RoboClaw::SpeedM1(uint8_t address, uint32_t speed){ |
681 | return write_n(6,address,M1SPEED,SetDWORDval(speed)); |
682 | } |
683 |
|
684 | bool RoboClaw::SpeedM2(uint8_t address, uint32_t speed){ |
685 | return write_n(6,address,M2SPEED,SetDWORDval(speed)); |
686 | } |
687 |
|
688 | bool RoboClaw::SpeedM1M2(uint8_t address, uint32_t speed1, uint32_t speed2){ |
689 | return write_n(10,address,MIXEDSPEED,SetDWORDval(speed1),SetDWORDval(speed2)); |
690 | } |
691 |
|
692 | bool RoboClaw::SpeedAccelM1(uint8_t address, uint32_t accel, uint32_t speed){ |
693 | return write_n(10,address,M1SPEEDACCEL,SetDWORDval(accel),SetDWORDval(speed)); |
694 | } |
695 |
|
696 | bool RoboClaw::SpeedAccelM2(uint8_t address, uint32_t accel, uint32_t speed){ |
697 | return write_n(10,address,M2SPEEDACCEL,SetDWORDval(accel),SetDWORDval(speed)); |
698 | } |
699 | bool RoboClaw::SpeedAccelM1M2(uint8_t address, uint32_t accel, uint32_t speed1, uint32_t speed2){ |
700 | return write_n(14,address,MIXEDSPEEDACCEL,SetDWORDval(accel),SetDWORDval(speed1),SetDWORDval(speed2)); |
701 | } |
702 |
|
703 | bool RoboClaw::SpeedDistanceM1(uint8_t address, uint32_t speed, uint32_t distance, uint8_t flag){ |
704 | return write_n(11,address,M1SPEEDDIST,SetDWORDval(speed),SetDWORDval(distance),flag); |
705 | } |
706 |
|
707 | bool RoboClaw::SpeedDistanceM2(uint8_t address, uint32_t speed, uint32_t distance, uint8_t flag){ |
708 | return write_n(11,address,M2SPEEDDIST,SetDWORDval(speed),SetDWORDval(distance),flag); |
709 | } |
710 |
|
711 | bool RoboClaw::SpeedDistanceM1M2(uint8_t address, uint32_t speed1, uint32_t distance1, uint32_t speed2, uint32_t distance2, uint8_t flag){ |
712 | return write_n(19,address,MIXEDSPEEDDIST,SetDWORDval(speed1),SetDWORDval(distance1),SetDWORDval(speed2),SetDWORDval(distance2),flag); |
713 | } |
714 |
|
715 | bool RoboClaw::SpeedAccelDistanceM1(uint8_t address, uint32_t accel, uint32_t speed, uint32_t distance, uint8_t flag){ |
716 | return write_n(15,address,M1SPEEDACCELDIST,SetDWORDval(accel),SetDWORDval(speed),SetDWORDval(distance),flag); |
717 | } |
718 |
|
719 | bool RoboClaw::SpeedAccelDistanceM2(uint8_t address, uint32_t accel, uint32_t speed, uint32_t distance, uint8_t flag){ |
720 | return write_n(15,address,M2SPEEDACCELDIST,SetDWORDval(accel),SetDWORDval(speed),SetDWORDval(distance),flag); |
721 | } |
722 |
|
723 | bool RoboClaw::SpeedAccelDistanceM1M2(uint8_t address, uint32_t accel, uint32_t speed1, uint32_t distance1, uint32_t speed2, uint32_t distance2, uint8_t flag){ |
724 | return write_n(23,address,MIXEDSPEEDACCELDIST,SetDWORDval(accel),SetDWORDval(speed1),SetDWORDval(distance1),SetDWORDval(speed2),SetDWORDval(distance2),flag); |
725 | } |
726 |
|
727 | bool RoboClaw::ReadBuffers(uint8_t address, uint8_t &depth1, uint8_t &depth2){ |
728 | bool valid; |
729 | uint16_t value = Read2(address,GETBUFFERS,&valid); |
730 | if(valid){ |
731 | depth1 = value>>8; |
732 | depth2 = value; |
733 | } |
734 | return valid; |
735 | } |
736 |
|
737 | bool RoboClaw::ReadPWMs(uint8_t address, int16_t &pwm1, int16_t &pwm2){ |
738 | bool valid; |
739 | uint32_t value = Read4(address,GETPWMS,&valid); |
740 | if(valid){ |
741 | pwm1 = value>>16; |
742 | pwm2 = value&0xFFFF; |
743 | } |
744 | return valid; |
745 | } |
746 |
|
747 | bool RoboClaw::ReadCurrents(uint8_t address, int16_t ¤t1, int16_t ¤t2){ |
748 | bool valid; |
749 | uint32_t value = Read4(address,GETCURRENTS,&valid); |
750 | if(valid){ |
751 | current1 = value>>16; |
752 | current2 = value&0xFFFF; |
753 | } |
754 | return valid; |
755 | } |
756 |
|
757 | bool RoboClaw::SpeedAccelM1M2_2(uint8_t address, uint32_t accel1, uint32_t speed1, uint32_t accel2, uint32_t speed2){ |
758 | return write_n(18,address,MIXEDSPEED2ACCEL,SetDWORDval(accel1),SetDWORDval(speed1),SetDWORDval(accel2),SetDWORDval(speed2)); |
759 | } |
760 |
|
761 | bool RoboClaw::SpeedAccelDistanceM1M2_2(uint8_t address, uint32_t accel1, uint32_t speed1, uint32_t distance1, uint32_t accel2, uint32_t speed2, uint32_t distance2, uint8_t flag){ |
762 | return write_n(27,address,MIXEDSPEED2ACCELDIST,SetDWORDval(accel1),SetDWORDval(speed1),SetDWORDval(distance1),SetDWORDval(accel2),SetDWORDval(speed2),SetDWORDval(distance2),flag); |
763 | } |
764 |
|
765 | bool RoboClaw::DutyAccelM1(uint8_t address, uint16_t duty, uint32_t accel){ |
766 | return write_n(8,address,M1DUTYACCEL,SetWORDval(duty),SetDWORDval(accel)); |
767 | } |
768 |
|
769 | bool RoboClaw::DutyAccelM2(uint8_t address, uint16_t duty, uint32_t accel){ |
770 | return write_n(8,address,M2DUTYACCEL,SetWORDval(duty),SetDWORDval(accel)); |
771 | } |
772 |
|
773 | bool RoboClaw::DutyAccelM1M2(uint8_t address, uint16_t duty1, uint32_t accel1, uint16_t duty2, uint32_t accel2){ |
774 | return write_n(14,address,MIXEDDUTYACCEL,SetWORDval(duty1),SetDWORDval(accel1),SetWORDval(duty2),SetDWORDval(accel2)); |
775 | } |
776 |
|
777 | bool RoboClaw::ReadM1VelocityPID(uint8_t address,float &Kp_fp,float &Ki_fp,float &Kd_fp,uint32_t &qpps){ |
778 | uint32_t Kp,Ki,Kd; |
779 | bool valid = read_n(4,address,READM1PID,&Kp,&Ki,&Kd,&qpps); |
780 | Kp_fp = ((float)Kp)/65536; |
781 | Ki_fp = ((float)Ki)/65536; |
782 | Kd_fp = ((float)Kd)/65536; |
783 | return valid; |
784 | } |
785 |
|
786 | bool RoboClaw::ReadM2VelocityPID(uint8_t address,float &Kp_fp,float &Ki_fp,float &Kd_fp,uint32_t &qpps){ |
787 | uint32_t Kp,Ki,Kd; |
788 | bool valid = read_n(4,address,READM2PID,&Kp,&Ki,&Kd,&qpps); |
789 | Kp_fp = ((float)Kp)/65536; |
790 | Ki_fp = ((float)Ki)/65536; |
791 | Kd_fp = ((float)Kd)/65536; |
792 | return valid; |
793 | } |
794 |
|
795 | bool RoboClaw::SetMainVoltages(uint8_t address,uint16_t min,uint16_t max){ |
796 | return write_n(6,address,SETMAINVOLTAGES,SetWORDval(min),SetWORDval(max)); |
797 | } |
798 |
|
799 | bool RoboClaw::SetLogicVoltages(uint8_t address,uint16_t min,uint16_t max){ |
800 | return write_n(6,address,SETLOGICVOLTAGES,SetWORDval(min),SetWORDval(max)); |
801 | } |
802 |
|
803 | bool RoboClaw::ReadMinMaxMainVoltages(uint8_t address,uint16_t &min,uint16_t &max){ |
804 | bool valid; |
805 | uint32_t value = Read4(address,GETMINMAXMAINVOLTAGES,&valid); |
806 | if(valid){ |
807 | min = value>>16; |
808 | max = value&0xFFFF; |
809 | } |
810 | return valid; |
811 | } |
812 | |
813 | bool RoboClaw::ReadMinMaxLogicVoltages(uint8_t address,uint16_t &min,uint16_t &max){ |
814 | bool valid; |
815 | uint32_t value = Read4(address,GETMINMAXLOGICVOLTAGES,&valid); |
816 | if(valid){ |
817 | min = value>>16; |
818 | max = value&0xFFFF; |
819 | } |
820 | return valid; |
821 | } |
822 |
|
823 | bool RoboClaw::SetM1PositionPID(uint8_t address,float kp_fp,float ki_fp,float kd_fp,uint32_t kiMax,uint32_t deadzone,uint32_t min,uint32_t max){ |
824 | uint32_t kp=kp_fp*1024; |
825 | uint32_t ki=ki_fp*1024; |
826 | uint32_t kd=kd_fp*1024; |
827 | return write_n(30,address,SETM1POSPID,SetDWORDval(kd),SetDWORDval(kp),SetDWORDval(ki),SetDWORDval(kiMax),SetDWORDval(deadzone),SetDWORDval(min),SetDWORDval(max)); |
828 | } |
829 |
|
830 | bool RoboClaw::SetM2PositionPID(uint8_t address,float kp_fp,float ki_fp,float kd_fp,uint32_t kiMax,uint32_t deadzone,uint32_t min,uint32_t max){ |
831 | uint32_t kp=kp_fp*1024; |
832 | uint32_t ki=ki_fp*1024; |
833 | uint32_t kd=kd_fp*1024; |
834 | return write_n(30,address,SETM2POSPID,SetDWORDval(kd),SetDWORDval(kp),SetDWORDval(ki),SetDWORDval(kiMax),SetDWORDval(deadzone),SetDWORDval(min),SetDWORDval(max)); |
835 | } |
836 |
|
837 | bool RoboClaw::ReadM1PositionPID(uint8_t address,float &Kp_fp,float &Ki_fp,float &Kd_fp,uint32_t &KiMax,uint32_t &DeadZone,uint32_t &Min,uint32_t &Max){ |
838 | uint32_t Kp,Ki,Kd; |
839 | bool valid = read_n(7,address,READM1POSPID,&Kp,&Ki,&Kd,&KiMax,&DeadZone,&Min,&Max); |
840 | Kp_fp = ((float)Kp)/1024; |
841 | Ki_fp = ((float)Ki)/1024; |
842 | Kd_fp = ((float)Kd)/1024; |
843 | return valid; |
844 | } |
845 |
|
846 | bool RoboClaw::ReadM2PositionPID(uint8_t address,float &Kp_fp,float &Ki_fp,float &Kd_fp,uint32_t &KiMax,uint32_t &DeadZone,uint32_t &Min,uint32_t &Max){ |
847 | uint32_t Kp,Ki,Kd; |
848 | bool valid = read_n(7,address,READM2POSPID,&Kp,&Ki,&Kd,&KiMax,&DeadZone,&Min,&Max); |
849 | Kp_fp = ((float)Kp)/1024; |
850 | Ki_fp = ((float)Ki)/1024; |
851 | Kd_fp = ((float)Kd)/1024; |
852 | return valid; |
853 | } |
854 |
|
855 | bool RoboClaw::SpeedAccelDeccelPositionM1(uint8_t address,uint32_t accel,uint32_t speed,uint32_t deccel,uint32_t position,uint8_t flag){ |
856 | return write_n(19,address,M1SPEEDACCELDECCELPOS,SetDWORDval(accel),SetDWORDval(speed),SetDWORDval(deccel),SetDWORDval(position),flag); |
857 | } |
858 |
|
859 | bool RoboClaw::SpeedAccelDeccelPositionM2(uint8_t address,uint32_t accel,uint32_t speed,uint32_t deccel,uint32_t position,uint8_t flag){ |
860 | return write_n(19,address,M2SPEEDACCELDECCELPOS,SetDWORDval(accel),SetDWORDval(speed),SetDWORDval(deccel),SetDWORDval(position),flag); |
861 | } |
862 |
|
863 | bool RoboClaw::SpeedAccelDeccelPositionM1M2(uint8_t address,uint32_t accel1,uint32_t speed1,uint32_t deccel1,uint32_t position1,uint32_t accel2,uint32_t speed2,uint32_t deccel2,uint32_t position2,uint8_t flag){ |
864 | return write_n(35,address,MIXEDSPEEDACCELDECCELPOS,SetDWORDval(accel1),SetDWORDval(speed1),SetDWORDval(deccel1),SetDWORDval(position1),SetDWORDval(accel2),SetDWORDval(speed2),SetDWORDval(deccel2),SetDWORDval(position2),flag); |
865 | } |
866 |
|
867 | bool RoboClaw::SetM1DefaultAccel(uint8_t address, uint32_t accel){ |
868 | return write_n(6,address,SETM1DEFAULTACCEL,SetDWORDval(accel)); |
869 | } |
870 |
|
871 | bool RoboClaw::SetM2DefaultAccel(uint8_t address, uint32_t accel){ |
872 | return write_n(6,address,SETM2DEFAULTACCEL,SetDWORDval(accel)); |
873 | } |
874 |
|
875 | bool RoboClaw::SetPinFunctions(uint8_t address, uint8_t S3mode, uint8_t S4mode, uint8_t S5mode){ |
876 | return write_n(5,address,SETPINFUNCTIONS,S3mode,S4mode,S5mode); |
877 | } |
878 |
|
879 | bool RoboClaw::GetPinFunctions(uint8_t address, uint8_t &S3mode, uint8_t &S4mode, uint8_t &S5mode){ |
880 | uint8_t crc; |
881 | bool valid = false; |
882 | uint8_t val1,val2,val3; |
883 | uint8_t trys=MAXRETRY; |
884 | int16_t data; |
885 | do{ |
886 | flush(); |
887 |
|
888 | crc_clear(); |
889 | write(address); |
890 | crc_update(address); |
891 | write(GETPINFUNCTIONS); |
892 | crc_update(GETPINFUNCTIONS); |
893 | |
894 | data = read(timeout); |
895 | crc_update(data); |
896 | val1=data; |
897 |
|
898 | if(data!=-1){ |
899 | data = read(timeout); |
900 | crc_update(data); |
901 | val2=data; |
902 | } |
903 | |
904 | if(data!=-1){ |
905 | data = read(timeout); |
906 | crc_update(data); |
907 | val3=data; |
908 | } |
909 | |
910 | if(data!=-1){ |
911 | uint16_t ccrc; |
912 | data = read(timeout); |
913 | if(data!=-1){ |
914 | ccrc = data << 8; |
915 | data = read(timeout); |
916 | if(data!=-1){ |
917 | ccrc |= data; |
918 | if(crc_get()==ccrc){ |
919 | S3mode = val1; |
920 | S4mode = val2; |
921 | S5mode = val3; |
922 | return true; |
923 | } |
924 | } |
925 | } |
926 | } |
927 | }while(trys--); |
928 | |
929 | return false; |
930 | } |
931 |
|
932 | bool RoboClaw::SetDeadBand(uint8_t address, uint8_t Min, uint8_t Max){ |
933 | return write_n(4,address,SETDEADBAND,Min,Max); |
934 | } |
935 |
|
936 | bool RoboClaw::GetDeadBand(uint8_t address, uint8_t &Min, uint8_t &Max){ |
937 | bool valid; |
938 | uint16_t value = Read2(address,GETDEADBAND,&valid); |
939 | if(valid){ |
940 | Min = value>>8; |
941 | Max = value; |
942 | } |
943 | return valid; |
944 | } |
945 |
|
946 | bool RoboClaw::ReadEncoders(uint8_t address,uint32_t &enc1,uint32_t &enc2){ |
947 | bool valid = read_n(2,address,GETENCODERS,&enc1,&enc2); |
948 | return valid; |
949 | } |
950 |
|
951 | bool RoboClaw::ReadISpeeds(uint8_t address,uint32_t &ispeed1,uint32_t &ispeed2){ |
952 | bool valid = read_n(2,address,GETISPEEDS,&ispeed1,&ispeed2); |
953 | return valid; |
954 | } |
955 |
|
956 | bool RoboClaw::RestoreDefaults(uint8_t address){ |
957 | return write_n(2,address,RESTOREDEFAULTS); |
958 | } |
959 |
|
960 | bool RoboClaw::ReadTemp(uint8_t address, uint16_t &temp){ |
961 | bool valid; |
962 | temp = Read2(address,GETTEMP,&valid); |
963 | return valid; |
964 | } |
965 |
|
966 | bool RoboClaw::ReadTemp2(uint8_t address, uint16_t &temp){ |
967 | bool valid; |
968 | temp = Read2(address,GETTEMP2,&valid); |
969 | return valid; |
970 | } |
971 |
|
972 | uint16_t RoboClaw::ReadError(uint8_t address,bool *valid){ |
973 | return Read2(address,GETERROR,valid); |
974 | } |
975 |
|
976 | bool RoboClaw::ReadEncoderModes(uint8_t address, uint8_t &M1mode, uint8_t &M2mode){ |
977 | bool valid; |
978 | uint16_t value = Read2(address,GETENCODERMODE,&valid); |
979 | if(valid){ |
980 | M1mode = value>>8; |
981 | M2mode = value; |
982 | } |
983 | return valid; |
984 | } |
985 |
|
986 | bool RoboClaw::SetM1EncoderMode(uint8_t address,uint8_t mode){ |
987 | return write_n(3,address,SETM1ENCODERMODE,mode); |
988 | } |
989 |
|
990 | bool RoboClaw::SetM2EncoderMode(uint8_t address,uint8_t mode){ |
991 | return write_n(3,address,SETM2ENCODERMODE,mode); |
992 | } |
993 |
|
994 | bool RoboClaw::WriteNVM(uint8_t address){ |
995 | return write_n(6,address,WRITENVM, SetDWORDval(0xE22EAB7A) ); |
996 | } |
997 |
|
998 | bool RoboClaw::ReadNVM(uint8_t address){ |
999 | return write_n(2,address,READNVM); |
1000 | } |
1001 |
|
1002 | bool RoboClaw::SetConfig(uint8_t address, uint16_t config){ |
1003 | return write_n(4,address,SETCONFIG,SetWORDval(config)); |
1004 | } |
1005 |
|
1006 | bool RoboClaw::GetConfig(uint8_t address, uint16_t &config){ |
1007 | bool valid; |
1008 | uint16_t value = Read2(address,GETCONFIG,&valid); |
1009 | if(valid){ |
1010 | config = value; |
1011 | } |
1012 | return valid; |
1013 | } |
1014 |
|
1015 | bool RoboClaw::SetM1MaxCurrent(uint8_t address,uint32_t max){ |
1016 | return write_n(10,address,SETM1MAXCURRENT,SetDWORDval(max),SetDWORDval(0)); |
1017 | } |
1018 |
|
1019 | bool RoboClaw::SetM2MaxCurrent(uint8_t address,uint32_t max){ |
1020 | return write_n(10,address,SETM2MAXCURRENT,SetDWORDval(max),SetDWORDval(0)); |
1021 | } |
1022 |
|
1023 | bool RoboClaw::ReadM1MaxCurrent(uint8_t address,uint32_t &max){ |
1024 | uint32_t tmax,dummy; |
1025 | bool valid = read_n(2,address,GETM1MAXCURRENT,&tmax,&dummy); |
1026 | if(valid) |
1027 | max = tmax; |
1028 | return valid; |
1029 | } |
1030 |
|
1031 | bool RoboClaw::ReadM2MaxCurrent(uint8_t address,uint32_t &max){ |
1032 | uint32_t tmax,dummy; |
1033 | bool valid = read_n(2,address,GETM2MAXCURRENT,&tmax,&dummy); |
1034 | if(valid) |
1035 | max = tmax; |
1036 | return valid; |
1037 | } |
1038 |
|
1039 | bool RoboClaw::SetPWMMode(uint8_t address, uint8_t mode){ |
1040 | return write_n(3,address,SETPWMMODE,mode); |
1041 | } |
1042 |
|
1043 | bool RoboClaw::GetPWMMode(uint8_t address, uint8_t &mode){ |
1044 | bool valid; |
1045 | uint8_t value = Read1(address,GETPWMMODE,&valid); |
1046 | if(valid){ |
1047 | mode = value; |
1048 | } |
1049 | return valid; |
1050 | } |
1051 |
|