YARP
Yet Another Robot Platform
ControlBoardHelper.cpp
Go to the documentation of this file.
1 /*
2  * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 
7 #include <yarp/dev/PidEnums.h>
8 #include <cstdio> // for printf
9 #include <cmath> //fabs
10 #include <yarp/os/Log.h>
11 #include <yarp/os/LogStream.h>
12 #include <map>
13 
14 using namespace yarp::dev;
15 
16 struct PidUnits
17 {
23  }
24 };
25 
27 {
28 public:
29  int nj;
30  int *axisMap;
31  int *invAxisMap;
32  bool verbose;
33 
34  double *position_zeros;
35  double *helper_ones;
36  double *angleToEncoders;
38  double *ampereToSensors;
39  double *voltToSensors;
40  double *dutycycleToPWMs;
41  double *bemfToRaws;
42  double *ktauToRaws;
43 
48  std::map<PidControlTypeEnum, PidUnits*> pid_units;
49 
50  explicit PrivateUnitsHandler(int size) :
51  axisMap(nullptr),
52  invAxisMap(nullptr),
53  verbose(true),
54  position_zeros(nullptr),
55  helper_ones(nullptr),
56  angleToEncoders(nullptr),
57  newtonsToSensors(nullptr),
58  ampereToSensors(nullptr),
59  voltToSensors(nullptr),
60  dutycycleToPWMs(nullptr),
61  bemfToRaws(nullptr),
62  ktauToRaws(nullptr),
63  PosPid_units(nullptr),
64  VelPid_units(nullptr),
65  CurPid_units(nullptr),
66  TrqPid_units(nullptr)
67  {
68  alloc(size);
69  std::fill_n(helper_ones, size, 1.0);
70  std::fill_n(position_zeros, size, 0.0);
71  std::fill_n(angleToEncoders, size, 1.0);
72  std::fill_n(newtonsToSensors, size, 1.0);
73  std::fill_n(ampereToSensors, size, 1.0);
74  std::fill_n(voltToSensors, size, 1.0);
75  std::fill_n(dutycycleToPWMs, size, 1.0);
76  std::fill_n(bemfToRaws, size, 1.0);
77  std::fill_n(ktauToRaws, size, 1.0);
78  }
79 
81  {
86  checkAndDestroy<double>(position_zeros);
87  checkAndDestroy<double>(helper_ones);
88  checkAndDestroy<int>(axisMap);
89  checkAndDestroy<int>(invAxisMap);
90  checkAndDestroy<double>(angleToEncoders);
91  checkAndDestroy<double>(newtonsToSensors);
92  checkAndDestroy<double>(ampereToSensors);
93  checkAndDestroy<double>(voltToSensors);
94  checkAndDestroy<double>(dutycycleToPWMs);
95  checkAndDestroy<double>(bemfToRaws);
96  checkAndDestroy<double>(ktauToRaws);
97  }
98 
99  void alloc(int n)
100  {
101  nj = n;
102  position_zeros = new double[nj];
103  helper_ones = new double[nj];
104  axisMap = new int[nj];
105  invAxisMap = new int[nj];
106  angleToEncoders = new double[nj];
107  newtonsToSensors = new double[nj];
108  ampereToSensors = new double[nj];
109  voltToSensors = new double[nj];
110  dutycycleToPWMs = new double[nj];
111  PosPid_units = new PidUnits[nj];
112  VelPid_units = new PidUnits[nj];
113  TrqPid_units = new PidUnits[nj];
114  CurPid_units = new PidUnits[nj];
115  bemfToRaws = new double[nj];
116  ktauToRaws = new double[nj];
117 
118  yAssert(position_zeros != nullptr);
119  yAssert(helper_ones != nullptr);
120  yAssert(axisMap != nullptr);
121  yAssert(invAxisMap != nullptr);
122  yAssert(angleToEncoders != nullptr);
123  yAssert(newtonsToSensors != nullptr);
124  yAssert(ampereToSensors != nullptr);
125  yAssert(voltToSensors != nullptr);
126  yAssert(dutycycleToPWMs != nullptr);
127  yAssert(PosPid_units != nullptr);
128  yAssert(VelPid_units != nullptr);
129  yAssert(TrqPid_units != nullptr);
130  yAssert(CurPid_units != nullptr);
131  yAssert(bemfToRaws != nullptr);
132  yAssert(ktauToRaws != nullptr);
133 
138  }
139 
141  {
142  alloc(other.nj);
143  memcpy(this->position_zeros, other.position_zeros, sizeof(*other.position_zeros)*nj);
144  memcpy(this->helper_ones, other.helper_ones, sizeof(*other.helper_ones)*nj);
145  memcpy(this->axisMap, other.axisMap, sizeof(*other.axisMap)*nj);
146  memcpy(this->invAxisMap, other.invAxisMap, sizeof(*other.invAxisMap)*nj);
147  memcpy(this->angleToEncoders, other.angleToEncoders, sizeof(*other.angleToEncoders)*nj);
148  memcpy(this->newtonsToSensors, other.newtonsToSensors, sizeof(*other.newtonsToSensors)*nj);
149  memcpy(this->ampereToSensors, other.ampereToSensors, sizeof(*other.ampereToSensors)*nj);
150  memcpy(this->voltToSensors, other.voltToSensors, sizeof(*other.voltToSensors)*nj);
151  memcpy(this->dutycycleToPWMs, other.dutycycleToPWMs, sizeof(*other.dutycycleToPWMs)*nj);
152  memcpy(this->PosPid_units, other.PosPid_units, sizeof(*other.PosPid_units)*nj);
153  memcpy(this->VelPid_units, other.VelPid_units, sizeof(*other.VelPid_units)*nj);
154  memcpy(this->TrqPid_units, other.TrqPid_units, sizeof(*other.TrqPid_units)*nj);
155  memcpy(this->CurPid_units, other.CurPid_units, sizeof(*other.CurPid_units)*nj);
156  memcpy(this->bemfToRaws, other.bemfToRaws, sizeof(*other.bemfToRaws)*nj);
157  memcpy(this->ktauToRaws, other.ktauToRaws, sizeof(*other.ktauToRaws)*nj);
158  }
159 };
160 
161 ControlBoardHelper::ControlBoardHelper(int n, const int *aMap, const double *angToEncs, const double *zs, const double *newtons, const double *amps, const double *volts, const double *dutycycles, const double *kbemf, const double *ktau)
162 {
163  yAssert(n>=0); // if number of joints is negative complain!
164  yAssert(aMap!=nullptr); // at least the axisMap is required
165  mPriv = new PrivateUnitsHandler(n);
166 
167  memcpy(mPriv->axisMap, aMap, sizeof(int)*n);
168 
169  if (zs != nullptr) {
170  memcpy(mPriv->position_zeros, zs, sizeof(double) * n);
171  }
172  if (angToEncs != nullptr) {
173  memcpy(mPriv->angleToEncoders, angToEncs, sizeof(double) * n);
174  }
175  if (newtons != nullptr) {
176  memcpy(mPriv->newtonsToSensors, newtons, sizeof(double) * n);
177  }
178  if (amps != nullptr) {
179  memcpy(mPriv->ampereToSensors, amps, sizeof(double) * n);
180  }
181  if (volts != nullptr) {
182  memcpy(mPriv->voltToSensors, volts, sizeof(double) * n);
183  }
184  if (dutycycles != nullptr) {
185  memcpy(mPriv->dutycycleToPWMs, dutycycles, sizeof(double) * n);
186  }
187  if (kbemf != nullptr) {
188  memcpy(mPriv->bemfToRaws, kbemf, sizeof(double) * n);
189  }
190  if (ktau != nullptr) {
191  memcpy(mPriv->ktauToRaws, ktau, sizeof(double) * n);
192  }
193 
194  // invert the axis map
195  memset (mPriv->invAxisMap, 0, sizeof(int) * n);
196  int i;
197  for (i = 0; i < n; i++)
198  {
199  int j;
200  for (j = 0; j < n; j++)
201  {
202  if (mPriv->axisMap[j] == i)
203  {
204  mPriv->invAxisMap[i] = j;
205  break;
206  }
207  }
208  }
209 }
210 
212 {
213  if (mPriv) { delete mPriv; mPriv = nullptr; }
214 }
215 
217 {
218  mPriv = new PrivateUnitsHandler(*other.mPriv);
219 }
220 
222 {
223  mPriv = new PrivateUnitsHandler(*other.mPriv);
224  return *this;
225 }
226 
228 {
229  if( (id >= mPriv->nj) || (id< 0))
230  {
231  return false;
232  }
233  return true;
234 }
235 
236 
237 bool ControlBoardHelper::checkAxesIds(const int n_axes, const int* axesList)
238 {
239  if(n_axes > mPriv->nj)
240  {
241  if (mPriv->verbose) {
242  yError("checkAxesIds: num of axes is too big");
243  }
244  return false;
245  }
246  for(int idx = 0; idx<n_axes; idx++)
247  {
248  if( (axesList[idx]<0) || (axesList[idx]>= mPriv->nj) )
249  {
250  if (mPriv->verbose) {
251  yError("checkAxesIds: joint id out of bound");
252  }
253 
254  return false;
255  }
256  }
257  return true;
258 }
259 
261 { return mPriv->axisMap[axis]; }
262 
264 { return mPriv->invAxisMap[axis]; }
265 
266 //map a vector, no conversion
267  void ControlBoardHelper::toUser(const double *hwData, double *user)
268 {
269  for (int k = 0; k < mPriv->nj; k++) {
270  user[toUser(k)] = hwData[k];
271  }
272 }
273 
274 //map a vector, no conversion
275 void ControlBoardHelper::ControlBoardHelper::toUser(const int *hwData, int *user)
276 {
277  for (int k = 0; k < mPriv->nj; k++) {
278  user[toUser(k)] = hwData[k];
279  }
280 }
281 
282 //map a vector, no conversion
283  void ControlBoardHelper::toHw(const double *usr, double *hwData)
284 {
285  for (int k = 0; k < mPriv->nj; k++) {
286  hwData[toHw(k)] = usr[k];
287  }
288 }
289 
290 //map a vector, no conversion
291 void ControlBoardHelper::toHw(const int *usr, int *hwData)
292 {
293  for (int k = 0; k < mPriv->nj; k++) {
294  hwData[toHw(k)] = usr[k];
295  }
296 }
297 
298 void ControlBoardHelper::posA2E(double ang, int j, double &enc, int &k)
299 {
300  enc=(ang+ mPriv->position_zeros[j])*mPriv->angleToEncoders[j];
301  k=toHw(j);
302 }
303 
304 double ControlBoardHelper::posA2E(double ang, int j)
305 {
306  return (ang+ mPriv->position_zeros[j])*mPriv->angleToEncoders[j];
307 }
308 
309 void ControlBoardHelper::posE2A(double enc, int j, double &ang, int &k)
310 {
311  k=toUser(j);
312 
313  ang=(enc/ mPriv->angleToEncoders[k])- mPriv->position_zeros[k];
314 }
315 
316 double ControlBoardHelper::posE2A(double enc, int j)
317 {
318  int k=toUser(j);
319 
320  return (enc/ mPriv->angleToEncoders[k])- mPriv->position_zeros[k];
321 }
322 
323 void ControlBoardHelper::impN2S(double newtons, int j, double &sens, int &k)
324 {
325  sens=newtons* mPriv->newtonsToSensors[j]/ mPriv->angleToEncoders[j];
326  k=toHw(j);
327 }
328 
329 double ControlBoardHelper::impN2S(double newtons, int j)
330 {
331  return newtons* mPriv->newtonsToSensors[j]/ mPriv->angleToEncoders[j];
332 }
333 
334 void ControlBoardHelper::impN2S(const double *newtons, double *sens)
335 {
336  double tmp;
337  int index;
338  for(int j=0;j<mPriv->nj;j++)
339  {
340  impN2S(newtons[j], j, tmp, index);
341  sens[index]=tmp;
342  }
343 }
344 
345 void ControlBoardHelper::trqN2S(double newtons, int j, double &sens, int &k)
346 {
347  sens=newtons* mPriv->newtonsToSensors[j];
348  k=toHw(j);
349 }
350 
351 double ControlBoardHelper::trqN2S(double newtons, int j)
352 {
353  return newtons* mPriv->newtonsToSensors[j];
354 }
355 
356 //map a vector, convert from newtons to sensors
357 void ControlBoardHelper::trqN2S(const double *newtons, double *sens)
358 {
359  double tmp;
360  int index;
361  for(int j=0;j<mPriv->nj;j++)
362  {
363  trqN2S(newtons[j], j, tmp, index);
364  sens[index]=tmp;
365  }
366 }
367 
368 //map a vector, convert from sensor to newtons
369 void ControlBoardHelper::trqS2N(const double *sens, double *newtons)
370 {
371  double tmp;
372  int index;
373  for(int j=0;j<mPriv->nj;j++)
374  {
375  trqS2N(sens[j], j, tmp, index);
376  newtons[index]=tmp;
377  }
378 }
379 
380 void ControlBoardHelper::trqS2N(double sens, int j, double &newton, int &k)
381 {
382  k=toUser(j);
383  newton=(sens/ mPriv->newtonsToSensors[k]);
384 }
385 
386 double ControlBoardHelper::trqS2N(double sens, int j)
387 {
388  int k=toUser(j);
389  return (sens/ mPriv->newtonsToSensors[k]);
390 }
391 
392 void ControlBoardHelper::impS2N(const double *sens, double *newtons)
393 {
394  double tmp;
395  int index;
396  for(int j=0;j<mPriv->nj;j++)
397  {
398  impS2N(sens[j], j, tmp, index);
399  newtons[index]=tmp;
400  }
401 }
402 
403 void ControlBoardHelper::impS2N(double sens, int j, double &newton, int &k)
404 {
405  k=toUser(j);
406  newton=(sens/ mPriv->newtonsToSensors[k]* mPriv->angleToEncoders[k]);
407 }
408 
409 double ControlBoardHelper::impS2N(double sens, int j)
410 {
411  int k=toUser(j);
412 
413  return (sens/ mPriv->newtonsToSensors[k]* mPriv->angleToEncoders[k]);
414 }
415 
416 void ControlBoardHelper::velA2E(double ang, int j, double &enc, int &k)
417 {
418  k=toHw(j);
419  enc=ang* mPriv->angleToEncoders[j];
420 }
421 
422 double ControlBoardHelper::velA2E(double ang, int j)
423 {
424  return ang* mPriv->angleToEncoders[j];
425 }
426 
427 void ControlBoardHelper::velA2E_abs(double ang, int j, double &enc, int &k)
428 {
429  k=toHw(j);
430  enc=ang*fabs(mPriv->angleToEncoders[j]);
431 }
432 
433 void ControlBoardHelper::velE2A(double enc, int j, double &ang, int &k)
434 {
435  k=toUser(j);
436  ang=enc/ mPriv->angleToEncoders[k];
437 }
438 
439 void ControlBoardHelper::velE2A_abs(double enc, int j, double &ang, int &k)
440 {
441  k=toUser(j);
442  ang=enc/fabs(mPriv->angleToEncoders[k]);
443 }
444 
445 void ControlBoardHelper::accA2E(double ang, int j, double &enc, int &k)
446 {
447  velA2E(ang, j, enc, k);
448 }
449 
450 void ControlBoardHelper::accA2E_abs(double ang, int j, double &enc, int &k)
451 {
452  velA2E_abs(ang, j, enc, k);
453 }
454 
455 void ControlBoardHelper::accE2A(double enc, int j, double &ang, int &k)
456 {
457  velE2A(enc, j, ang, k);
458 }
459 
460 void ControlBoardHelper::accE2A_abs(double enc, int j, double &ang, int &k)
461 {
462  velE2A_abs(enc, j, ang, k);
463 }
464 
465 double ControlBoardHelper::velE2A(double enc, int j)
466 {
467  int k=toUser(j);
468  return enc/ mPriv->angleToEncoders[k];
469 }
470 
471 double ControlBoardHelper::velE2A_abs(double enc, int j)
472 {
473  int k=toUser(j);
474  return enc/fabs(mPriv->angleToEncoders[k]);
475 }
476 
477 
478 double ControlBoardHelper::accE2A(double enc, int j)
479 {
480  return velE2A(enc, j);
481 }
482 
483 double ControlBoardHelper::accE2A_abs(double enc, int j)
484 {
485  return velE2A_abs(enc, j);
486 }
487 
488 //map a vector, convert from angles to encoders
489 void ControlBoardHelper::posA2E(const double *ang, double *enc)
490 {
491  double tmp;
492  int index;
493  for(int j=0;j<mPriv->nj;j++)
494  {
495  posA2E(ang[j], j, tmp, index);
496  enc[index]=tmp;
497  }
498 }
499 
500 //map a vector, convert from encoders to angles
501 void ControlBoardHelper::posE2A(const double *enc, double *ang)
502 {
503  double tmp;
504  int index;
505  for(int j=0;j<mPriv->nj;j++)
506  {
507  posE2A(enc[j], j, tmp, index);
508  ang[index]=tmp;
509  }
510 }
511 
512 void ControlBoardHelper::velA2E(const double *ang, double *enc)
513 {
514  double tmp;
515  int index;
516  for(int j=0;j<mPriv->nj;j++)
517  {
518  velA2E(ang[j], j, tmp, index);
519  enc[index]=tmp;
520  }
521 }
522 
523 void ControlBoardHelper::velA2E_abs(const double *ang, double *enc)
524 {
525  double tmp;
526  int index;
527  for(int j=0;j<mPriv->nj;j++)
528  {
529  velA2E_abs(ang[j], j, tmp, index);
530  enc[index]=tmp;
531  }
532 }
533 
534 void ControlBoardHelper::velE2A(const double *enc, double *ang)
535 {
536  double tmp;
537  int index;
538  for(int j=0;j<mPriv->nj;j++)
539  {
540  velE2A(enc[j], j, tmp, index);
541  ang[index]=tmp;
542  }
543 }
544 
545 void ControlBoardHelper::velE2A_abs(const double *enc, double *ang)
546 {
547  double tmp;
548  int index;
549  for(int j=0;j<mPriv->nj;j++)
550  {
551  velE2A_abs(enc[j], j, tmp, index);
552  ang[index]=tmp;
553  }
554 }
555 
556 void ControlBoardHelper::accA2E(const double *ang, double *enc)
557 {
558  double tmp;
559  int index;
560  for(int j=0;j<mPriv->nj;j++)
561  {
562  accA2E(ang[j], j, tmp, index);
563  enc[index]=tmp;
564  }
565 }
566 
567 void ControlBoardHelper::accA2E_abs(const double *ang, double *enc)
568 {
569  double tmp;
570  int index;
571  for(int j=0;j<mPriv->nj;j++)
572  {
573  accA2E_abs(ang[j], j, tmp, index);
574  enc[index]=tmp;
575  }
576 }
577 
578 void ControlBoardHelper::accE2A(const double *enc, double *ang)
579 {
580  double tmp;
581  int index;
582  for(int j=0;j<mPriv->nj;j++)
583  {
584  accE2A(enc[j], j, tmp, index);
585  ang[index]=tmp;
586  }
587 }
588 
589 void ControlBoardHelper::accE2A_abs(const double *enc, double *ang)
590 {
591  double tmp;
592  int index;
593  for(int j=0;j<mPriv->nj;j++)
594  {
595  accE2A_abs(enc[j], j, tmp, index);
596  ang[index]=tmp;
597  }
598 }
599 
600 //***************** current ******************//
601 void ControlBoardHelper::ampereA2S(double ampere, int j, double &sens, int &k)
602 {
603  sens=ampere* mPriv->ampereToSensors[j];
604  k=toHw(j);
605 }
606 
607 double ControlBoardHelper::ampereA2S(double ampere, int j)
608 {
609  return ampere* mPriv->ampereToSensors[j];
610 }
611 
612 //map a vector, convert from ampere to sensors
613 void ControlBoardHelper::ampereA2S(const double *ampere, double *sens)
614 {
615  double tmp;
616  int index;
617  for(int j=0;j<mPriv->nj;j++)
618  {
619  ampereA2S(ampere[j], j, tmp, index);
620  sens[index]=tmp;
621  }
622 }
623 
624 //map a vector, convert from sensor to ampere
625 void ControlBoardHelper::ampereS2A(const double *sens, double *ampere)
626 {
627  double tmp;
628  int index;
629  for(int j=0;j<mPriv->nj;j++)
630  {
631  ampereS2A(sens[j], j, tmp, index);
632  ampere[index]=tmp;
633  }
634 }
635 
636 void ControlBoardHelper::ampereS2A(double sens, int j, double &ampere, int &k)
637 {
638  k=toUser(j);
639  ampere=(sens/ mPriv->ampereToSensors[k]);
640 }
641 
642 double ControlBoardHelper::ampereS2A(double sens, int j)
643 {
644  int k=toUser(j);
645  return sens/ mPriv->ampereToSensors[k];
646 }
647 // *******************************************//
648 
649 //***************** voltage ******************//
650 void ControlBoardHelper::voltageV2S(double voltage, int j, double &sens, int &k)
651 {
652  sens=voltage* mPriv->voltToSensors[j];
653  k=toHw(j);
654 }
655 
656 double ControlBoardHelper::voltageV2S(double voltage, int j)
657 {
658  return voltage* mPriv->voltToSensors[j];
659 }
660 
661 //map a vector, convert from voltage to sensors
662 void ControlBoardHelper::voltageV2S(const double *voltage, double *sens)
663 {
664  double tmp;
665  int index;
666  for(int j=0;j<mPriv->nj;j++)
667  {
668  voltageV2S(voltage[j], j, tmp, index);
669  sens[index]=tmp;
670  }
671 }
672 
673 //map a vector, convert from sensor to newtons
674 void ControlBoardHelper::voltageS2V(const double *sens, double *voltage)
675 {
676  double tmp;
677  int index;
678  for(int j=0;j<mPriv->nj;j++)
679  {
680  voltageS2V(sens[j], j, tmp, index);
681  voltage[index]=tmp;
682  }
683 }
684 
685 void ControlBoardHelper::voltageS2V(double sens, int j, double &voltage, int &k)
686 {
687  k=toUser(j);
688  voltage=(sens/ mPriv->voltToSensors[k]);
689 }
690 
691 double ControlBoardHelper::voltageS2V(double sens, int j)
692 {
693  int k=toUser(j);
694  return (sens/ mPriv->voltToSensors[k]);
695 }
696 // *******************************************//
697 
698 //***************** dutycycle ******************//
699 void ControlBoardHelper::dutycycle2PWM(double dutycycle, int j, double &pwm, int &k)
700 {
701  pwm = dutycycle* mPriv->dutycycleToPWMs[j];
702  k = toHw(j);
703 }
704 
705 double ControlBoardHelper::dutycycle2PWM(double dutycycle, int j)
706 {
707  return dutycycle* mPriv->dutycycleToPWMs[j];
708 }
709 
710 void ControlBoardHelper::dutycycle2PWM(const double *dutycycle, double *sens)
711 {
712  double tmp;
713  int index;
714  for (int j = 0; j<mPriv->nj; j++)
715  {
716  dutycycle2PWM(dutycycle[j], j, tmp, index);
717  sens[index] = tmp;
718  }
719 }
720 
721 void ControlBoardHelper::PWM2dutycycle(const double *pwm, double *dutycycle)
722 {
723  double tmp;
724  int index;
725  for (int j = 0; j<mPriv->nj; j++)
726  {
727  PWM2dutycycle(pwm[j], j, tmp, index);
728  dutycycle[index] = tmp;
729  }
730 }
731 
732 void ControlBoardHelper::PWM2dutycycle(double pwm_raw, int k_raw, double &dutycycle, int &j)
733 {
734  j = toUser(k_raw);
735  dutycycle = (pwm_raw / mPriv->dutycycleToPWMs[j]);
736 }
737 
738 double ControlBoardHelper::PWM2dutycycle(double pwm_raw, int k_raw)
739 {
740  int j = toUser(k_raw);
741  return (pwm_raw / mPriv->dutycycleToPWMs[j]);
742 }
743 
744 // *******************************************//
745 void ControlBoardHelper::bemf_user2raw(double bemf_user, int j, double &bemf_raw, int &k)
746 {
747  bemf_raw = bemf_user * mPriv->bemfToRaws[j];
748  k = toHw(j);
749 }
750 
751 void ControlBoardHelper::ktau_user2raw(double ktau_user, int j, double &ktau_raw, int &k)
752 {
753  ktau_raw = ktau_user * mPriv->ktauToRaws[j];
754  k = toHw(j);
755 }
756 
757 void ControlBoardHelper::bemf_raw2user(double bemf_raw, int k_raw, double &bemf_user, int &j_user)
758 {
759  j_user = toUser(k_raw);
760  bemf_user = bemf_raw / mPriv->bemfToRaws[j_user];
761 }
762 
763 void ControlBoardHelper::ktau_raw2user(double ktau_raw, int k_raw, double &ktau_user, int &j_user)
764 {
765  j_user = toUser(k_raw);
766  ktau_user = ktau_raw / mPriv->ktauToRaws[j_user];
767 }
768 
769 double ControlBoardHelper::bemf_user2raw(double bemf_user, int j)
770 {
771  return bemf_user * mPriv->bemfToRaws[j];
772 }
773 
774 double ControlBoardHelper::ktau_user2raw(double ktau_user, int j)
775 {
776  return ktau_user * mPriv->ktauToRaws[j];
777 }
778 
779 // *******************************************//
780 
782 { return mPriv->nj; }
783 
784 // *******************************************//
785 
787 {
788  double output_conversion_factor;
789  switch (mPriv->pid_units[pidtype][j].out_units)
790  {
791  case PidOutputUnitsEnum::DUTYCYCLE_PWM_PERCENT: output_conversion_factor = mPriv->dutycycleToPWMs[j]; break;
792  case PidOutputUnitsEnum::CURRENT_METRIC: output_conversion_factor = mPriv->ampereToSensors[j]; break;
793  case PidOutputUnitsEnum::POSITION_METRIC: output_conversion_factor = mPriv->angleToEncoders[j]; break;
794  case PidOutputUnitsEnum::VELOCITY_METRIC: output_conversion_factor = mPriv->angleToEncoders[j]; break;
795  case PidOutputUnitsEnum::TORQUE_METRIC: output_conversion_factor = mPriv->newtonsToSensors[j]; break;
797  default: output_conversion_factor = mPriv->helper_ones[j]; break;
798  }
799  return output_conversion_factor;
800 }
801 
803 {
804  double feedback_conversion_factor = 0.0;
805  switch (mPriv->pid_units[pidtype][j].fbk_units)
806  {
808  switch (pidtype)
809  {
810  case yarp::dev::PidControlTypeEnum::VOCAB_PIDTYPE_POSITION: feedback_conversion_factor = mPriv->angleToEncoders[j]; break;
811  case yarp::dev::PidControlTypeEnum::VOCAB_PIDTYPE_VELOCITY: feedback_conversion_factor = mPriv->angleToEncoders[j]; break;
812  case yarp::dev::PidControlTypeEnum::VOCAB_PIDTYPE_TORQUE: feedback_conversion_factor = mPriv->newtonsToSensors[j]; break;
813  case yarp::dev::PidControlTypeEnum::VOCAB_PIDTYPE_CURRENT: feedback_conversion_factor = mPriv->ampereToSensors[j]; break;
814  }
815  break;
817  default: feedback_conversion_factor = mPriv->helper_ones[j]; break;
818  }
819  return (1.0 / feedback_conversion_factor);
820 }
821 void ControlBoardHelper::convert_pid_to_user(const yarp::dev::PidControlTypeEnum& pidtype, const Pid &in_raw, int j_raw, Pid &out_usr, int &k_usr)
822 {
823  ControlBoardHelper* cb_helper = this;
824  k_usr = cb_helper->toUser(j_raw);
825  out_usr = in_raw;
826 
827  //feedback is at the denominator, i.e. kp=[PWM/deg]
828  double feedback_conversion_units_user2raw = get_pidfeedback_conversion_factor_user2raw(pidtype, k_usr);
829  out_usr.kp = out_usr.kp / feedback_conversion_units_user2raw;
830  out_usr.ki = out_usr.ki / feedback_conversion_units_user2raw;
831  out_usr.kd = out_usr.kd / feedback_conversion_units_user2raw;
832 
833  //output is at the numerator, i.e. kp=[PWM/deg]
834  double output_conversion_units_user2raw = get_pidoutput_conversion_factor_user2raw(pidtype, k_usr);
835  out_usr.kp = out_usr.kp / output_conversion_units_user2raw;
836  out_usr.ki = out_usr.ki / output_conversion_units_user2raw;
837  out_usr.kd = out_usr.kd / output_conversion_units_user2raw;
838  out_usr.max_output = out_usr.max_output / output_conversion_units_user2raw;
839  out_usr.max_int = out_usr.max_int / output_conversion_units_user2raw;
840  out_usr.stiction_up_val = out_usr.stiction_up_val / output_conversion_units_user2raw;
841  out_usr.stiction_down_val = out_usr.stiction_down_val / output_conversion_units_user2raw;
842  out_usr.offset = out_usr.offset / output_conversion_units_user2raw;
843 }
844 
846 {
847  Pid tmp;
848  int tmp_k;
849  convert_pid_to_machine(pidtype, in_usr, j_usr, tmp, tmp_k);
850  return tmp;
851 }
852 
853 void ControlBoardHelper::convert_pid_to_machine(const yarp::dev::PidControlTypeEnum& pidtype, const Pid &in_usr, int j_usr, Pid &out_raw, int &k_raw)
854 {
855  ControlBoardHelper* cb_helper = this;
856  k_raw = cb_helper->toHw(j_usr);
857  out_raw = in_usr;
858 
859  //feedback is at the denominator, i.e. kp=[PWM/deg]
860  double feedback_conversion_units_user2raw = get_pidfeedback_conversion_factor_user2raw(pidtype, j_usr);
861  out_raw.kp = out_raw.kp * feedback_conversion_units_user2raw;
862  out_raw.ki = out_raw.ki * feedback_conversion_units_user2raw;
863  out_raw.kd = out_raw.kd * feedback_conversion_units_user2raw;
864 
865  //output is at the numerator, i.e. kp=[PWM/deg]
866  double output_conversion_units_user2raw = get_pidoutput_conversion_factor_user2raw(pidtype, j_usr);
867  out_raw.kp = out_raw.kp * output_conversion_units_user2raw;
868  out_raw.ki = out_raw.ki * output_conversion_units_user2raw;
869  out_raw.kd = out_raw.kd * output_conversion_units_user2raw;
870  out_raw.max_output = out_raw.max_output * output_conversion_units_user2raw;
871  out_raw.max_int = out_raw.max_int * output_conversion_units_user2raw;
872  out_raw.stiction_up_val = out_raw.stiction_up_val * output_conversion_units_user2raw;
873  out_raw.stiction_down_val = out_raw.stiction_down_val * output_conversion_units_user2raw;
874  out_raw.offset = out_raw.offset * output_conversion_units_user2raw;
875 }
876 
877 void ControlBoardHelper::convert_pidunits_to_machine(const yarp::dev::PidControlTypeEnum& pidtype, double userval, int j, double &machineval, int &k)
878 {
879  ControlBoardHelper* cb_helper = this;
880  switch (pidtype)
881  {
883  //Beware:posA2E employs zeros, not only angleToEncoders
884  //This is fine if convert_pidunits_to_machine() is called by methods that are aware of this feature, that is intentional.
885  cb_helper->posA2E(userval, j, machineval, k);
886  break;
888  cb_helper->velA2E(userval, j, machineval, k);
889  break;
891  cb_helper->trqN2S(userval, j, machineval, k);
892  break;
894  cb_helper->ampereA2S(userval, j, machineval, k);
895  break;
896  default:
897  yError() << "convert_units_to_machine: invalid pidtype";
898  break;
899  }
900 }
901 
902 void ControlBoardHelper::convert_pidunits_to_machine(const yarp::dev::PidControlTypeEnum& pidtype, const double* userval, double* machineval)
903 {
904  ControlBoardHelper* cb_helper = this;
905  switch (pidtype)
906  {
908  //Beware:posA2E employs zeros, not only angleToEncoders
909  //This is fine if convert_pidunits_to_machine() is called by methods that are aware of this feature, that is intentional.
910  cb_helper->posA2E(userval, machineval);
911  break;
913  cb_helper->velA2E(userval, machineval);
914  break;
916  cb_helper->trqN2S(userval, machineval);
917  break;
919  cb_helper->ampereA2S(userval, machineval);
920  break;
921  default:
922  yError() << "convert_units_to_machine: invalid pidtype";
923  break;
924  }
925 }
926 
927 void ControlBoardHelper::convert_pidunits_to_user(const yarp::dev::PidControlTypeEnum& pidtype, const double machineval, double* userval, int k)
928 {
929  ControlBoardHelper* cb_helper = this;
930  switch (pidtype)
931  {
933  //Beware:posE2A employs zeros, not only angleToEncoders.
934  //This is fine if convert_pidunits_to_user() is called by methods that are aware of this feature, that is intentional.
935  *userval = cb_helper->posE2A(machineval, k);
936  break;
938  *userval = cb_helper->velE2A(machineval, k);
939  break;
941  *userval = cb_helper->trqS2N(machineval, k);
942  break;
944  *userval = cb_helper->ampereS2A(machineval, k);
945  break;
946  default:
947  yError() << "convert_units_to_machine: invalid pidtype";
948  break;
949  }
950 }
951 
952 void ControlBoardHelper::convert_pidunits_to_user(const yarp::dev::PidControlTypeEnum& pidtype, const double* machineval, double* userval)
953 {
954  ControlBoardHelper* cb_helper = this;
955  switch (pidtype)
956  {
958  //Beware:posE2A employs zeros, not only angleToEncoders.
959  //This is fine if convert_pidunits_to_user() is called by methods that are aware of this feature, that is intentional.
960  cb_helper->posE2A(machineval, userval);
961  break;
963  cb_helper->velE2A(machineval, userval);
964  break;
966  cb_helper->trqS2N(machineval, userval);
967  break;
969  cb_helper->ampereS2A(machineval, userval);
970  break;
971  default:
972  yError() << "convert_units_to_machine: invalid pidtype";
973  break;
974  }
975 }
976 
977 void ControlBoardHelper::set_pid_conversion_units(const PidControlTypeEnum& pidtype, const PidFeedbackUnitsEnum fbk_conv_units, const PidOutputUnitsEnum out_conv_units)
978 {
979  ControlBoardHelper* cb_helper = this;
980  int nj = cb_helper->axes();
981  for (int i = 0; i < nj; i++)
982  {
983  mPriv->pid_units[pidtype][i].fbk_units = fbk_conv_units;
984  mPriv->pid_units[pidtype][i].out_units = out_conv_units;
985  }
986 }
void checkAndDestroy(T *&p)
#define yError(...)
Definition: Log.h:279
#define yAssert(x)
Definition: Log.h:294
PrivateUnitsHandler(const PrivateUnitsHandler &other)
std::map< PidControlTypeEnum, PidUnits * > pid_units
double get_pidfeedback_conversion_factor_user2raw(const yarp::dev::PidControlTypeEnum &pidtype, int j)
void accE2A(double enc, int j, double &ang, int &k)
void convert_pid_to_user(const yarp::dev::PidControlTypeEnum &pidtype, const Pid &in_raw, int j_raw, Pid &out_usr, int &k_usr)
void ktau_raw2user(double ktau_raw, int k_raw, double &ktau_user, int &j_user)
void trqN2S(double newtons, int j, double &sens, int &k)
void velE2A_abs(double enc, int j, double &ang, int &k)
void convert_pidunits_to_machine(const yarp::dev::PidControlTypeEnum &pidtype, double userval, int j, double &machineval, int &k)
void bemf_raw2user(double bemf_raw, int k_raw, double &bemf_user, int &j_user)
void voltageS2V(const double *sens, double *voltage)
void convert_pid_to_machine(const yarp::dev::PidControlTypeEnum &pidtype, const Pid &in_usr, int j_usr, Pid &out_raw, int &k_raw)
void ampereA2S(double ampere, int j, double &sens, int &k)
void impN2S(double newtons, int j, double &sens, int &k)
double ktau_user2raw(double ktau_user, int j)
void velE2A(double enc, int j, double &ang, int &k)
void velA2E(double ang, int j, double &enc, int &k)
void dutycycle2PWM(double dutycycle, int j, double &pwm, int &k)
void ampereS2A(const double *sens, double *ampere)
void posE2A(double enc, int j, double &ang, int &k)
void trqS2N(const double *sens, double *newtons)
double get_pidoutput_conversion_factor_user2raw(const yarp::dev::PidControlTypeEnum &pidtype, int j)
void set_pid_conversion_units(const PidControlTypeEnum &pidtype, const PidFeedbackUnitsEnum fbk_conv_units, const PidOutputUnitsEnum out_conv_units)
void voltageV2S(double voltage, int j, double &sens, int &k)
ControlBoardHelper & operator=(const ControlBoardHelper &other)
double bemf_user2raw(double bemf_user, int j)
void accA2E_abs(double ang, int j, double &enc, int &k)
void accA2E(double ang, int j, double &enc, int &k)
void accE2A_abs(double enc, int j, double &ang, int &k)
void velA2E_abs(double ang, int j, double &enc, int &k)
ControlBoardHelper(int n, const int *aMap, const double *angToEncs=nullptr, const double *zs=nullptr, const double *newtons=nullptr, const double *amps=nullptr, const double *volts=nullptr, const double *dutycycles=nullptr, const double *kbemf=nullptr, const double *ktau=nullptr)
void convert_pidunits_to_user(const yarp::dev::PidControlTypeEnum &pidtype, const double machineval, double *userval, int k)
void impS2N(const double *sens, double *newtons)
void PWM2dutycycle(const double *pwm, double *dutycycle)
bool checkAxesIds(const int n_axes, const int *axesList)
void posA2E(double ang, int j, double &enc, int &k)
Contains the parameters for a PID.
double kd
derivative gain
double offset
pwm offset added to the pid output
double stiction_down_val
down stiction offset added to the pid output
double stiction_up_val
up stiction offset added to the pid output
double max_output
max output
double ki
integrative gain
double max_int
saturation threshold for the integrator
double kp
proportional gain
An interface for the device drivers.
PidOutputUnitsEnum
Definition: PidEnums.h:34
PidControlTypeEnum
Definition: PidEnums.h:18
@ VOCAB_PIDTYPE_TORQUE
Definition: PidEnums.h:21
@ VOCAB_PIDTYPE_VELOCITY
Definition: PidEnums.h:20
@ VOCAB_PIDTYPE_POSITION
Definition: PidEnums.h:19
@ VOCAB_PIDTYPE_CURRENT
Definition: PidEnums.h:22
PidFeedbackUnitsEnum
Definition: PidEnums.h:28
PidOutputUnitsEnum out_units
PidFeedbackUnitsEnum fbk_units