SPIDAR API Library  0x16033101
Space Interface Device for Artificial Reality
SpidarSystem.hpp
Go to the documentation of this file.
1 
5 #ifndef SPIDAR_SYSTEM_HPP
6 #define SPIDAR_SYSTEM_HPP
7 
8 #include <cstdint>
9 
10 namespace Spidar
11 {
12 namespace Core
13 {
19 template <class T>
21 {
22 public:
23  typedef T TraitsType;
24 
25  static const size_t MOTOR_COUNT = TraitsType::MOTOR_COUNT;
26 
27  typedef typename TraitsType::SpecType SpecType;
28  typedef typename TraitsType::ControllerType ControllerType;
29 
30  typedef typename TraitsType::ValueType ValueType;
31  typedef typename TraitsType::VectorType VectorType;
32  typedef typename TraitsType::QuaternionType QuaternionType;
33  typedef typename TraitsType::PoseType PoseType;
34 
35  typedef typename TraitsType::ModelType ModelType;
36  typedef typename TraitsType::PoseEstimationType PoseEstimationType;
37  typedef typename TraitsType::ForceDecompositionType ForceDecompositionType;
38 
39  typedef typename TraitsType::LogDataType LogDataType;
40  typedef typename TraitsType::DataLoggerType DataLoggerType;
41  typedef typename TraitsType::TimerType TimerType;
42  typedef typename TraitsType::ThreadType ThreadType;
43 
44  SpidarSystem(void);
45  ~SpidarSystem(void);
46 
48  double deltaTime(void) const { return timer_.avgDeltaTime(); }
49 
51  ValueType gripRadius(void) const { return estimator_.gripRadius(); }
52 
54  ValueType cascadeGain(void) const { return cascadeGain_; }
55 
57  VectorType targetForce(void) const { return targetForce_; }
58 
60  VectorType targetTorque(void) const { return targetTorque_; }
61 
63  VectorType resultantForce(void) const { return resultantForce_; }
64 
66  VectorType resultantTorque(void) const { return resultantTorque_; }
67 
68  bool initialize(const SpecType& spec);
69  bool terminate(void);
70 
71  void setHaptics(bool enable);
72  void setCascadeGain(ValueType gain);
73 
74  void start(void);
75  void stop(void);
76  void calibrate(void);
77 
78  void gripPose(VectorType& position, QuaternionType& rotation,
79  VectorType& velocity, VectorType& angularVelocity) const;
80 
81  bool setForce(const VectorType& force, ValueType forceK, ValueType forceB,
82  const VectorType& torque, ValueType torqueK, ValueType torqueB,
83  bool lerp, bool cascade = false);
84 
85  void encoderCount(int32_t(&count)[MOTOR_COUNT]) const;
86 
87  uint32_t gpioValue(void) const;
88 
89  void startLog(void);
90 
91 private:
92  void majorLoop(void);
93 
94  static void threadFunc(void* param);
95 
96  void outputLog(const std::string& filename);
97 
98  //
99  ControllerType controller_;
100  ModelType model_;
101 
102  PoseEstimationType estimator_;
103  ForceDecompositionType decomposer_;
104 
105  DataLoggerType dataLogger_;
106  TimerType timer_;
107  ThreadType* thread_;
108 
109  bool initialized_;
110  bool haptics_;
111  bool cascadeControl_;
112  bool kill_;
113  bool calibrate_;
114  bool clearEncoder_;
115 
116  int32_t encoderCount_[MOTOR_COUNT];
117 
118  ValueType cascadeGain_;
119  ValueType cascadeSpringK_;
120 
122  ValueType springKToPulseRatio_[MOTOR_COUNT];
123 
124  uint16_t cascadeRatioKB_;
125 
126  int16_t velocityGain_[MOTOR_COUNT];
127 
128  uint16_t velocityFilterGain_;
129 
130  uint16_t forceFilterGain_;
131 
132  uint16_t pulseWidthLimit_[MOTOR_COUNT];
133 
134  VectorType targetForce_;
135  VectorType targetTorque_;
136 
137  VectorType resultantForce_;
138  VectorType resultantTorque_;
139 
140 }; // end of class SpidarSystem.
141 
146 template <class T>
147 SpidarSystem<T>::SpidarSystem(void) : thread_(nullptr), kill_(true), calibrate_(false), clearEncoder_(false),
148 initialized_(false), haptics_(false), cascadeControl_(false), cascadeGain_(1), cascadeSpringK_(0), cascadeRatioKB_(0)
149 {
150 }
151 
156 template <class T>
158 {
159  terminate();
160 }
161 
166 template <class T>
168 {
169  // すでに初期化済みの場合,一度終了処理を行う
170  if (initialized_)
171  {
172  if (!terminate()) return false;
173  }
174 
175  // 初期状態の設定
176  kill_ = true;
177 
178  // コントローラの初期化
179  if (!controller_.initialize(spec.serialNumber)) return false;
180 
181  // メンバの初期化
182  if (!estimator_.initialize(spec, controller_.controlFrequency())) return false;
183  if (!decomposer_.initialize(spec)) return false;
184 
185  // コントローラ内速度補償ゲインの設定
186  for (size_t i = 0; i < MOTOR_COUNT; ++i)
187  {
188  if (spec.speedConstant[i] == 0)
189  {
190  velocityGain_[i] = 0;
191  }
192  else
193  {
194  double dutyPerVoltage = controller_.maxPulseWidth() / spec.terminalVoltage[i];
195  double pulsePerSecond = spec.encoderResolution[i] * spec.speedConstant[i] / 60;
196 
197  double value = controller_.cascadeFrequency() * dutyPerVoltage / pulsePerSecond;
198 
199  velocityGain_[i] = static_cast<int16_t>(-value * spec.encoderDirection[i]);
200  }
201  }
202 
203  velocityFilterGain_ = static_cast<uint16_t>(spec.minorLoopVelocityFilterGain);
204 
205  // コントローラ内提示力制限の設定
206  for (size_t i = 0; i < MOTOR_COUNT; ++i)
207  {
208  double pulseWidthLimit = decomposer_.tensionToDuty(i) * decomposer_.maxTension(i) * controller_.maxPulseWidth();
209  pulseWidthLimit_[i] = static_cast<uint16_t>(pulseWidthLimit);
210  }
211 
212  // カスケード制御ゲインの設定
213  const double PI = 3.14159265358979323846;
214 
215  for (size_t i = 0; i < MOTOR_COUNT; ++i)
216  {
217  double lengthPerCount = spec.pulleyRadius[i] * 2.0 * PI / spec.encoderResolution[i];
218 
219  double maxCurrent = spec.terminalVoltage[i] / spec.terminalResistance[i];
220 
221  double maxTension = spec.torqueConstant[i] / spec.pulleyRadius[i] * maxCurrent;
222 
223  double pulseWidthPerNewton = controller_.maxPulseWidth() / maxTension;
224 
225  springKToPulseRatio_[i] = static_cast<ValueType>(pulseWidthPerNewton * lengthPerCount * spec.encoderDirection[i]);
226  }
227 
228  forceFilterGain_ = static_cast<uint16_t>(spec.minorLoopForceFilterGain);
229 
230  // システムの初期化完了
231  initialized_ = true;
232 
233  return true;
234 }
235 
240 template <class T>
242 {
243  if (!initialized_) return true;
244 
245  // 動作中の場合は停止
246  if (!kill_) stop();
247 
248  // コントローラの終了
249  if (!controller_.terminate()) return false;
250 
251  initialized_ = false;
252 
253  return true;
254 }
255 
263 template <class T>
265 {
266  haptics_ = enable;
267 }
268 
275 template <class T>
277 {
278  cascadeGain_ = gain;
279 }
280 
286 template <class T>
288 {
289  if (!initialized_ || thread_) return;
290 
291  kill_ = false;
292 
293  thread_ = new ThreadType(threadFunc, static_cast<void*>(this));
294 }
295 
301 template <class T>
303 {
304  if (!initialized_ || !thread_) return;
305 
306  kill_ = true;
307 
308  thread_->join();
309 
310  delete thread_;
311 
312  thread_ = nullptr;
313 
314  outputLog("C:/SPIDAR/log.txt");
315 }
316 
321 template <class T>
323 {
324  if (!initialized_ || kill_) return;
325 
326  clearEncoder_ = true;
327  calibrate_ = true;
328 }
329 
339 template <class T>
341  VectorType& velocity, VectorType& angularVelocity) const
342 {
343  if (!initialized_) return;
344 
345  position = estimator_.pose().position;
346  rotation = estimator_.pose().rotation;
347  velocity = estimator_.pose().velocity;
348  angularVelocity = estimator_.pose().angularVelocity;
349 }
350 
365 template <class T>
366 bool SpidarSystem<T>::setForce(const VectorType& force, ValueType forceK, ValueType forceB,
367  const VectorType& torque, ValueType torqueK, ValueType torqueB, bool lerp, bool cascade)
368 {
369  if (!initialized_) return false;
370 
371  model_.setParameter(forceK, forceB, torqueK, torqueB);
372  model_.setOrigin(estimator_.pose(), force, torque, lerp);
373 
374  cascadeControl_ = cascade;
375  cascadeSpringK_ = forceK;
376 
377  if (forceB == 0) cascadeRatioKB_ = 0;
378  else cascadeRatioKB_ = static_cast<uint16_t>(forceK / forceB);
379 
380  return true;
381 }
382 
389 template <class T>
390 void SpidarSystem<T>::encoderCount(int32_t(&count)[MOTOR_COUNT]) const
391 {
392  if (!initialized_) return;
393 
394  for (size_t i = 0; i < MOTOR_COUNT; ++i) count[i] = encoderCount_[i];
395 }
396 
403 template <class T>
404 uint32_t SpidarSystem<T>::gpioValue(void) const
405 {
406  if (!initialized_) return 0;
407 
408  return controller_.gpioValue();
409 }
410 
411 //
412 //
413 // 以下プライベート関数
414 //
415 //
416 
421 template <class T>
423 {
424  int32_t count[8];
425  double duty[8];
426 
427  // force time limit
428  size_t forceCount = 0;
429 
430  const size_t collisionThreshold = static_cast<const size_t>(1000 * decomposer_.maxDuration());
431 
432  const size_t maxCollisionCount = collisionThreshold + 1000;
433 
434  // log
435  LogDataType log;
436 
437  // コントローラのオフライン設定
438  controller_.writePulseWidthLimit(pulseWidthLimit_);
439  controller_.writeVelocityGain(velocityGain_);
440  controller_.writeVelocityFilterGain(velocityFilterGain_);
441  controller_.writeForceFilterGain(forceFilterGain_);
442 
443  // エンコーダ値のクリア
444  for (size_t i = 0; i < MOTOR_COUNT; ++i) encoderCount_[i] = 0;
445 
446  // バネダンパモデルの初期化
447  model_.clear();
448  model_.setFrequency(static_cast<ValueType>(controller_.controlFrequency()), 60);
449 
450  // 最初のキャリブーション用設定
451  calibrate_ = true;
452  clearEncoder_ = true;
453  size_t clearEncoderCount = 0;
454 
455  // コントローラの有効化
456  controller_.enableMotorControl();
457 
458  // コントローラの制御周波数でタイマーを初期化
459  timer_.initialize(controller_.controlFrequency());
460 
461  // main loop
462  while (!kill_)
463  {
464  // 安全のため提示力の計算にはゼロクリアから始めるローカル変数を使用する
465  VectorType force = VectorType(), torque = VectorType();
466 
467  resultantForce_ = targetForce_ = force;
468  resultantTorque_ = targetTorque_ = torque;
469 
470  // キャリブレーション
471  if (calibrate_)
472  {
473  if (clearEncoder_)
474  {
475  controller_.clearEncoderCount();
476  controller_.readEncoderCount(count);
477  clearEncoder_ = false;
478  }
479  else
480  {
481  if (clearEncoderCount < 10)
482  {
483  controller_.readEncoderCount(count);
484  ++clearEncoderCount;
485  }
486  else
487  {
488  clearEncoderCount = 0;
489  controller_.readEncoderCount(count);
490  estimator_.calibrate(count);
491  forceCount = 0;
492  calibrate_ = false;
493  }
494  }
495  }
496  else
497  {
498  // エンコーダ値の読み込み
499  controller_.readEncoderCount(count);
500 
501  for (size_t i = 0; i < MOTOR_COUNT; ++i) encoderCount_[i] = count[i];
502 
503  // グリップ位置,姿勢の更新
504  estimator_.estimate(count);
505 
506  //
507  // 提示力の計算
508  //
509 
510  // 提示力の目標値をバネダンパモデルにより補間計算
511  model_.calcModel(estimator_.pose(), force, torque);
512 
513  if (force.norm() != 0 || torque.norm() != 0)
514  {
515  // モータ出力の時間制限(安全のため)
516  if (forceCount < maxCollisionCount) ++forceCount;
517 
518  if (forceCount > collisionThreshold)
519  {
520  float temp = 0.001f * (forceCount - collisionThreshold);
521 
522  force *= (1.0f - temp);
523  torque *= (1.0f - temp);
524  }
525  }
526  else
527  {
528  forceCount = 0;
529  }
530 
531  // 提示力の目標値の記録
532  targetForce_ = force;
533  targetTorque_ = torque;
534 
535  //
536  // 張力分配
537  //
538  // 力覚提示OFFの場合:提示力の目標値は保存したまま,張力分配の入力はクリア
539  if (haptics_ && forceCount != 0) decomposer_.decompose(estimator_.wireVector(), force, torque);
540  else decomposer_.decompose(estimator_.wireVector(), VectorType(), VectorType());
541 
542  // 各モータの張力を合成した実際の提示力を保存
543  resultantForce_ = decomposer_.force();
544  resultantTorque_ = decomposer_.torque();
545  }
546 
547  // 張力をデューティー比に変換
548  if (!haptics_ || forceCount == 0)
549  {
550  for (size_t i = 0; i<MOTOR_COUNT; ++i)
551  {
552  double temp = (decomposer_.minTension(i) - decomposer_.springTension(i)) * decomposer_.tensionToDuty(i);
553  duty[i] = static_cast<ValueType>(temp);
554  }
555  }
556  else
557  {
558  for (size_t i = 0; i<MOTOR_COUNT; ++i)
559  {
560  double temp = (decomposer_.wireTension(i) - decomposer_.springTension(i)) * decomposer_.tensionToDuty(i);
561  duty[i] = static_cast<ValueType>(temp);
562  }
563  }
564 
565  // コントローラから出力
566  if (!cascadeControl_)
567  {
568  controller_.writeDutyCycle(duty);
569  }
570  else
571  {
572  int16_t springK[8];
573 
574  for (size_t i = 0; i < MOTOR_COUNT; ++i)
575  {
576  springK[i] = static_cast<int32_t>(springKToPulseRatio_[i] * cascadeGain_ * cascadeSpringK_);
577  }
578 
579  controller_.writeDutyCycle(duty, springK, cascadeRatioKB_);
580  }
581 
582  // ログ
583  if (dataLogger_.started())
584  {
585  //
586  log.position = estimator_.pose().position;
587  log.velocity = estimator_.pose().velocity;
588 
589  log.targetForce = targetForce_;
590  log.resultantForce = resultantForce_;
591 
592  //
593  log.rotation = estimator_.pose().rotation;
594  log.angularVelocity = estimator_.pose().angularVelocity;
595  log.targetTorque = targetTorque_;
596  log.resultantTorque = resultantTorque_;
597 
598  for (size_t i = 0; i < MOTOR_COUNT; ++i)
599  {
600  log.tension[i] = decomposer_.wireTension(i);
601  }
602  dataLogger_.add(log);
603  }
604 
605  // busy waiting
606  timer_.wait();
607 
608  } // end of while (!kill)
609 
610  for (size_t i = 0; i<MOTOR_COUNT; ++i) duty[i] = 0;
611 
612  controller_.writeDutyCycle(duty);
613 
614  // コントローラの無効化
615  controller_.disableMotorControl();
616 }
617 
622 template <class T>
623 void SpidarSystem<T>::threadFunc(void* param)
624 {
625  SpidarSystem<T>* system = static_cast<SpidarSystem<T>*>(param);
626 
627  system->majorLoop();
628 }
629 
633 template <class T>
635 {
636  dataLogger_.start();
637 }
638 
644 template <class T>
645 void SpidarSystem<T>::outputLog(const std::string& filename)
646 {
647  if (!kill_) return;
648 
649  if (dataLogger_.started()) dataLogger_.output(filename);
650 }
651 
652 } // end of namespace Core.
653 } // end of namespace Spidar.
654 
655 #endif // SPIDAR_SYSTEM_HPP
656 
657 // end of file.
void gripPose(VectorType &position, QuaternionType &rotation, VectorType &velocity, VectorType &angularVelocity) const
グリップの姿勢を取得します.
void startLog(void)
ログの記録を開始します.
TraitsType::ThreadType ThreadType
スレッドの型
TraitsType::PoseType PoseType
グリップ姿勢の型
void encoderCount(int32_t(&count)[MOTOR_COUNT]) const
エンコーダ値を取得します.
double deltaTime(void) const
更新時間間隔を取得します.
bool terminate(void)
システムを終了します.
TraitsType::ValueType ValueType
値の型
ValueType cascadeGain(void) const
カスケード制御のマイナーループのゲインを取得します.
void calibrate(void)
グリップ姿勢のキャリブレーションを行います.
SPIDARライブラリのルート名前空間です.
TraitsType::QuaternionType QuaternionType
四元数の型
VectorType resultantForce(void) const
並進力の出力値を取得します.
VectorType targetForce(void) const
並進力の目標値を取得します.
~SpidarSystem(void)
デストラクタ.
T TraitsType
Traitsクラス
static const size_t MOTOR_COUNT
モータの数(=ワイヤの本数)
VectorType targetTorque(void) const
回転力の目標値を取得します.
void setHaptics(bool enable)
力提示のON/OFFを設定します.
TraitsType::PoseEstimationType PoseEstimationType
姿勢推定オブジェクトの型
uint32_t gpioValue(void) const
GPIOの値を取得します.
TraitsType::TimerType TimerType
タイマーの型
TraitsType::DataLoggerType DataLoggerType
データロガーの型
TraitsType::VectorType VectorType
ベクトルの型
SpidarSystem(void)
コンストラクタ.
ValueType gripRadius(void) const
グリップ半径を取得します.
TraitsType::ControllerType ControllerType
コントローラの型
void start(void)
システムの動作を開始します.
SPIDARシステムクラスです.
bool initialize(const SpecType &spec)
システムを初期化します.
VectorType resultantTorque(void) const
回転力の出力値を取得します.
TraitsType::ForceDecompositionType ForceDecompositionType
張力分配オブジェクトの型
bool setForce(const VectorType &force, ValueType forceK, ValueType forceB, const VectorType &torque, ValueType torqueK, ValueType torqueB, bool lerp, bool cascade=false)
提示力の目標値を設定します.
TraitsType::LogDataType LogDataType
ログデータの型
TraitsType::ModelType ModelType
バネダンパモデルの型
TraitsType::SpecType SpecType
デバイス情報の型
void setCascadeGain(ValueType gain)
カスケード制御用ゲインを設定します.
void stop(void)
システムの動作を停止します.