MicroMouse Control Module  v1.3.2-2-ge2c6882
accel_curve.h
[詳解]
1 
9 #pragma once
10 
11 #include <array>
12 #include <cmath> //< for std::sqrt, std::cbrt
13 #include <iostream> //< for std::cout
14 #include <ostream>
15 
16 /* log level definition */
17 #define CTRL_LOG_LEVEL_NONE 0
18 #define CTRL_LOG_LEVEL_ERROR 1
19 #define CTRL_LOG_LEVEL_WARNING 2
20 #define CTRL_LOG_LEVEL_INFO 3
21 #define CTRL_LOG_LEVEL_DEBUG 4
22 /* set log level */
23 #ifndef CTRL_LOG_LEVEL
24 #define CTRL_LOG_LEVEL CTRL_LOG_LEVEL_WARNING
25 #endif
26 /* Log Error */
27 #if CTRL_LOG_LEVEL >= CTRL_LOG_LEVEL_ERROR
28 #define ctrl_loge (std::cout << "[E][" __FILE__ ":" << __LINE__ << "]\t")
29 #else
30 #define ctrl_loge std::ostream(0)
31 #endif
32 /* Log Warning */
33 #if CTRL_LOG_LEVEL >= CTRL_LOG_LEVEL_WARNING
34 #define ctrl_logw (std::cout << "[W][" __FILE__ ":" << __LINE__ << "]\t")
35 #else
36 #define ctrl_logw std::ostream(0)
37 #endif
38 /* Log Info */
39 #if CTRL_LOG_LEVEL >= CTRL_LOG_LEVEL_INFO
40 #define ctrl_logi (std::cout << "[I][" __FILE__ ":" << __LINE__ << "]\t")
41 #else
42 #define ctrl_logi std::ostream(0)
43 #endif
44 /* Log Debug */
45 #if CTRL_LOG_LEVEL >= CTRL_LOG_LEVEL_DEBUG
46 #define ctrl_logd (std::cout "[D][" << __FILE__ ":" << __LINE__ << "]\t")
47 #else
48 #define ctrl_logd std::ostream(0)
49 #endif
50 
54 namespace ctrl {
55 
64 class AccelCurve {
65  public:
73  AccelCurve(const float j_max, const float a_max, const float v_start,
74  const float v_end) {
75  reset(j_max, a_max, v_start, v_end);
76  }
82  jm = am = t0 = t1 = t2 = t3 = v0 = v1 = v2 = v3 = x0 = x1 = x2 = x3 = 0;
83  }
92  void reset(const float j_max, const float a_max, const float v_start,
93  const float v_end) {
94  /* 符号付きで代入 */
95  am = (v_end > v_start) ? a_max : -a_max; //< 最大加速度の符号を決定
96  jm = (v_end > v_start) ? j_max : -j_max; //< 最大躍度の符号を決定
97  /* 初期値と最終値を代入 */
98  v0 = v_start; //< 代入
99  v3 = v_end; //< 代入
100  t0 = 0; //< ここでは初期値をゼロとする
101  x0 = 0; //< ここでは初期値はゼロとする
102  /* 速度が曲線となる部分の時間を決定 */
103  const auto tc = a_max / j_max;
104  /* 等加速度直線運動の時間を決定 */
105  const auto tm = (v3 - v0) / am - tc;
106  /* 等加速度直線運動の有無で分岐 */
107  if (tm > 0) {
108  /* 速度: 曲線 -> 直線 -> 曲線 */
109  t1 = t0 + tc;
110  t2 = t1 + tm;
111  t3 = t2 + tc;
112  v1 = v0 + am * tc / 2; //< v(t) を積分
113  v2 = v1 + am * tm; //< v(t) を積分
114  x1 = x0 + v0 * tc + am * tc * tc / 6; //< x(t) を積分
115  x2 = x1 + v1 * tm; //< x(t) を積分
116  x3 = x0 + (v0 + v3) / 2 * (t3 - t0); //< v(t) グラフの台形の面積より
117  } else {
118  /* 速度: 曲線 -> 曲線 */
119  const auto tcp = std::sqrt((v3 - v0) / jm); //< 変曲までの時間
120  t1 = t2 = t0 + tcp;
121  t3 = t2 + tcp;
122  v1 = v2 = (v0 + v3) / 2; //< 対称性より中点となる
123  x1 = x2 = x0 + v1 * tcp + jm * tcp * tcp * tcp / 6; //< x(t) を積分
124  x3 = x0 + 2 * v1 * tcp; //< 速度 v(t) グラフの面積より
125  }
126  }
132  float j(const float t) const {
133  if (t <= t0)
134  return 0;
135  else if (t <= t1)
136  return jm;
137  else if (t <= t2)
138  return 0;
139  else if (t <= t3)
140  return -jm;
141  else
142  return 0;
143  }
149  float a(const float t) const {
150  if (t <= t0)
151  return 0;
152  else if (t <= t1)
153  return jm * (t - t0);
154  else if (t <= t2)
155  return am;
156  else if (t <= t3)
157  return -jm * (t - t3);
158  else
159  return 0;
160  }
166  float v(const float t) const {
167  if (t <= t0)
168  return v0;
169  else if (t <= t1)
170  return v0 + jm / 2 * (t - t0) * (t - t0);
171  else if (t <= t2)
172  return v1 + am * (t - t1);
173  else if (t <= t3)
174  return v3 - jm / 2 * (t - t3) * (t - t3);
175  else
176  return v3;
177  }
183  float x(const float t) const {
184  if (t <= t0)
185  return x0 + v0 * (t - t0);
186  else if (t <= t1)
187  return x0 + v0 * (t - t0) + jm / 6 * (t - t0) * (t - t0) * (t - t0);
188  else if (t <= t2)
189  return x1 + v1 * (t - t1) + am / 2 * (t - t1) * (t - t1);
190  else if (t <= t3)
191  return x3 + v3 * (t - t3) - jm / 6 * (t - t3) * (t - t3) * (t - t3);
192  else
193  return x3 + v3 * (t - t3);
194  }
198  float t_end() const { return t3; }
202  float v_end() const { return v3; }
206  float x_end() const { return x3; }
210  float t_0() const { return t0; }
214  float t_1() const { return t1; }
218  float t_2() const { return t2; }
222  float t_3() const { return t3; }
226  const std::array<float, 4> getTimeStamps() const {
227  return {{t0, t1, t2, t3}};
228  }
232  void printCsv(std::ostream& os, const float t_interval = 1e-3f) const {
233  for (float t = t0; t < t_end(); t += t_interval) {
234  os << t << "," << j(t) << "," << a(t) << "," << v(t) << "," << x(t)
235  << std::endl;
236  }
237  }
241  friend std::ostream& operator<<(std::ostream& os, const AccelCurve& obj) {
242  os << "AccelCurve ";
243  os << "\tvs: " << obj.v0;
244  os << "\tve: " << obj.v3;
245  os << "\tt0: " << obj.t0;
246  os << "\tt1: " << obj.t1;
247  os << "\tt2: " << obj.t2;
248  os << "\tt3: " << obj.t3;
249  os << "\td: " << obj.x3 - obj.x0;
250  return os;
251  }
252 
253  public:
263  static float calcReachableVelocityEnd(const float j_max, const float a_max,
264  const float vs, const float vt,
265  const float d) {
266  /* 速度が曲線となる部分の時間を決定 */
267  const auto tc = a_max / j_max;
268  /* 最大加速度の符号を決定 */
269  const auto am = (vt > vs) ? a_max : -a_max;
270  const auto jm = (vt > vs) ? j_max : -j_max;
271  /* 等加速度直線運動の有無で分岐 */
272  const auto d_triangle = (vs + am * tc / 2) * tc; //< distance @ tm == 0
273  const auto v_triangle = jm / am * d - vs; //< v_end @ tm == 0
274  // ctrl_logd << "d_tri: " << d_triangle << std::endl;
275  // ctrl_logd << "v_tri: " << v_triangle << std::endl;
276  if (d * v_triangle > 0 && std::abs(d) > std::abs(d_triangle)) {
277  /* 曲線・直線・曲線 */
278  ctrl_logd << "v: curve - straight - curve" << std::endl;
279  /* 2次方程式の解の公式を解く */
280  const auto amtc = am * tc;
281  const auto D = amtc * amtc - 4 * (amtc * vs - vs * vs - 2 * am * d);
282  const auto sqrtD = std::sqrt(D);
283  return (-amtc + (d > 0 ? sqrtD : -sqrtD)) / 2;
284  }
285  /* 曲線・曲線 (走行距離が短すぎる) */
286  /* 3次方程式を解いて、終点速度を算出;
287  * 簡単のため、値を一度すべて正に変換して、計算結果に符号を付与して返送 */
288  const auto a = std::abs(vs);
289  const auto b = (d > 0 ? 1 : -1) * jm * d * d;
290  const auto aaa_27 = a * a * a / 27;
291  const auto cr = 8 * aaa_27 + b / 2;
292  const auto ci_b = 8 * aaa_27 / b + 1.0f / 4;
293  if (ci_b >= 0) {
294  /* ルートの中が非負のとき、3乗根により解を求める */
295  ctrl_logd << "v: curve - curve (accel)" << std::endl;
296  const auto c = std::cbrt(cr + std::abs(b) * std::sqrt(ci_b));
297  return (d > 0 ? 1 : -1) * (c + 4 * a * a / c / 9 - a / 3);
298  } else {
299  /* ルートの中が負のとき、極座標変換して解を求める */
300  ctrl_logd << "v: curve - curve (decel)" << std::endl;
301  const auto ci = std::abs(b) * std::sqrt(-ci_b);
302  const auto r = std::hypot(cr, ci); //< = sqrt(cr^2 + ci^2)
303  const auto th = std::atan2(ci, cr);
304  return (d > 0 ? 1 : -1) * (2 * std::cbrt(r) * std::cos(th / 3) - a / 3);
305  }
306  }
316  static float calcReachableVelocityMax(const float j_max, const float a_max,
317  const float vs, const float ve,
318  const float d) {
319  /* 速度が曲線となる部分の時間を決定 */
320  const auto tc = a_max / j_max;
321  const auto am = (d > 0) ? a_max : -a_max; //< 加速方向は移動方向に依存
322  /* 2次方程式の解の公式を解く */
323  const auto amtc = am * tc;
324  const auto D = amtc * amtc - 2 * (vs + ve) * amtc + 4 * am * d +
325  2 * (vs * vs + ve * ve);
326  if (D < 0) {
327  /* 拘束条件がおかしい */
328  ctrl_loge << "Error! D = " << D << " < 0" << std::endl;
329  /* 入力のチェック */
330  if (vs * ve < 0)
331  ctrl_loge << "Invalid Input! vs: " << vs << ", ve: " << ve << std::endl;
332  return vs;
333  }
334  const auto sqrtD = std::sqrt(D);
335  return (-amtc + (d > 0 ? sqrtD : -sqrtD)) / 2; //< 2次方程式の解
336  }
345  static float calcDistanceFromVelocityStartToEnd(const float j_max,
346  const float a_max,
347  const float v_start,
348  const float v_end) {
349  /* キャッシュ */
350  const auto ve_minus_vs = v_end - v_start;
351  /* 符号付きで代入 */
352  const auto am = (ve_minus_vs > 0) ? a_max : -a_max;
353  const auto jm = (ve_minus_vs > 0) ? j_max : -j_max;
354  /* 速度が曲線となる部分の時間を決定 */
355  const auto tc = a_max / j_max;
356  /* 等加速度直線運動の時間を決定 */
357  const auto tm = ve_minus_vs / am - tc;
358  /* 始点から終点までの時間を決定 */
359  const auto t_all =
360  (tm > 0) ? (tc + tm + tc) : (2 * std::sqrt(ve_minus_vs / jm));
361  return (v_start + v_end) / 2 * t_all; //< 速度グラフの面積により
362  }
363 
364  protected:
365  float jm;
366  float am;
367  float t0, t1, t2, t3;
368  float v0, v1, v2, v3;
369  float x0, x1, x2, x3;
370 };
371 } // namespace ctrl
#define ctrl_logd
Definition: accel_curve.h:48
#define ctrl_loge
Definition: accel_curve.h:28
走行距離拘束のない曲線加速の軌道を生成するクラス
Definition: accel_curve.h:64
float x3
位置定数 [m]
Definition: accel_curve.h:369
float am
加速度定数 [m/s/s]
Definition: accel_curve.h:366
float a(const float t) const
任意の時刻 t [s] における加速度 a [m/s/s] を返す関数
Definition: accel_curve.h:149
float t2
Definition: accel_curve.h:367
float t1
Definition: accel_curve.h:367
float t_2() const
等加速度直線運動の終了時刻 [s]
Definition: accel_curve.h:218
float x0
Definition: accel_curve.h:369
static float calcReachableVelocityMax(const float j_max, const float a_max, const float vs, const float ve, const float d)
走行距離の拘束から達しうる最大速度を算出する関数
Definition: accel_curve.h:316
float t_3() const
曲線加速の終了時刻 [s]
Definition: accel_curve.h:222
float v1
Definition: accel_curve.h:368
friend std::ostream & operator<<(std::ostream &os, const AccelCurve &obj)
情報の表示
Definition: accel_curve.h:241
float t_1() const
等加速度直線運動の開始時刻 [s]
Definition: accel_curve.h:214
float jm
躍度定数 [m/s/s/s]
Definition: accel_curve.h:365
float x_end() const
終点位置 [m]
Definition: accel_curve.h:206
float v2
Definition: accel_curve.h:368
void printCsv(std::ostream &os, const float t_interval=1e-3f) const
std::ostream に軌道のcsvを出力する関数
Definition: accel_curve.h:232
float x(const float t) const
任意の時刻 t [s] における位置 x [m] を返す関数
Definition: accel_curve.h:183
void reset(const float j_max, const float a_max, const float v_start, const float v_end)
引数の拘束条件から曲線を生成する関数
Definition: accel_curve.h:92
float t3
時刻定数 [s]
Definition: accel_curve.h:367
float t_end() const
終点時刻 [s]
Definition: accel_curve.h:198
AccelCurve()
とりあえずインスタンス化を行う空のコンストラクタ
Definition: accel_curve.h:81
const std::array< float, 4 > getTimeStamps() const
境界のタイムスタンプをまとめて取得する関数
Definition: accel_curve.h:226
float j(const float t) const
任意の時刻 t [s] における躍度 j [m/s/s/s] を返す関数
Definition: accel_curve.h:132
float v3
速度定数 [m/s]
Definition: accel_curve.h:368
float v(const float t) const
任意の時刻 t [s] における速度 v [m/s] を返す関数
Definition: accel_curve.h:166
static float calcReachableVelocityEnd(const float j_max, const float a_max, const float vs, const float vt, const float d)
走行距離の拘束から達しうる終点速度を算出する関数
Definition: accel_curve.h:263
AccelCurve(const float j_max, const float a_max, const float v_start, const float v_end)
初期化付きのコンストラクタ
Definition: accel_curve.h:73
float v0
Definition: accel_curve.h:368
float x2
Definition: accel_curve.h:369
float x1
Definition: accel_curve.h:369
float v_end() const
終点速度 [m/s]
Definition: accel_curve.h:202
float t_0() const
曲線加速の開始時刻 [s]
Definition: accel_curve.h:210
static float calcDistanceFromVelocityStartToEnd(const float j_max, const float a_max, const float v_start, const float v_end)
速度差の拘束から達しうる変位を算出する関数
Definition: accel_curve.h:345
float t0
Definition: accel_curve.h:367
制御関係の名前空間
Definition: accel_curve.h:54