1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766 | /* File: shadow_hand_buffers_definition.h
* This file is part of the program ethercatcpp-shadow
* Program description : EtherCAT driver library for shadow hand.
* Copyright (C) 2018-2022 - Robin Passama (CNRS/LIRMM) Arnaud Meline
* (CNRS/LIRMM) Benjamin Navarro (CNRS/LIRMM). All Right reserved.
*
* This software is free software: you can redistribute it and/or modify
* it under the terms of the CeCILL-C license as published by
* the CEA CNRS INRIA, either version 1
* of the License, or (at your option) any later version.
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* CeCILL-C License for more details.
*
* You should have received a copy of the CeCILL-C License
* along with this software. If not, it can be found on the official
* website of the CeCILL licenses family (http://www.cecill.info/index.en.html).
*/
/**
* @file shadow_hand_buffers_definition.h
* @author Robin Passama (robin.passama@lirmm.fr)
* @author Arnaud Meline
* @brief incmlude file for ethercat buffer definitions
* @ingroup ethercatcpp-shadow
*/
#pragma once
#include <cstdint>
#include <string>
#include <array>
#include <ethercatcpp/shadow/common.h>
/**
* @namespace ethercatcpp
* Root namespace for ethercatcpp packages
*/
namespace ethercatcpp {
// FIXME Doing type puning with unions is undefined behavior in C++ although
// supported by all major compilers
union word_to_bytes_t {
uint16_t word;<--- union member 'word_to_bytes_t::word' is never used.
uint8_t byte[2];<--- union member 'word_to_bytes_t::byte' is never used.
};
//! This enum describes type of trame we can send to hand
enum EDC_COMMAND {
EDC_COMMAND_INVALID =
0, //!< Reading an empty mailbox on the ET1200 results in a zero.
EDC_COMMAND_SENSOR_DATA, //!< Normal operating value. Palm transmits ADC
//!< readings.
EDC_COMMAND_SENSOR_CHANNEL_NUMBERS, //!< Instead of sending ADC readings,
//!< send the channel number, so the
//!< host can confirm the firmware is
//!< correct.
EDC_COMMAND_SENSOR_ADC_CHANNEL_CS, //!< Instead of sending ADC readings,
//!< send the chip select channel, so the
//!< host can confirm the firmware is
//!< correct.
EDC_COMMAND_CAN_DIRECT_MODE //!< Might be used in the future for running
//!< automated tests inside the firmware.
};
// ========================================================
//
// F R O M M O T O R D A T A T Y P E
//
// ========================================================
//! The host can request different types of data from the motors.
//! These values are inserted into bits [3..0] of the message ID
//! in the Data Request (Start Of Frame) message.
//!
//!
//! \htmlonly
//!< table border=1>
//! <tr> <td> </td> <td colspan=2>Word 0</td> <td
//! colspan=2>Word 1</td> </tr> <tr> <td>FROM_MOTOR_DATA_TYPE</td>
//! <td>Byte0</td> <td>Byte1</td> <td>Byte2</td> <td>Byte3</td> </tr>
//!
//! <tr> <td>MOTOR_DATA_SGL</td> <td colspan=2>Torque</td>
//! <td colspan=2>SGL</td> </tr> <tr>
//! <td>MOTOR_DATA_SGR</td> <td colspan=2>Torque</td> <td
//! colspan=2>SGR</td> </tr> <tr> <td>MOTOR_DATA_PWM</td>
//! <td colspan=2>Torque</td> <td colspan=2>PWM</td> </tr> <tr>
//! <td>MOTOR_DATA_FLAGS</td> <td colspan=2>Torque</td> <td
//! colspan=2>Flags</td> </tr> <tr>
//! <td>MOTOR_DATA_CURRENT</td> <td colspan=2>Torque</td> <td
//! colspan=2>Current</td> </tr> <tr>
//! <td>MOTOR_DATA_VOLTAGE</td> <td colspan=2>Torque</td> <td
//! colspan=2>Voltage</td> </tr> <tr>
//! <td>MOTOR_DATA_TEMPERATURE</td> <td colspan=2>Torque</td> <td
//! colspan=2>Temperature</td> </tr> <tr>
//! <td>MOTOR_DATA_CAN_NUM_RECEIVED</td> <td colspan=2>Torque</td> <td
//! colspan=2>Num Rx</td> </tr> <tr>
//! <td>MOTOR_DATA_CAN_NUM_TRANSMITTED</td> <td colspan=2>Torque</td> <td
//! colspan=2>Num Tx</td> </tr> <tr>
//! <td>MOTOR_DATA_SVN_REVISION</td> <td colspan=2>Server
//! revision</td> <td colspan=2>This revision (top bit = modified)</td>
//! </tr> <tr> <td>MOTOR_DATA_READBACK_LAST_CONFIG</td> <td
//! colspan=2>FROM_MOTOR_SLOW_DATA_TYPE</td> <td colspan=2>Config value</td>
//! </tr> <tr> <td>MOTOR_DATA_CAN_ERROR_COUNTERS</td> <td
//! colspan=2>Torque</td> <td >Tx Err</td> <td>Rx Err</td>
//! </tr>
//!</table>
//! \endhtmlonly
enum FROM_MOTOR_DATA_TYPE {
MOTOR_DATA_INVALID = 0x0, //!< For safety, this is not a valid request
MOTOR_DATA_SGL = 0x1, //!< ADC reading of left strain gauge
MOTOR_DATA_SGR = 0x2, //!< ADC reading of right strain gauge
MOTOR_DATA_PWM = 0x3, //!< Current motor PWM duty cycle.
MOTOR_DATA_FLAGS = 0x4, //!< See error_flag_names[]
MOTOR_DATA_CURRENT =
0x5, //!< Current in milliamps => real_value = data_receive / 1000
MOTOR_DATA_VOLTAGE =
0x6, //!< Voltage in millivolts => real_value = data_receive / 256
MOTOR_DATA_TEMPERATURE = 0x7, //!< Temperature in 8.8 fixed point format =>
//!< real_value = data_receive / 256
MOTOR_DATA_CAN_NUM_RECEIVED =
0x8, //!< Number of CAN messages received by this motor
MOTOR_DATA_CAN_NUM_TRANSMITTED =
0x9, //!< Number of CAN messages transmitted by this motor
MOTOR_DATA_SLOW_MISC = 0xA, //!< See FROM_MOTOR_SLOW_DATA_TYPE
MOTOR_DATA_READBACK_LAST_CONFIG =
0xB, //!< Torque=TO_MOTOR_DATA_TYPE. Misc=config value.
MOTOR_DATA_CAN_ERROR_COUNTERS =
0xC, //!< LSB = TX error counter. MSB = RX error counter.
MOTOR_DATA_PTERM =
0xD, //!< Internal proportional term from the torque controller / 256
MOTOR_DATA_ITERM =
0xE, //!< Internal integral term from the torque controller / 256
MOTOR_DATA_DTERM =
0xF //!< Internal derivative term from the torque controller / 256
};
//! These are the human-readable names of the different types of data.
//! you can send to the motors.
static const std::array<std::string, 16> from_motor_data_type_names = {
"safety mode",
"sgl",
"sgr",
"pwm",
"flags",
"current",
"voltage",
"temperature",
"can_num_received",
"can_num_transmitted",
"slow_data",
"read_back_last_config",
"can_error_counters",
"p_term",
"i_term",
"d_term"};
// ========================================================
// F R O M M O T O R D A T A T Y P E
// == > S L O W D A T A
//
// ========================================================
enum FROM_MOTOR_SLOW_DATA_TYPE {
MOTOR_SLOW_DATA_INVALID = 0x0000, //!< For safety, this is not a data type
MOTOR_SLOW_DATA_SVN_REVISION = 0x0001, //!< The revision of the code
MOTOR_SLOW_DATA_SVN_SERVER_REVISION =
0x0002, //!< The revision of the code on the SVN server at build time.
//! Should we have done an Update before building?
MOTOR_SLOW_DATA_SVN_MODIFIED =
0x0003, //!< Did the local code have any uncomitted modifications at
//!< build time?
MOTOR_SLOW_DATA_SERIAL_NUMBER_LOW = 0x0004, //!< Serial number low word
MOTOR_SLOW_DATA_SERIAL_NUMBER_HIGH = 0x0005, //!< Serial number high word
MOTOR_SLOW_DATA_GEAR_RATIO =
0x0006, //!< The gear ratio of the motor. E.G. 131 or 128
MOTOR_SLOW_DATA_ASSEMBLY_DATE_YYYY =
0x0007, //!< Year of assembly, E.G. 2012
MOTOR_SLOW_DATA_ASSEMBLY_DATE_MMDD =
0x0008, //!< Day/Month of assembly. E.G. 0x0A1F means October 31st
MOTOR_SLOW_DATA_CONTROLLER_F =
0x0009, //!< Feed forward gain of the FPID torque controller.
MOTOR_SLOW_DATA_CONTROLLER_P =
0x000A, //!< Proportional gain of the FPID torque controller.
MOTOR_SLOW_DATA_CONTROLLER_I =
0x000B, //!< Integral gain of the FPID torque controller.
MOTOR_SLOW_DATA_CONTROLLER_IMAX =
0x000C, //!< Maximum wind up of the integral term
MOTOR_SLOW_DATA_CONTROLLER_D =
0x000D, //!< Derivative gain of the FPID torque controller.
MOTOR_SLOW_DATA_CONTROLLER_DEADSIGN =
0x000E, //!< LSB = Dead band. Unsigned 8 bit. MSB = Sign. 0=+ve. 1=-ve.
MOTOR_SLOW_DATA_CONTROLLER_FREQUENCY =
0x000F, //!< Typically 5000. I.E. Torque controller runs at 5kHz.
MOTOR_SLOW_DATA_STRAIN_GAUGE_TYPE =
0x0010, //!< 0x0C = coupled gauges. 0x0D = decoupled gauges.
MOTOR_SLOW_DATA_LAST =
0x0010 //!< Important to know that this is the last one
};
//!< Flag to set "MOTOR_SLOW_DATA_STRAIN_GAUGE_TYPE" in stain gauge coupled
constexpr int STRAIN_GAUGE_TYPE_COUPLED = 0x0C;
//!< Flag to set "MOTOR_SLOW_DATA_STRAIN_GAUGE_TYPE" in stain gauge decoupled
constexpr int STRAIN_GAUGE_TYPE_DECOUPLED = 0x0D;
// Used to have human readable text
static const std::array<std::string, 18> slow_data_types_string = {
"Invalid", // 0x0000
"SVN revision", // 0x0001
"SVN revision on server at build time", // 0x0002
"Modified from SVN revision", // 0x0003
"Serial number low", // 0x0004
"Serial number high", // 0x0005
"Motor gear ratio", // 0x0006
"Assembly date year", // 0x0007
"Assembly date month, day", // 0x0008
"Controller F", // 0x0009
"Controller P", // 0x000A
"Controller I", // 0x000B
"Controller Imax", // 0x000C
"Controller D", // 0x000D
"Controller deadband and sign", // 0x000E
"Controller loop frequency Hz", // 0x000F
"Strain gauge type", // 0x0010
"Last data of motor slow" // 0x0010 //!< Important to know that
// this is the last one ?
};
// ========================================================
// F R O M M O T O R D A T A T Y P E
// == > F L A G S
//
// ========================================================
// Non serious flags, Just for information. Control still works.
// -------------------------------------------------------------
//!< Top 4 bits of the current choke.
constexpr int MOTOR_FLAG_BITS_CURRENT_CHOKE = 0x000F;
//!< 1=EEPROM write currently in progress, don't update configuration.
constexpr int MOTOR_FLAG_BITS_EEPROM_WRITING = 0x0010;
//!< 1=Last CRC message didn't patch the previously sent configs.
constexpr int MOTOR_FLAG_BITS_LAST_CONFIG_CRC_FAILED = 0x0020;
//!< 1=Last config message contained a value which was out of range.
constexpr int MOTOR_FLAG_BITS_LAST_CONFIG_OUT_OF_RANGE = 0x0040;
//!< Jiggling in progress to zreo gauge readings. Control unavailable at this
//!< time.
constexpr int MOTOR_FLAG_BITS_JIGGLING_IN_PROGRESS = 0x0080;
// Serious flags cause the motor to be switched off
// ------------------------------------------------
//!< Motor seems to have an out-of-range ID. You'll probably never see this
//!< flag. (Might get rid of it)
constexpr int MOTOR_FLAG_BITS_MOTOR_ID_IS_INVALID = 0x0200;
//!< Haven't received any demand messages for longer than NO_DEMAND_TIMEOUT_MS.
//!< Motor halted
constexpr int MOTOR_FLAG_BITS_NO_DEMAND_SEEN = 0x0400;
//!< Fault seen with Left strain gauge. Not currently implemented.
constexpr int MOTOR_FLAG_BITS_SGL_FAULT = 0x0800;
//!< Fault seen with Left strain gauge. Not currently implemented.
constexpr int MOTOR_FLAG_BITS_SGR_FAULT = 0x1000;
//!< nFault output from A3950 H-Bridge
constexpr int MOTOR_FLAG_BITS_A3950_NFAULT = 0x2000;
//!< EEPROM contains a bad CRC. Configs not loaded.
constexpr int MOTOR_FLAG_BITS_EEPROM_CONFIG_BAD_CRC = 0x4000;
//!< Motor over-heated and halted.
constexpr int MOTOR_FLAG_BITS_OVER_TEMP = 0x8000;
constexpr int NO_TORQUE_CONTROL_ERROR_FLAGS =
(MOTOR_FLAG_BITS_SGL_FAULT | MOTOR_FLAG_BITS_SGR_FAULT);
constexpr int PALM_0200_EDC_SERIOUS_ERROR_FLAGS =
(MOTOR_FLAG_BITS_NO_DEMAND_SEEN | MOTOR_FLAG_BITS_A3950_NFAULT |
MOTOR_FLAG_BITS_EEPROM_CONFIG_BAD_CRC | MOTOR_FLAG_BITS_OVER_TEMP);
//!< If a motor doesn't see any Torque or PWM demand values,how long, in
//!< milliseconds, before it switches off the motor.
constexpr int PALM_0200_EDC_NO_DEMAND_TIMEOUT_MS = 20;
//
//! These are the names of the bits in the MOTOR_DATA_FLAGS.
//! error_flag_names[n] is the name of bit 'n' in MOTOR_DATA_FLAGS.
static const std::array<std::string, 16> palm_0200_edc_error_flag_names = {
"Current choke bit 6", // 0x0001
"Current choke bit 7", // 0x0002
"Current choke bit 8", // 0x0004
"Current choke bit 9", // 0x0008
"EEPROM write in progress", // 0x0010
"Last CRC sent didn't match configs", // 0x0020
"Last config received was out of range", // 0x0040
"Jiggling in progress", // 0x0080
"Invalid flag", // 0x0100
"Motor ID is invalid", // 0x0200
"No demand seen for more than 20ms", // 0x0400
"Fault with strain gauge 0: left", // 0x0800
"Fault with strain gauge 1: right", // 0x1000
"A3950 H-bridge nFault asserted", // 0x2000
"EEPROM contains bad CRC. Motor off.", // 0x4000
"Motor over temperature" // 0x8000
};
// ========================================================
//
// T O M O T O R D A T A T Y P E
//
// ========================================================
//! The host can send different types of data from the motors.
//! These can be either control demands, or configurations.
//! These values are inserted into bits [3..0] of the message ID
//! in the Motor data message.
enum TO_MOTOR_DATA_TYPE {
MOTOR_DEMAND_INVALID =
0x0, //!< A zero is what happens if an EtherCAT packet doesn't get
//!< through, so it's considered a special case.
MOTOR_DEMAND_TORQUE =
0x1, //!< Demanding torque activates the Torque PID loop
MOTOR_DEMAND_PWM = 0x2, //!< Demanding PWM bypasses the Torque PID loop, and
//!< gives the exact PWM you asked for
//! except where
MOTOR_SYSTEM_RESET =
0x3, //!< Send with a demand value of 0x520x to reset motor x
MOTOR_SYSTEM_CONTROLS =
0x4, //!< Various bits to switch on / off misc things.
MOTOR_CONFIG_FIRST_VALUE =
0x7, //!< This is the first TO_MOTOR_DATA_TYPE which is actually a
//!< configuration and should be stored in EEPROM
MOTOR_CONFIG_MAX_PWM = 0x7, //!< Put an upper limit on the absolute value of
//!< the motor PWM. Range [0..0x03FF]
MOTOR_CONFIG_SG_REFS = 0x8, //!< Strain gauge amp references. LSB = ref for
//!< SGL, MSB = ref for SGR.
MOTOR_CONFIG_F = 0x9, //!< Feed forward gain
MOTOR_CONFIG_P = 0xA, //!< Proportional gain
MOTOR_CONFIG_I = 0xB, //!< Integral gain
MOTOR_CONFIG_D = 0xC, //!< Derivative gain
MOTOR_CONFIG_IMAX = 0xD, //!< Maximum integral windup
MOTOR_CONFIG_DEADBAND_SIGN = 0xE, //!< MSB=sign. LSB=Deadband.
MOTOR_CONFIG_LAST_VALUE =
0xE, //!< This is the last config (apart from the CRC, which is special)
MOTOR_CONFIG_CRC =
0xF //!< Sending this value, if it matches the CRC of the configs
//! above, causes the configs to take effect.
};
constexpr int MOTOR_SYSTEM_RESET_KEY = 0x5200; //!< | Motor ID.
// Flags for MOTOR_SYSTEM_CONTROLS
//!< Turn on Backlash Compensation
constexpr int MOTOR_SYSTEM_CONTROL_BACKLASH_COMPENSATION_ENABLE = 0x0001;
//!< Turn off Backlash Compensation
constexpr int MOTOR_SYSTEM_CONTROL_BACKLASH_COMPENSATION_DISABLE = 0x0002;
//!< Increment the tracking value for Left gauge
constexpr int MOTOR_SYSTEM_CONTROL_SGL_TRACKING_INC = 0x0004;
//!< Decrement the tracking value for Left gauge
constexpr int MOTOR_SYSTEM_CONTROL_SGL_TRACKING_DEC = 0x0008;
//!< Increment the tracking value for Right gauge
constexpr int MOTOR_SYSTEM_CONTROL_SGR_TRACKING_INC = 0x0010;
//!< Decrement the tracking value for Right gauge
constexpr int MOTOR_SYSTEM_CONTROL_SGR_TRACKING_DEC = 0x0020;
//!< Initiate the jiggling to re-zero the strain gauges. You'll see the
//!< MOTOR_FLAG_BITS_JIGGLING_IN_PROGRESS flag appear.
constexpr int MOTOR_SYSTEM_CONTROL_INITIATE_JIGGLING = 0x0040;
//!< Write the configuration to the EEPROM.
constexpr int MOTOR_SYSTEM_CONTROL_EEPROM_WRITE = 0x0080;
constexpr int MOTOR_DEMAND_TORQUE_RANGE_MIN = -0x7FFF;
constexpr int MOTOR_DEMAND_TORQUE_RANGE_MAX = 0x7FFF;
constexpr int MOTOR_DEMAND_PWM_RANGE_MIN = -0x03FF;
constexpr int MOTOR_DEMAND_PWM_RANGE_MAX = 0x03FF;
constexpr int MOTOR_CONFIG_F_RANGE_MIN = 0x0000;
constexpr int MOTOR_CONFIG_F_RANGE_MAX = 0x7FFF;
constexpr int MOTOR_CONFIG_P_RANGE_MIN = 0x0000;
constexpr int MOTOR_CONFIG_P_RANGE_MAX = 0x7FFF;
constexpr int MOTOR_CONFIG_I_RANGE_MIN = 0x0000;
constexpr int MOTOR_CONFIG_I_RANGE_MAX = 0x7FFF;
constexpr int MOTOR_CONFIG_D_RANGE_MIN = 0x0000;
constexpr int MOTOR_CONFIG_D_RANGE_MAX = 0x7FFF;
constexpr int MOTOR_CONFIG_IMAX_RANGE_MIN = 0x0000;
constexpr int MOTOR_CONFIG_IMAX_RANGE_MAX = 0x3FFF;
constexpr int MOTOR_CONFIG_DEADBAND_RANGE_MIN = 0x00;
constexpr int MOTOR_CONFIG_DEADBAND_RANGE_MAX = 0xFF;
constexpr int MOTOR_CONFIG_SIGN_RANGE_MIN = 0x00;
constexpr int MOTOR_CONFIG_SIGN_RANGE_MAX = 0x01;
//! These are the human-readable names of the different types of data.
//! you can send to the motors.
static const std::array<std::string, 16> to_motor_data_type_names = {
"INVALID",
"Demand: Torque",
"Demand: PWM",
"INVALID",
"INVALID",
"INVALID",
"INVALID",
"Config: Maximum PWM value",
"Config: Strain gauge amp references. LSB = ref for SGL, MSB = ref "
"for SGR",
"Config: Feed forward gain",
"Config: Proportional gain",
"Config: Integral gain",
"Config: Derivative gain",
"Config: Maximum integral windup",
"Config: MSB=Deadband. LSB=Sign",
"Config: CRC",
};
//
// Each motor sends back two 16-bit words of status data on the CAN bus.
// Generically, those two words look like this.
struct MOTOR_DATA_PACKET {
int16_t torque; //!< Measured Motor Torque<--- struct member 'MOTOR_DATA_PACKET::torque' is never used.
uint16_t misc; //!< Some other value, determined by from_motor_data_type<--- struct member 'MOTOR_DATA_PACKET::misc' is never used.
};
// ----------------------------------------------------------------------------
//
// T A C T I L E S E N S O R S
//
// -----------------------------------------------------------------------------
// from "../common/tactile_edc_ethercat_protocol.h"
// SynTouch BioTac v2.3 : detailed spec in shadowHand wiki.
//! Data you can request from tactile sensors in general
enum FROM_TACTILE_SENSOR_TYPE {
TACTILE_SENSOR_TYPE_WHICH_SENSORS =
0xFFF9, //!< Is this a PST, a BioTac, or what? Returns a
//!< TACTILE_SENSOR_PROTOCOL_TYPE
TACTILE_SENSOR_TYPE_SAMPLE_FREQUENCY_HZ =
0xFFFA, //!< word[0] = frequency in Hz. currently only used by BioTacs
TACTILE_SENSOR_TYPE_MANUFACTURER = 0xFFFB, //!< e.g. "Shadow" or "Syntouch"
TACTILE_SENSOR_TYPE_SERIAL_NUMBER = 0xFFFC, //!< e.g. "PST3200110190001"
TACTILE_SENSOR_TYPE_SOFTWARE_VERSION = 0xFFFD, //!< e.g. "1825"
TACTILE_SENSOR_TYPE_PCB_VERSION =
0xFFFE, //!< e.g. "FB". Currently only used by BioTacs
TACTILE_SENSOR_TYPE_RESET_COMMAND =
0xFFFF //!< Requesting this causes the tactile sensors to reset if they
//!< support it.
};
//! returned data when request a "TACTILE_SENSOR_TYPE_WHICH_SENSORS" on
//! FROM_TACTILE_SENSOR_TYPE
enum TACTILE_SENSOR_PROTOCOL_TYPE {
TACTILE_SENSOR_PROTOCOL_TYPE_INVALID =
0x0000, //!< No supported sensors were found.
TACTILE_SENSOR_PROTOCOL_TYPE_PST3 =
0x0001, //!< Shadow's Pressure Tactile sensor, Hugo's firmware
TACTILE_SENSOR_PROTOCOL_TYPE_BIOTAC_2_3 =
0x0002, //!< Syntouch's BioTac sensor, version 2.3
TACTILE_SENSOR_PROTOCOL_TYPE_UBI0 = 0x0003, //!< Bielefeld's tactile sensor
TACTILE_SENSOR_PROTOCOL_TYPE_CONFLICTING =
0xFFFF //!< More than 1 type of sensor is connected to the hand! (Very
//!< unlikely to happen)
};
static const std::array<std::string, 5> tactile_sensor_protocol_type_strings = {
"None", "Shadow Robot Company Ltd.", "Syntouch BioTac 2.3",
"Bielefeld University", "Error : more than 1 type of sensor is connected"};
// Data you can request from BioTacs
enum FROM_TACTILE_BIOTAC {
TACTILE_BIOTAC_INVALID = 0x0000,
TACTILE_BIOTAC_PDC_AND_TAC =
0x0001, // other_sensor_0 = Pdc (Fluid pressure) | other_sensor_1 = Tac
// (Thermal Flux)
// TACTILE_BIOTAC_TAC = 0x0002,
TACTILE_BIOTAC_TDC_AND_ELECTRODE_1 =
0x0003, // other_sensor_0 = Tdc (Temperature) | other_sensor_1 =
// electrode_1 (Impedance)
// TACTILE_BIOTAC_ELECTRODE_1 = 0x0004,
TACTILE_BIOTAC_ELECTRODE_2_AND_3 =
0x0005, // other_sensor_0 = electrode_2 (Impedance) | other_sensor_1 =
// electrode_3 (Impedance)
// TACTILE_BIOTAC_ELECTRODE_3 = 0x0006,
TACTILE_BIOTAC_ELECTRODE_4_AND_5 =
0x0007, // other_sensor_0 = electrode_4 (Impedance) | other_sensor_1 =
// electrode_5 (Impedance)
// TACTILE_BIOTAC_ELECTRODE_5 = 0x0008,
TACTILE_BIOTAC_ELECTRODE_6_AND_7 =
0x0009, // other_sensor_0 = electrode_6 (Impedance) | other_sensor_1 =
// electrode_7 (Impedance)
// TACTILE_BIOTAC_ELECTRODE_7 = 0x000A,
TACTILE_BIOTAC_ELECTRODE_8_AND_9 =
0x000B, // other_sensor_0 = electrode_8 (Impedance) | other_sensor_1 =
// electrode_9 (Impedance)
// TACTILE_BIOTAC_ELECTRODE_9 = 0x000C,
TACTILE_BIOTAC_ELECTRODE_10_AND_11 =
0x000D, // other_sensor_0 = electrode_10 (Impedance) | other_sensor_1 =
// electrode_11 (Impedance)
// TACTILE_BIOTAC_ELECTRODE_11 = 0x000E,
TACTILE_BIOTAC_ELECTRODE_12_AND_13 =
0x000F, // other_sensor_0 = electrode_12 (Impedance) | other_sensor_1 =
// electrode_13 (Impedance)
// TACTILE_BIOTAC_ELECTRODE_13 = 0x0010,
TACTILE_BIOTAC_ELECTRODE_14_AND_15 =
0x0011, // other_sensor_0 = electrode_14 (Impedance) | other_sensor_1 =
// electrode_15 (Impedance)
// TACTILE_BIOTAC_ELECTRODE_15 = 0x0012,
TACTILE_BIOTAC_ELECTRODE_16_AND_17 =
0x0013, // other_sensor_0 = electrode_16 (Impedance) | other_sensor_1 =
// electrode_17 (Impedance)
// TACTILE_BIOTAC_ELECTRODE_17 = 0x0014,
TACTILE_BIOTAC_ELECTRODE_18_AND_19 =
0x0015, // other_sensor_0 = electrode_18 (Impedance) | other_sensor_1 =
// electrode_19 (Impedance)
// TACTILE_BIOTAC_ELECTRODE_19 = 0x0016,
// TACTILE_BIOTAC_ELECTRODE_20 = 0x0017, //only 19 electrode on BioTac
// v2.3 TACTILE_BIOTAC_ELECTRODE_21 = 0x0018, TACTILE_BIOTAC_ELECTRODE_22
// = 0x0019, TACTILE_BIOTAC_ELECTRODE_23 = 0x001A,
// TACTILE_BIOTAC_ELECTRODE_24 = 0x001B,
FROM_TACTILE_BIOTAC_NUM_VALUES = 0x001C
};
// Structure that define data BioTac contents
struct tactile_biotac_data_contents_t {
int16_t Pac[2]; //!< Pressure vibration signal (microvibration)<--- struct member 'tactile_biotac_data_contents_t::Pac' is never used.
int16_t other_sensor_0; //!< Value of requested data by FROM_TACTILE_BIOTAC<--- struct member 'tactile_biotac_data_contents_t::other_sensor_0' is never used.
//! Struct that define if data receive in Pac and other_sensors are valid
struct {
uint8_t Pac0 : 1; //!< Validity of Pac0<--- struct member 'Anonymous0::Pac0' is never used.
uint8_t Pac1 : 1; //!< Validity of Pac1<--- struct member 'Anonymous0::Pac1' is never used.
uint8_t other_sensor_0 : 1; //!< Validity of other_sensor_0<--- struct member 'Anonymous0::other_sensor_0' is never used.
uint8_t other_sensor_1 : 1; //!< Validity of other_sensor_1<--- struct member 'Anonymous0::other_sensor_1' is never used.
} data_valid;<--- struct member 'tactile_biotac_data_contents_t::data_valid' is never used.
int16_t other_sensor_1; //!< Value of requested data by FROM_TACTILE_BIOTAC<--- struct member 'tactile_biotac_data_contents_t::other_sensor_1' is never used.
uint16_t nothing[3]; //!< To complete and respect size of struct ( 8 words<--- struct member 'tactile_biotac_data_contents_t::nothing' is never used.
//!< = 5 used + 3 unused)
}; // TACTILE_SENSOR_BIOTAC_DATA_CONTENTS
//!< Tactile names
static const std::array<std::string, 5> tactile_name = {"FF", //!< First finger
"MF", //!< Middle finger
"RF", //!< Ring finger
"LF", //!< Little finger
"TH"}; //!< Thumb
// ----------------------------------------------------------------------------
// E N D O F T A C T I L E S E N S O R S
// -----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
//
// P O S I T I O N S E N S O R S
//
// -----------------------------------------------------------------------------
// This array defines the names of the sensors on joints. The names and order
// should match the enum SENSOR_NAMES_ENUM.
static const std::array<std::string, shadow::SENSORS_NUM_0220 + 1>
sensor_names = {
"FFJ1", "FFJ2", "FFJ3",
"FFJ4", // [00..03] ADC readings from First finger
"MFJ1", "MFJ2", "MFJ3",
"MFJ4", // [04..07] ADC readings from Middle finger
"RFJ1", "RFJ2", "RFJ3",
"RFJ4", // [08..11] ADC readings from Ring finger
"LFJ1", "LFJ2", "LFJ3",
"LFJ4", "LFJ5", // [12..16] ADC readings from Little finger
"THJ1", "THJ2", "THJ3",
"THJ4", "THJ5A", "THJ5B", // [17..22] ADC readings from Thumb
"WRJ1A", "WRJ1B", "WRJ2", // [23..25] ADC readings from Wrist
"ACCX", "ACCY", "ACCZ", // [26..28] ADC readings from Accelerometer
"GYRX", "GYRY", "GYRZ", // [29..31] ADC readings from Gyroscope
"AN0", "AN1", "AN2",
"AN3", // [32..35] ADC readings from auxillary ADC port.
"IGNORE"};
//! This enum defines which ADC reading goes into which sensors[].
enum SENSOR_NAME_ENUM {
FFJ1 = 0,
FFJ2,
FFJ3,
FFJ4, // [ 0...3]
MFJ1,
MFJ2,
MFJ3,
MFJ4, // [ 4...7]
RFJ1,
RFJ2,
RFJ3,
RFJ4, // [ 8..11]
LFJ1,
LFJ2,
LFJ3,
LFJ4,
LFJ5, // [12..16]
THJ1,
THJ2,
THJ3,
THJ4,
THJ5A,
THJ5B, // [17..22]
WRJ1A,
WRJ1B,
WRJ2, // [23..25]
ACCX,
ACCY,
ACCZ, // [26..28]
GYRX,
GYRY,
GYRZ, // [29..32]
ANA0,
ANA1,
ANA2,
ANA3, // [31..35]
IGNORE // [36]
};
// This array defines the joints names. The names and order should match the
// sensors datas array
static const std::array<std::string, 24> joints_names = {
"FFJ1", "FFJ2", "FFJ3", "FFJ4", // [00..03] First finger
"MFJ1", "MFJ2", "MFJ3", "MFJ4", // [04..07] Middle finger
"RFJ1", "RFJ2", "RFJ3", "RFJ4", // [08..11] Ring finger
"LFJ1", "LFJ2", "LFJ3", "LFJ4", "LFJ5", // [12..16] Little finger
"THJ1", "THJ2", "THJ3", "THJ4", "THJ5", // [17..21] Thumb
"WRJ1", "WRJ2", // [22..23] Wrist
};
// ========================================================
//
// C O M M A N D B U F F E R
//
// ========================================================
// This structure represent the "command buffer" datas send by the host.
struct [[gnu::packed]] buffer_shadow_out_command_t {
EDC_COMMAND EDC_command; //!< What type of data should the palm send back in<--- struct member 'buffer_shadow_out_command_t::EDC_command' is never used.
//!< the next packet?
FROM_MOTOR_DATA_TYPE from_motor_data_type; //!< Which data does the host<--- struct member 'buffer_shadow_out_command_t::from_motor_data_type' is never used.
//!< want from the motors?
int16_t which_motors; //!< Which motors does the host want to read? 0: Even<--- struct member 'buffer_shadow_out_command_t::which_motors' is never used.
//!< motor numbers. 1: Odd motor numbers
TO_MOTOR_DATA_TYPE to_motor_data_type; //!< Type of datas ask by the host<--- struct member 'buffer_shadow_out_command_t::to_motor_data_type' is never used.
int16_t
motor_data[shadow::NUM_MOTORS]; //!< Data to send to motors. Typically<--- struct member 'buffer_shadow_out_command_t::motor_data' is never used.
//!< torque/PWM demands, or configs.
uint32_t
tactile_data_type; //!< Request for specific tactile data<--- struct member 'buffer_shadow_out_command_t::tactile_data_type' is never used.
//!< FROM_TACTILE_SENSOR_TYPE or FROM_TACTILE_BIOTAC
};
// ========================================================
//
// S T A T U S B U F F E R
//
// ========================================================
// This structure represent the "status buffer" datas send from the Palm to the
// host.
struct [[gnu::packed]] buffer_shadow_in_status_t {
EDC_COMMAND
EDC_command; //!< This tells us the contents of the data below adn<--- struct member 'buffer_shadow_in_status_t::EDC_command' is never used.
//!< should be identical to the EDC_command value which
//!< arrived from the host in the previous EtherCAT packet.
uint16_t sensors[shadow::SENSORS_NUM_0220 +<--- struct member 'buffer_shadow_in_status_t::sensors' is never used.
1]; //!< All ADC sensor datas in SENSOR_NAME_ENUM. Raw
//!< value (0..25) of each joints coders (need to
//!< calibrate with table to obtained angle).
FROM_MOTOR_DATA_TYPE
motor_data_type; //!< Which data does motor[] contain? This value should<--- struct member 'buffer_shadow_in_status_t::motor_data_type' is never used.
//!< agree with the previous value in
//!< ETHERCAT_DATA_STRUCTURE_0200_PALM_EDC_COMMAND.
int16_t which_motors; //!< 0: Even motor numbers. 1: Odd motor numbers.<--- struct member 'buffer_shadow_in_status_t::which_motors' is never used.
//!< This value should agree with the previous value
//!< in ETHERCAT_DATA_STRUCTURE_0200_PALM_EDC_COMMAND.
uint32_t
which_motor_data_arrived; //!< Bit N set when motor CAN message arrives.<--- struct member 'buffer_shadow_in_status_t::which_motor_data_arrived' is never used.
//!< Ideally, bits 0..19 get set.
uint32_t
which_motor_data_had_errors; //!< Bit N set when motor sends bad CAN<--- struct member 'buffer_shadow_in_status_t::which_motor_data_had_errors' is never used.
//!< message Ideally, no bits get set.
MOTOR_DATA_PACKET motor_data_packet[10]; //!< Data for 10 motors only. (Even<--- struct member 'buffer_shadow_in_status_t::motor_data_packet' is never used.
//!< ones or Odd ones).
uint32_t
tactile_data_type; //!< asked specific tactile data<--- struct member 'buffer_shadow_in_status_t::tactile_data_type' is never used.
//!< FROM_TACTILE_SENSOR_TYPE or FROM_TACTILE_BIOTAC.
uint16_t tactile_data_valid; //!< Bit 0:FF, Bit 1:MF, Bit 2:RF, Bit 3:LF,<--- struct member 'buffer_shadow_in_status_t::tactile_data_valid' is never used.
//!< Bit 4:TH
tactile_biotac_data_contents_t
tactile[5]; //!< Datas from tactile_biotac_data_contents_t struct for<--- struct member 'buffer_shadow_in_status_t::tactile' is never used.
//!< the 5 fingers (0:FF, 1:MF, 2:RF, 3:LF, 4:TH).
uint16_t idle_time_us; //!< The idle time from when the palm has finished<--- struct member 'buffer_shadow_in_status_t::idle_time_us' is never used.
//!< dealing with one EtherCAT packet, and the next
//!< packet arriving. Ideally, this number should be
//!< more than 50.
};
// ========================================================
//
// C A N B U F F E R
//
// ========================================================
// UNUSED !
// This packet allows the palm to transmit and receive CAN messages
// on either CAN bus. One CAN message per EtherCAT packet only.
// The CAN messages can be used for bootloading new code onto the motors,
// or to configure the motor boards.
struct [[gnu::packed]] buffer_shadow_can_t {
uint8_t can_bus;<--- struct member 'buffer_shadow_can_t::can_bus' is never used.
uint8_t message_length;<--- struct member 'buffer_shadow_can_t::message_length' is never used.
uint16_t message_id;<--- struct member 'buffer_shadow_can_t::message_id' is never used.
uint8_t message_data[8];<--- struct member 'buffer_shadow_can_t::message_data' is never used.
};
} // namespace ethercatcpp
|