Motion Master
Loading...
Searching...
No Matches
circulo_encoder_configuration.h
Go to the documentation of this file.
1#pragma once
2
3#include <chrono>
4#include <cstdint>
5
6#include "util.h"
7
8class Cia402Drive;
10
12 public:
14 Cia402Drive& cia402_drive, uint8_t encoder_ordinal,
15 uint8_t battery_mode_max_acceleration, uint32_t external_circulo_type,
16 const std::function<void()>& started_callback = {},
17 const std::function<void(uint8_t)>& progress_callback = {});
18
20
21 private:
22 Cia402Drive& cia402_drive_;
23 uint8_t encoder_ordinal_;
24 uint8_t battery_mode_max_acceleration_;
25 uint32_t external_circulo_type_;
28 uint8_t singleturn_bits_ = 0;
29
30 const std::function<void()>& started_callback_;
31 const std::function<void(uint8_t)>& progress_callback_;
32
33 double progress_ = 0;
34
35 // Prevent multiple encoder configurations from running on the same device
36 // at the same time
37 static inline std::unordered_map<int32_t, std::mutex> mutex_map_;
38
39 // Registers that have CALIBRATION written are not used by
40 // configuration. They will be written when calibrating the encoder.
41
42 // Singleturn
43 // Tuple: {Circulo type that uses the register value, address, value}
44 static inline const std::list<std::tuple<CirculoType, uint8_t, uint8_t>>
45 singleturn_address_value_list_ = {
46 // Register 0x00 = 0x00 (default=0x00)
47 {CirculoType::kUnspecified, 0x00, 0x00},
48
49 // Register 0x01 = CALIBRATION (default = 0x00)
50 // Register 0x02 = CALIBRATION (default = 0x00)
51 // Register 0x03 = CALIBRATION (default = 0x00)
52 // Register 0x04 = CALIBRATION (default = 0x00)
53 // Register 0x05 = 0x88 (default = 0x88)
54 {CirculoType::kUnspecified, 0x05, 0x88},
55
56 // Register 0x06 = 0x00 (default = 0x00)
57 {CirculoType::kUnspecified, 0x06, 0x00},
58
59 // Register 0x07 = CALIBRATION (default = 0x00)
60 // Register 0x08 = CALIBRATION (default = 0x00)
61 // Register 0x09 = CALIBRATION (default = 0x00)
62 // Register 0x0A = CALIBRATION (default = 0x00)
63 // Register 0x0B = 0x02 (default = 0x02)
64 {CirculoType::kCirculo7, 0x0B, 0x02},
65 {CirculoType::kCirculo7Smm, 0x0B, 0x52},
66 {CirculoType::kCirculo9, 0x0B, 0x02},
67 {CirculoType::kCirculo9Smm, 0x0B, 0x52},
68
69 // Register 0x0C = 0x6C (Mask AN_MAX error; default = 0x00)
70 {CirculoType::kUnspecified, 0x0C, 0x6C},
71
72 // Register 0x0D = 0xC0 (default = 0x00)
73 {CirculoType::kUnspecified, 0x0D, 0xC0},
74
75 // Register 0x0E = 0x04 (default=0x06)
76 {CirculoType::kUnspecified, 0x0E, 0x04},
77
78 // Register 0x0F = {Circulo 7: 0x05, Circulo 9: 0x06} (default=0x05)
79 {CirculoType::kCirculo7, 0x0F, 0x05},
80 {CirculoType::kCirculo7Smm, 0x0F, 0x05},
81 {CirculoType::kCirculo9, 0x0F, 0x06},
82 {CirculoType::kCirculo9Smm, 0x0F, 0x06},
83
84 // Register 0x10 = 0x00 (default=0x00)
85 {CirculoType::kUnspecified, 0x10, 0x00},
86
87 // Register 0x11 = {Circulo 7: 0x05, Circulo 9: 0x06} (default=0xA5)
88 {CirculoType::kCirculo7, 0x11, 0x05},
89 {CirculoType::kCirculo7Smm, 0x11, 0x05},
90 {CirculoType::kCirculo9, 0x11, 0x06},
91 {CirculoType::kCirculo9Smm, 0x11, 0x06},
92
93 // Register 0x12 = 0x00 (default=0x00)
94 {CirculoType::kUnspecified, 0x12, 0x00},
95
96 // Register 0x13/0x14 = 0xFF/0x0F (default=0xFF/0x0F)
97 {CirculoType::kUnspecified, 0x13, 0xFF},
98 {CirculoType::kUnspecified, 0x14, 0x0F},
99
100 // Register 0x15 = 0x13 (default=0x13)
101 {CirculoType::kUnspecified, 0x15, 0x13},
102
103 // Register 0x16 = 0x10 (default=0x10)
104 {CirculoType::kUnspecified, 0x16, 0x10},
105
106 // Register 0x17 = 0x02 (default=0x02)
107 {CirculoType::kUnspecified, 0x17, 0x02},
108
109 // Register 0x18 = 0x00 (default=0x00)
110 {CirculoType::kUnspecified, 0x18, 0x00},
111
112 // Write the iC-MU configuration to EEPROM
113 {CirculoType::kUnspecified, 0x75, 0x01}};
114
115 // Multiturn - Stage 1
116 // Tuple: {Circulo type that uses the register value, address, value}
117 static inline const std::list<std::tuple<CirculoType, uint8_t, uint8_t>>
118 multiturn_address_value_stage_1_list_ = {
120
121 // Register 0x00 = 0x00 (default=0x00)
122 {CirculoType::kUnspecified, 0x00, 0x00},
123
124 // Register 0x01 = CALIBRATION (default=0x00)
125 // Register 0x02 = CALIBRATION (default=0x00)
126 // Register 0x03 = CALIBRATION (default=0x00)
127 // Register 0x04 = CALIBRATION (default=0x00)
128 // Register 0x05 = 0x88 (default=0x88)
129 {CirculoType::kUnspecified, 0x05, 0x88},
130
131 // Register 0x06 = 0x00 (default=0x00)
132 {CirculoType::kUnspecified, 0x06, 0x00},
133
134 // Register 0x07 = CALIBRATION (default=0x00)
135 // Register 0x08 = CALIBRATION (default=0x00)
136 // Register 0x09 = CALIBRATION (default=0x00)
137 // Register 0x0A = CALIBRATION (default=0x00)
138 // Register 0x0B = 0x02 (default=0x02)
139 {CirculoType::kCirculo7, 0x0B, 0x02},
140 {CirculoType::kCirculo7Smm, 0x0B, 0x52},
141 {CirculoType::kCirculo9, 0x0B, 0x02},
142 {CirculoType::kCirculo9Smm, 0x0B, 0x52},
143
144 // Register 0x0C = 0x6C (Mask AN_MAX error; default=0x00)
145 {CirculoType::kUnspecified, 0x0C, 0x6C},
146
147 // Register 0x0D = 0xC0 (default=0x00)
148 {CirculoType::kUnspecified, 0x0D, 0xC0},
149
150 // Register 0x0E = 0x44 (default=0x06)
151 {CirculoType::kUnspecified, 0x0E, 0x44},
152
153 // Register 0x0F = {Circulo 7: 0x05, Circulo 9: 0x06} (default=0x05)
154 {CirculoType::kCirculo7, 0x0F, 0x05},
155 {CirculoType::kCirculo7Smm, 0x0F, 0x05},
156 {CirculoType::kCirculo9, 0x0F, 0x06},
157 {CirculoType::kCirculo9Smm, 0x0F, 0x06},
158
159 // Register 0x10 = 0x6F (default=0x00)
160 {CirculoType::kUnspecified, 0x10, 0x6F},
161
162 // Register 0x11 = {Circulo 7: 0x17, Circulo 9: 0x18} (default=0xA5)
163 {CirculoType::kCirculo7, 0x11, 0x17},
164 {CirculoType::kCirculo7Smm, 0x11, 0x17},
165 {CirculoType::kCirculo9, 0x11, 0x18},
166 {CirculoType::kCirculo9Smm, 0x11, 0x18},
167
168 // Register 0x12 = 0x00 (default=0x00)
169 {CirculoType::kUnspecified, 0x12, 0x00},
170
171 // Register 0x13/0x14 = 0xFF/0x0F (default=0xFF/0x0F)
172 {CirculoType::kUnspecified, 0x13, 0xFF},
173 {CirculoType::kUnspecified, 0x14, 0x0F},
174
175 // Register 0x15 = 0x13 (default=0x13)
176 {CirculoType::kUnspecified, 0x15, 0x13},
177
178 // Register 0x16 = 0x10 (default=0x10)
179 {CirculoType::kUnspecified, 0x16, 0x10},
180
181 // Register 0x17 = 0x02 (default=0x02)
182 {CirculoType::kUnspecified, 0x17, 0x02},
183
184 // Register 0x18 = 0x00 (default=0x00)
185 {CirculoType::kUnspecified, 0x18, 0x00},
186
188
189 // Configure I2C_DEVID (0x5E) to WRITE_EEPROM (0xA0). This tells the
190 // iC-MU that we want to use the I2C communication to write to the
191 // EEPROM.
192 {CirculoType::kUnspecified, 0x5E, 0xA0},
193
194 // Set the I2C_RAM_START (0x5C) to USER_EXCHANGE_REGISTERS_1 (0x60).
195 // This tells the iC-MU that the first value that he should write to
196 // the EEPROM is in the iC-MU RAM address 0x60. These
197 // USER_EXCHANGE_REGISTERS are used exclusively to store values that
198 // should be written to an external device via I2C (like the EEPROM
199 // or the iC-PVL).
200 {CirculoType::kUnspecified, 0x5C, 0x60},
201
202 // Set I2C_DEV_START (0x5B) to 0x40. This sets the first EEPROM
203 // address that should be written. Basically this means that the
204 // value written in the iC-MU RAM address 0x60 will be written to
205 // the EEPROM address 0x40. The reason why we start at EEPROM
206 // address 0x40 is that the EEPROM range 0x00-0x3F is used for the
207 // iC-MU configuration, and the iC-PVL configuration is stored in
208 // the range 0x40-0x4C, storing the value of the iC-PVL register
209 // 0x00 in EEPROM address 0x40, iC-PVL register 0x01 in EEPROM
210 // address 0x41, and so on.
211 {CirculoType::kUnspecified, 0x5B, 0x40},
212
213 // Set I2C_RAM_END (0x5D) to 0x6C. This tells the iC-MU when to stop
214 // writing the values in the USER_EXCHANGE_REGISTERS to the EEPROM.
215 // Since we want to write 13 values (EEPROM address 0x40 to address
216 // 0x4C), we need to use USER_EXCHANGE_REGISTERS_1 (0x60) to
217 // USER_EXCHANGE_REGISTERS_13 (0x6C).
218 {CirculoType::kUnspecified, 0x5D, 0x6C}};
219
220 // Multiturn - Stage 2 - CRC
221 // Tuple: {Circulo type that uses the register value, encoder position,
222 // address, value}
223 static inline const std::list<
224 std::tuple<CirculoType, EncoderLocation, uint8_t, uint8_t>>
225 multiturn_address_value_stage_2_list_ = {
226 // iC-PVL register 0x00 = 0x28 (default=0x00)
228 0x28},
229
230 // iC-PVL register 0x01 = 0x09 (default=0x00)
232 0x09},
233
234 // iC-PVL register 0x02 = {Circulo 7: 0x1F, Circulo 9: 0x3F}
235 // (default=0x00)
238 0x1F},
241 0x3F},
242
243 // iC-PVL register 0x03 = {Motor shaft: 0x5D, Driving shaft: 0x68}
244 // (default=0x00)
247 0x68},
248
249 // iC-PVL register 0x04 = 0x50 (default=0x00)
251 0x50},
252
253 // iC-PVL register 0x05 = 0x30 (default=0x00)
255
256 // iC-PVL register 0x06 - calculated CRC value of the previous
257 // registers: 0x00-0x05 (default=0x00)
258 };
259
260 // Multiturn - Stage 3
261 // Tuple: {address, value}
262 static inline const std::list<std::tuple<uint8_t, uint8_t>>
263 multiturn_address_value_stage_3_list_ = {
264 // iC-PVL registers 0x07-0x0B = 0x0000000000 (default=0x00)
265 {0x67, 0x00}, {0x68, 0x00}, {0x69, 0x00}, {0x6A, 0x00}, {0x6B, 0x00},
266
267 // iC-PVL register 0x0C - calculated CRC value of the previous
268 // registers: 0x07-0x0B (default=0x00)
269 };
270
271 // Multiturn - Stage 4 - Write REBOOT to iC-PVL. This will force iC-PVL to
272 // re-read the EEPROM and load those values in the RAM.
273 static inline const std::list<std::tuple<uint8_t, uint8_t>>
274 multiturn_address_value_stage_4_list_ = {
275 // Configure I2C_DEVID (0x5E) to WRITE_ICPVL (0xC2). This tells the
276 // iC-MU that we want to use the I2C communication to write to the
277 // iC-PVL.
278 {0x5E, 0xC2},
279
280 // Set the I2C_RAM_START (0x5C) to USER_EXCHANGE_REGISTERS_1 (0x60).
281 // This tells the iC-MU that the first value that he should write to
282 // the iC-PVL is in the iC-MU RAM address 0x60. These
283 // USER_EXCHANGE_REGISTERS are used exclusively to store values that
284 // should be written to an external device via I2C (like the EEPROM
285 // or the iC-PVL).
286 {0x5C, 0x60},
287
288 // Set I2C_DEV_START (0x5B) to 0x11. This sets the first iC-PVL
289 // register that should be written. Basically this means that the
290 // value written in the iC-MU RAM address 0x60 will be written to
291 // the iC-PVL register 0x11.
292 {0x5B, 0x11},
293
294 // Set I2C_RAM_END (0x5D) to 0x60. This tells the iC-MU when to stop
295 // writing the values in the USER_EXCHANGE_REGISTERS to the iC-PVL.
296 // Since we want to only write one value (iC-PVL address 0x11), we
297 // need to use only USER_EXCHANGE_REGISTERS_1 (0x60), so both
298 // I2C_RAM_END and I2C_RAM_START are set to that value.
299 {0x5D, 0x60},
300
301 // Now we can write each of the values we want to write to the
302 // iC-PVL in the USER_EXCHANGE_REGISTERS. iC-PVL register 0x11 =
303 // 0x03 (default=0x00). This will write REBOOT to the iC-PVL CMD
304 // register.
305 {0x60, 0x03},
306
307 // Set CMD_MU (0x75) to I2C_COM (0x0A). This will start the I2C
308 // communication with all the parameters that were configured above,
309 // effectively writing the REBOOT command to the iC-PVL.
310 {0x75, 0x0A}};
311
312 // Multiturn - Stage 5 - Reset iC-PVL errors (SCLR) and re-calculate
313 // absolute position (ABS_RESET)
314 static inline const std::list<std::tuple<uint8_t, uint8_t>>
315 multiturn_address_value_stage_5_list_ = {
316 // Configure I2C_DEVID (0x5E) to WRITE_ICPVL (0xC2). This tells the
317 // iC-MU that we want to use the I2C communication to write to the
318 // iC-PVL.
319 {0x5E, 0xC2},
320
321 // Set the I2C_RAM_START (0x5C) to USER_EXCHANGE_REGISTERS_1 (0x60).
322 // This tells the iC-MU that the first value that he should write to
323 // the iC-PVL is in the iC-MU RAM address 0x60. These
324 // USER_EXCHANGE_REGISTERS are used exclusively to store values that
325 // should be written to an external device via I2C (like the EEPROM
326 // or the iC-PVL).
327 {0x5C, 0x60},
328
329 // Set I2C_DEV_START (0x5B) to 0x11. This sets the first iC-PVL
330 // register that should be written. Basically this means that the
331 // value written in the iC-MU RAM address 0x60 will be written to
332 // the iC-PVL register 0x11.
333 {0x5B, 0x11},
334
335 // Set I2C_RAM_END (0x5D) to 0x60. This tells the iC-MU when to stop
336 // writing the values in the USER_EXCHANGE_REGISTERS to the iC-PVL.
337 // Since we want to only write one value (iC-PVL address 0x11), we
338 // need to use only USER_EXCHANGE_REGISTERS_1 (0x60), so both
339 // I2C_RAM_END and I2C_RAM_START are set to that value.
340 {0x5D, 0x60},
341
342 // Now we can write each of the values we want to write to the
343 // iC-PVL in the USER_EXCHANGE_REGISTERS.
344
345 // iC-PVL register 0x11 = 0x05 (default=0x00). This will write SCLR
346 // to the iC-PVL CMD register.
347 {0x60, 0x05},
348
349 // Set CMD_MU (0x75) to I2C_COM (0x0A). This will start the I2C
350 // communication with all the parameters
351 // that were configured above, effectively writing the SCLR command
352 // to the iC-PVL.
353 {0x75, 0x0A},
354
355 // Send ABS_RESET command to iC-MU
356 {0x75, 0x03}};
357
358 // Stage 6
359 static inline const std::list<std::tuple<uint8_t, uint8_t>>
360 multiturn_address_value_stage_6_list_ = {
361 // Change value of I2C_POS to 1 to be able to read the sync bits
362 // iC-PVL register 0x05 = 0xB0 (value before = 0x30)
363 // Configure I2C_DEVID (0x5E) to WRITE_ICPVL (0xC2). This tells the
364 // iC-MU that we want to use the I2C communication to write to the
365 // iC-PVL.
366 {0x5E, 0xC2},
367
368 // Set the I2C_RAM_START (0x5C) to USER_EXCHANGE_REGISTERS_1 (0x60).
369 // This tells the iC-MU that the first value that he should write to
370 // the iC-PVL is in the iC-MU RAM address 0x60. These
371 // USER_EXCHANGE_REGISTERS are used exclusively to store values that
372 // should be written to an external device via I2C (like the EEPROM
373 // or the iC-PVL).
374 {0x5C, 0x60},
375
376 // Set I2C_DEV_START (0x5B) to 0x05. This sets the first iC-PVL
377 // register that should be written. Basically this means that the
378 // value written in the iC-MU RAM address 0x60 will be written to
379 // the iC-PVL register 0x05.
380 {0x5B, 0x05},
381
382 // Set I2C_RAM_END (0x5D) to 0x60. This tells the iC-MU when to stop
383 // writing the values in the USER_EXCHANGE_REGISTERS to the iC-PVL.
384 // Since we want to only write one value (iC-PVL address 0x05), we
385 // need to use only USER_EXCHANGE_REGISTERS_1 (0x60), so both
386 // I2C_RAM_END and I2C_RAM_START are set to that value.
387 {0x5D, 0x60},
388
389 // Now we can write each of the values we want to write to the
390 // iC-PVL in the USER_EXCHANGE_REGISTERS.
391
392 // iC-PVL register 0x05 = 0xB0 (default=0x00). This will write 0xB0
393 // to the iC-PVL 0x05 register.
394 {0x60, 0xB0},
395
396 // Set CMD_MU (0x75) to I2C_COM (0x0A). This will start the I2C
397 // communication with all the parameters that were configured above,
398 // effectively writing the SCLR command to the iC-PVL.
399 {0x75, 0x0A},
400
401 // Read iC-PVL sync bits (iC-PVL address 0x0D, bit 2:0)
402
403 // Configure I2C_DEVID (0x5E) to READ_ICPVL (0xC3). This tells the
404 // iC-MU that we want to use the I2C communication to read the
405 // iC-PVL.
406 {0x5E, 0xC3},
407
408 // Set the I2C_RAM_START (0x5C) to USER_EXCHANGE_REGISTERS_1 (0x60).
409 // This tells the iC-MU that the first value that he should write to
410 // the iC-PVL is in the iC-MU RAM address 0x60. These
411 // USER_EXCHANGE_REGISTERS are used exclusively to store values that
412 // should be written to an external device via I2C (like the EEPROM
413 // or the iC-PVL).
414 {0x5C, 0x60},
415
416 // Set I2C_DEV_START (0x5B) to 0x0D. This sets the first iC-PVL
417 // register that should be read. Basically this means that the value
418 // read in the iC-PVL register 0x0D will be written in the iC-MU RAM
419 // address 0x60.
420 {0x5B, 0x0D},
421
422 // Set I2C_RAM_END (0x5D) to 0x60. This tells the iC-MU when to stop
423 // reading the values and writing them to the
424 // USER_EXCHANGE_REGISTERS to the iC-PVL. Since we want to only read
425 // one value (iC-PVL address 0x0D), we need to use only
426 // USER_EXCHANGE_REGISTERS_1 (0x60), so both I2C_RAM_END and
427 // I2C_RAM_START are set to that value.
428 {0x5D, 0x60},
429
430 // Set CMD_MU (0x75) to I2C_COM (0x0A). This will start the I2C
431 // communication with all the parameters that were configured above,
432 // effectively reading the iC-PVL register 0x0D to the iC-MU
433 // register 0x60.
434 {0x75, 0x0A}};
435
436 // Stage 7
437 static inline const std::list<std::tuple<uint8_t, uint8_t>>
438 multiturn_address_value_stage_7_list_ = {
439 // Change value of I2C_POS back to 0
440
441 // iC-PVL register 0x05 = 0x30
442 // Configure I2C_DEVID (0x5E) to WRITE_ICPVL (0xC2). This tells the
443 // iC-MU that we want to use the I2C communication to write to the
444 // iC-PVL.
445 {0x5E, 0xC2},
446
447 // Set the I2C_RAM_START (0x5C) to USER_EXCHANGE_REGISTERS_1 (0x60).
448 // This tells the iC-MU that the first value that he should write to
449 // the iC-PVL is in the iC-MU RAM address 0x60. These
450 // USER_EXCHANGE_REGISTERS are used exclusively to store values that
451 // should be written to an external device via I2C (like the EEPROM
452 // or the iC-PVL).
453 {0x5C, 0x60},
454
455 // Set I2C_DEV_START (0x5B) to 0x05. This sets the first iC-PVL
456 // register that should be written. Basically this means that the
457 // value written in the iC-MU RAM address 0x60 will be written to
458 // the iC-PVL register 0x05.
459 {0x5B, 0x05},
460
461 // Set I2C_RAM_END (0x5D) to 0x60. This tells the iC-MU when to stop
462 // writing the values in the USER_EXCHANGE_REGISTERS to the iC-PVL.
463 // Since we want to only write one value (iC-PVL address 0x05), we
464 // need to use only USER_EXCHANGE_REGISTERS_1 (0x60), so both
465 // I2C_RAM_END and I2C_RAM_START are set to that value.
466 {0x5D, 0x60},
467
468 // Now we can write each of the values we want to write to the
469 // iC-PVL in the USER_EXCHANGE_REGISTERS.
470
471 // iC-PVL register 0x05 = 0x30 (default=0x00). This will write 0x30
472 // to the iC-PVL 0x05 register.
473 {0x60, 0x30},
474
475 // Set CMD_MU (0x75) to I2C_COM (0x0A). This will start the I2C
476 // communication with all the parameters that were configured above,
477 // effectively writing the SCLR command to the iC-PVL.
478 {0x75, 0x0A}};
479
480 MotionMasterError configure_singleturn();
481
482 MotionMasterError configure_multiturn();
483
484 void add_action_to_progress(uint32_t total_actions,
485 uint32_t actions_to_add = 1);
486
487 void sleep_with_progress(uint32_t milliseconds, uint32_t total_actions);
488
489 MotionMasterError ignore_biss_status_bits(bool ignore);
490
491 MotionMasterError write_register(uint8_t address, uint8_t value);
492
493 static uint8_t crc(const std::vector<uint8_t>& data);
494};
CirculoType
Definition util.h:47
@ kCirculo7
Definition util.h:49
@ kCirculo9Smm
Definition util.h:52
@ kUnspecified
Definition util.h:48
@ kCirculo7Smm
Definition util.h:50
@ kCirculo9
Definition util.h:51
EncoderLocation
Definition util.h:63
@ kMotorShaft
Definition util.h:63
@ kUnspecified
Definition util.h:63
@ kDrivingShaft
Definition util.h:63
Definition cia402_drive.h:48
MotionMasterError start()
Definition circulo_encoder_configuration.cc:29
CirculoEncoderConfiguration(Cia402Drive &cia402_drive, uint8_t encoder_ordinal, uint8_t battery_mode_max_acceleration, uint32_t external_circulo_type, const std::function< void()> &started_callback={}, const std::function< void(uint8_t)> &progress_callback={})
Definition circulo_encoder_configuration.cc:17
Definition motion_master_error.h:6
uint8_t * value
Definition co_dictionary.h:9