otto_movements.cc 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
  1. #include "otto_movements.h"
  2. #include <algorithm>
  3. #include "oscillator.h"
  4. static const char* TAG = "OttoMovements";
  5. #define HAND_HOME_POSITION 45
  6. Otto::Otto() {
  7. is_otto_resting_ = false;
  8. has_hands_ = false;
  9. // 初始化所有舵机管脚为-1(未连接)
  10. for (int i = 0; i < SERVO_COUNT; i++) {
  11. servo_pins_[i] = -1;
  12. servo_trim_[i] = 0;
  13. }
  14. }
  15. Otto::~Otto() {
  16. DetachServos();
  17. }
  18. unsigned long IRAM_ATTR millis() {
  19. return (unsigned long)(esp_timer_get_time() / 1000ULL);
  20. }
  21. void Otto::Init(int left_leg, int right_leg, int left_foot, int right_foot, int left_hand,
  22. int right_hand) {
  23. servo_pins_[LEFT_LEG] = left_leg;
  24. servo_pins_[RIGHT_LEG] = right_leg;
  25. servo_pins_[LEFT_FOOT] = left_foot;
  26. servo_pins_[RIGHT_FOOT] = right_foot;
  27. servo_pins_[LEFT_HAND] = left_hand;
  28. servo_pins_[RIGHT_HAND] = right_hand;
  29. // 检查是否有手部舵机
  30. has_hands_ = (left_hand != -1 && right_hand != -1);
  31. AttachServos();
  32. is_otto_resting_ = false;
  33. }
  34. ///////////////////////////////////////////////////////////////////
  35. //-- ATTACH & DETACH FUNCTIONS ----------------------------------//
  36. ///////////////////////////////////////////////////////////////////
  37. void Otto::AttachServos() {
  38. for (int i = 0; i < SERVO_COUNT; i++) {
  39. if (servo_pins_[i] != -1) {
  40. servo_[i].Attach(servo_pins_[i]);
  41. }
  42. }
  43. }
  44. void Otto::DetachServos() {
  45. for (int i = 0; i < SERVO_COUNT; i++) {
  46. if (servo_pins_[i] != -1) {
  47. servo_[i].Detach();
  48. }
  49. }
  50. }
  51. ///////////////////////////////////////////////////////////////////
  52. //-- OSCILLATORS TRIMS ------------------------------------------//
  53. ///////////////////////////////////////////////////////////////////
  54. void Otto::SetTrims(int left_leg, int right_leg, int left_foot, int right_foot, int left_hand,
  55. int right_hand) {
  56. servo_trim_[LEFT_LEG] = left_leg;
  57. servo_trim_[RIGHT_LEG] = right_leg;
  58. servo_trim_[LEFT_FOOT] = left_foot;
  59. servo_trim_[RIGHT_FOOT] = right_foot;
  60. if (has_hands_) {
  61. servo_trim_[LEFT_HAND] = left_hand;
  62. servo_trim_[RIGHT_HAND] = right_hand;
  63. }
  64. for (int i = 0; i < SERVO_COUNT; i++) {
  65. if (servo_pins_[i] != -1) {
  66. servo_[i].SetTrim(servo_trim_[i]);
  67. }
  68. }
  69. }
  70. ///////////////////////////////////////////////////////////////////
  71. //-- BASIC MOTION FUNCTIONS -------------------------------------//
  72. ///////////////////////////////////////////////////////////////////
  73. void Otto::MoveServos(int time, int servo_target[]) {
  74. if (GetRestState() == true) {
  75. SetRestState(false);
  76. }
  77. final_time_ = millis() + time;
  78. if (time > 10) {
  79. for (int i = 0; i < SERVO_COUNT; i++) {
  80. if (servo_pins_[i] != -1) {
  81. increment_[i] = (servo_target[i] - servo_[i].GetPosition()) / (time / 10.0);
  82. }
  83. }
  84. for (int iteration = 1; millis() < final_time_; iteration++) {
  85. partial_time_ = millis() + 10;
  86. for (int i = 0; i < SERVO_COUNT; i++) {
  87. if (servo_pins_[i] != -1) {
  88. servo_[i].SetPosition(servo_[i].GetPosition() + increment_[i]);
  89. }
  90. }
  91. vTaskDelay(pdMS_TO_TICKS(10));
  92. }
  93. } else {
  94. for (int i = 0; i < SERVO_COUNT; i++) {
  95. if (servo_pins_[i] != -1) {
  96. servo_[i].SetPosition(servo_target[i]);
  97. }
  98. }
  99. vTaskDelay(pdMS_TO_TICKS(time));
  100. }
  101. // final adjustment to the target.
  102. bool f = true;
  103. int adjustment_count = 0;
  104. while (f && adjustment_count < 10) {
  105. f = false;
  106. for (int i = 0; i < SERVO_COUNT; i++) {
  107. if (servo_pins_[i] != -1 && servo_target[i] != servo_[i].GetPosition()) {
  108. f = true;
  109. break;
  110. }
  111. }
  112. if (f) {
  113. for (int i = 0; i < SERVO_COUNT; i++) {
  114. if (servo_pins_[i] != -1) {
  115. servo_[i].SetPosition(servo_target[i]);
  116. }
  117. }
  118. vTaskDelay(pdMS_TO_TICKS(10));
  119. adjustment_count++;
  120. }
  121. };
  122. }
  123. void Otto::MoveSingle(int position, int servo_number) {
  124. if (position > 180)
  125. position = 90;
  126. if (position < 0)
  127. position = 90;
  128. if (GetRestState() == true) {
  129. SetRestState(false);
  130. }
  131. if (servo_number >= 0 && servo_number < SERVO_COUNT && servo_pins_[servo_number] != -1) {
  132. servo_[servo_number].SetPosition(position);
  133. }
  134. }
  135. void Otto::OscillateServos(int amplitude[SERVO_COUNT], int offset[SERVO_COUNT], int period,
  136. double phase_diff[SERVO_COUNT], float cycle = 1) {
  137. for (int i = 0; i < SERVO_COUNT; i++) {
  138. if (servo_pins_[i] != -1) {
  139. servo_[i].SetO(offset[i]);
  140. servo_[i].SetA(amplitude[i]);
  141. servo_[i].SetT(period);
  142. servo_[i].SetPh(phase_diff[i]);
  143. }
  144. }
  145. double ref = millis();
  146. double end_time = period * cycle + ref;
  147. while (millis() < end_time) {
  148. for (int i = 0; i < SERVO_COUNT; i++) {
  149. if (servo_pins_[i] != -1) {
  150. servo_[i].Refresh();
  151. }
  152. }
  153. vTaskDelay(5);
  154. }
  155. vTaskDelay(pdMS_TO_TICKS(10));
  156. }
  157. void Otto::Execute(int amplitude[SERVO_COUNT], int offset[SERVO_COUNT], int period,
  158. double phase_diff[SERVO_COUNT], float steps = 1.0) {
  159. if (GetRestState() == true) {
  160. SetRestState(false);
  161. }
  162. int cycles = (int)steps;
  163. //-- Execute complete cycles
  164. if (cycles >= 1)
  165. for (int i = 0; i < cycles; i++)
  166. OscillateServos(amplitude, offset, period, phase_diff);
  167. //-- Execute the final not complete cycle
  168. OscillateServos(amplitude, offset, period, phase_diff, (float)steps - cycles);
  169. vTaskDelay(pdMS_TO_TICKS(10));
  170. }
  171. ///////////////////////////////////////////////////////////////////
  172. //-- HOME = Otto at rest position -------------------------------//
  173. ///////////////////////////////////////////////////////////////////
  174. void Otto::Home(bool hands_down) {
  175. if (is_otto_resting_ == false) { // Go to rest position only if necessary
  176. // 为所有舵机准备初始位置值
  177. int homes[SERVO_COUNT];
  178. for (int i = 0; i < SERVO_COUNT; i++) {
  179. if (i == LEFT_HAND || i == RIGHT_HAND) {
  180. if (hands_down) {
  181. // 如果需要复位手部,设置为默认值
  182. if (i == LEFT_HAND) {
  183. homes[i] = HAND_HOME_POSITION;
  184. } else { // RIGHT_HAND
  185. homes[i] = 180 - HAND_HOME_POSITION; // 右手镜像位置
  186. }
  187. } else {
  188. // 如果不需要复位手部,保持当前位置
  189. homes[i] = servo_[i].GetPosition();
  190. }
  191. } else {
  192. // 腿部和脚部舵机始终复位
  193. homes[i] = 90;
  194. }
  195. }
  196. MoveServos(500, homes);
  197. is_otto_resting_ = true;
  198. }
  199. vTaskDelay(pdMS_TO_TICKS(200));
  200. }
  201. bool Otto::GetRestState() {
  202. return is_otto_resting_;
  203. }
  204. void Otto::SetRestState(bool state) {
  205. is_otto_resting_ = state;
  206. }
  207. ///////////////////////////////////////////////////////////////////
  208. //-- PREDETERMINED MOTION SEQUENCES -----------------------------//
  209. ///////////////////////////////////////////////////////////////////
  210. //-- Otto movement: Jump
  211. //-- Parameters:
  212. //-- steps: Number of steps
  213. //-- T: Period
  214. //---------------------------------------------------------
  215. void Otto::Jump(float steps, int period) {
  216. int up[SERVO_COUNT] = {90, 90, 150, 30, HAND_HOME_POSITION, 180 - HAND_HOME_POSITION};
  217. MoveServos(period, up);
  218. int down[SERVO_COUNT] = {90, 90, 90, 90, HAND_HOME_POSITION, 180 - HAND_HOME_POSITION};
  219. MoveServos(period, down);
  220. }
  221. //---------------------------------------------------------
  222. //-- Otto gait: Walking (forward or backward)
  223. //-- Parameters:
  224. //-- * steps: Number of steps
  225. //-- * T : Period
  226. //-- * Dir: Direction: FORWARD / BACKWARD
  227. //-- * amount: 手部摆动幅度, 0表示不摆动
  228. //---------------------------------------------------------
  229. void Otto::Walk(float steps, int period, int dir, int amount) {
  230. //-- Oscillator parameters for walking
  231. //-- Hip sevos are in phase
  232. //-- Feet servos are in phase
  233. //-- Hip and feet are 90 degrees out of phase
  234. //-- -90 : Walk forward
  235. //-- 90 : Walk backward
  236. //-- Feet servos also have the same offset (for tiptoe a little bit)
  237. int A[SERVO_COUNT] = {30, 30, 30, 30, 0, 0};
  238. int O[SERVO_COUNT] = {0, 0, 5, -5, HAND_HOME_POSITION - 90, HAND_HOME_POSITION};
  239. double phase_diff[SERVO_COUNT] = {0, 0, DEG2RAD(dir * -90), DEG2RAD(dir * -90), 0, 0};
  240. // 如果amount>0且有手部舵机,设置手部振幅和相位
  241. if (amount > 0 && has_hands_) {
  242. // 手臂振幅使用传入的amount参数
  243. A[LEFT_HAND] = amount;
  244. A[RIGHT_HAND] = amount;
  245. // 左手与右腿同相,右手与左腿同相,使得机器人走路时手臂自然摆动
  246. phase_diff[LEFT_HAND] = phase_diff[RIGHT_LEG]; // 左手与右腿同相
  247. phase_diff[RIGHT_HAND] = phase_diff[LEFT_LEG]; // 右手与左腿同相
  248. } else {
  249. A[LEFT_HAND] = 0;
  250. A[RIGHT_HAND] = 0;
  251. }
  252. //-- Let's oscillate the servos!
  253. Execute(A, O, period, phase_diff, steps);
  254. }
  255. //---------------------------------------------------------
  256. //-- Otto gait: Turning (left or right)
  257. //-- Parameters:
  258. //-- * Steps: Number of steps
  259. //-- * T: Period
  260. //-- * Dir: Direction: LEFT / RIGHT
  261. //-- * amount: 手部摆动幅度, 0表示不摆动
  262. //---------------------------------------------------------
  263. void Otto::Turn(float steps, int period, int dir, int amount) {
  264. //-- Same coordination than for walking (see Otto::walk)
  265. //-- The Amplitudes of the hip's oscillators are not igual
  266. //-- When the right hip servo amplitude is higher, the steps taken by
  267. //-- the right leg are bigger than the left. So, the robot describes an
  268. //-- left arc
  269. int A[SERVO_COUNT] = {30, 30, 30, 30, 0, 0};
  270. int O[SERVO_COUNT] = {0, 0, 5, -5, HAND_HOME_POSITION - 90, HAND_HOME_POSITION};
  271. double phase_diff[SERVO_COUNT] = {0, 0, DEG2RAD(-90), DEG2RAD(-90), 0, 0};
  272. if (dir == LEFT) {
  273. A[0] = 30; //-- Left hip servo
  274. A[1] = 0; //-- Right hip servo
  275. } else {
  276. A[0] = 0;
  277. A[1] = 30;
  278. }
  279. // 如果amount>0且有手部舵机,设置手部振幅和相位
  280. if (amount > 0 && has_hands_) {
  281. // 手臂振幅使用传入的amount参数
  282. A[LEFT_HAND] = amount;
  283. A[RIGHT_HAND] = amount;
  284. // 转向时手臂摆动相位:左手与左腿同相,右手与右腿同相,增强转向效果
  285. phase_diff[LEFT_HAND] = phase_diff[LEFT_LEG]; // 左手与左腿同相
  286. phase_diff[RIGHT_HAND] = phase_diff[RIGHT_LEG]; // 右手与右腿同相
  287. } else {
  288. A[LEFT_HAND] = 0;
  289. A[RIGHT_HAND] = 0;
  290. }
  291. //-- Let's oscillate the servos!
  292. Execute(A, O, period, phase_diff, steps);
  293. }
  294. //---------------------------------------------------------
  295. //-- Otto gait: Lateral bend
  296. //-- Parameters:
  297. //-- steps: Number of bends
  298. //-- T: Period of one bend
  299. //-- dir: RIGHT=Right bend LEFT=Left bend
  300. //---------------------------------------------------------
  301. void Otto::Bend(int steps, int period, int dir) {
  302. // Parameters of all the movements. Default: Left bend
  303. int bend1[SERVO_COUNT] = {90, 90, 62, 35, HAND_HOME_POSITION, 180 - HAND_HOME_POSITION};
  304. int bend2[SERVO_COUNT] = {90, 90, 62, 105, HAND_HOME_POSITION, 180 - HAND_HOME_POSITION};
  305. int homes[SERVO_COUNT] = {90, 90, 90, 90, HAND_HOME_POSITION, 180 - HAND_HOME_POSITION};
  306. // Time of one bend, constrained in order to avoid movements too fast.
  307. // T=max(T, 600);
  308. // Changes in the parameters if right direction is chosen
  309. if (dir == -1) {
  310. bend1[2] = 180 - 35;
  311. bend1[3] = 180 - 60; // Not 65. Otto is unbalanced
  312. bend2[2] = 180 - 105;
  313. bend2[3] = 180 - 60;
  314. }
  315. // Time of the bend movement. Fixed parameter to avoid falls
  316. int T2 = 800;
  317. // Bend movement
  318. for (int i = 0; i < steps; i++) {
  319. MoveServos(T2 / 2, bend1);
  320. MoveServos(T2 / 2, bend2);
  321. vTaskDelay(pdMS_TO_TICKS(period * 0.8));
  322. MoveServos(500, homes);
  323. }
  324. }
  325. //---------------------------------------------------------
  326. //-- Otto gait: Shake a leg
  327. //-- Parameters:
  328. //-- steps: Number of shakes
  329. //-- T: Period of one shake
  330. //-- dir: RIGHT=Right leg LEFT=Left leg
  331. //---------------------------------------------------------
  332. void Otto::ShakeLeg(int steps, int period, int dir) {
  333. // This variable change the amount of shakes
  334. int numberLegMoves = 2;
  335. // Parameters of all the movements. Default: Right leg
  336. int shake_leg1[SERVO_COUNT] = {90, 90, 58, 35, HAND_HOME_POSITION, 180 - HAND_HOME_POSITION};
  337. int shake_leg2[SERVO_COUNT] = {90, 90, 58, 120, HAND_HOME_POSITION, 180 - HAND_HOME_POSITION};
  338. int shake_leg3[SERVO_COUNT] = {90, 90, 58, 60, HAND_HOME_POSITION, 180 - HAND_HOME_POSITION};
  339. int homes[SERVO_COUNT] = {90, 90, 90, 90, HAND_HOME_POSITION, 180 - HAND_HOME_POSITION};
  340. // Changes in the parameters if left leg is chosen
  341. if (dir == -1) {
  342. shake_leg1[2] = 180 - 35;
  343. shake_leg1[3] = 180 - 58;
  344. shake_leg2[2] = 180 - 120;
  345. shake_leg2[3] = 180 - 58;
  346. shake_leg3[2] = 180 - 60;
  347. shake_leg3[3] = 180 - 58;
  348. }
  349. // Time of the bend movement. Fixed parameter to avoid falls
  350. int T2 = 1000;
  351. // Time of one shake, constrained in order to avoid movements too fast.
  352. period = period - T2;
  353. period = std::max(period, 200 * numberLegMoves);
  354. for (int j = 0; j < steps; j++) {
  355. // Bend movement
  356. MoveServos(T2 / 2, shake_leg1);
  357. MoveServos(T2 / 2, shake_leg2);
  358. // Shake movement
  359. for (int i = 0; i < numberLegMoves; i++) {
  360. MoveServos(period / (2 * numberLegMoves), shake_leg3);
  361. MoveServos(period / (2 * numberLegMoves), shake_leg2);
  362. }
  363. MoveServos(500, homes); // Return to home position
  364. }
  365. vTaskDelay(pdMS_TO_TICKS(period));
  366. }
  367. //---------------------------------------------------------
  368. //-- Otto movement: up & down
  369. //-- Parameters:
  370. //-- * steps: Number of jumps
  371. //-- * T: Period
  372. //-- * h: Jump height: SMALL / MEDIUM / BIG
  373. //-- (or a number in degrees 0 - 90)
  374. //---------------------------------------------------------
  375. void Otto::UpDown(float steps, int period, int height) {
  376. //-- Both feet are 180 degrees out of phase
  377. //-- Feet amplitude and offset are the same
  378. //-- Initial phase for the right foot is -90, so that it starts
  379. //-- in one extreme position (not in the middle)
  380. int A[SERVO_COUNT] = {0, 0, height, height, 0, 0};
  381. int O[SERVO_COUNT] = {0, 0, height, -height, HAND_HOME_POSITION, 180 - HAND_HOME_POSITION};
  382. double phase_diff[SERVO_COUNT] = {0, 0, DEG2RAD(-90), DEG2RAD(90), 0, 0};
  383. //-- Let's oscillate the servos!
  384. Execute(A, O, period, phase_diff, steps);
  385. }
  386. //---------------------------------------------------------
  387. //-- Otto movement: swinging side to side
  388. //-- Parameters:
  389. //-- steps: Number of steps
  390. //-- T : Period
  391. //-- h : Amount of swing (from 0 to 50 aprox)
  392. //---------------------------------------------------------
  393. void Otto::Swing(float steps, int period, int height) {
  394. //-- Both feets are in phase. The offset is half the amplitude
  395. //-- It causes the robot to swing from side to side
  396. int A[SERVO_COUNT] = {0, 0, height, height, 0, 0};
  397. int O[SERVO_COUNT] = {
  398. 0, 0, height / 2, -height / 2, HAND_HOME_POSITION, 180 - HAND_HOME_POSITION};
  399. double phase_diff[SERVO_COUNT] = {0, 0, DEG2RAD(0), DEG2RAD(0), 0, 0};
  400. //-- Let's oscillate the servos!
  401. Execute(A, O, period, phase_diff, steps);
  402. }
  403. //---------------------------------------------------------
  404. //-- Otto movement: swinging side to side without touching the floor with the heel
  405. //-- Parameters:
  406. //-- steps: Number of steps
  407. //-- T : Period
  408. //-- h : Amount of swing (from 0 to 50 aprox)
  409. //---------------------------------------------------------
  410. void Otto::TiptoeSwing(float steps, int period, int height) {
  411. //-- Both feets are in phase. The offset is not half the amplitude in order to tiptoe
  412. //-- It causes the robot to swing from side to side
  413. int A[SERVO_COUNT] = {0, 0, height, height, 0, 0};
  414. int O[SERVO_COUNT] = {0, 0, height, -height, HAND_HOME_POSITION, 180 - HAND_HOME_POSITION};
  415. double phase_diff[SERVO_COUNT] = {0, 0, 0, 0, 0, 0};
  416. //-- Let's oscillate the servos!
  417. Execute(A, O, period, phase_diff, steps);
  418. }
  419. //---------------------------------------------------------
  420. //-- Otto gait: Jitter
  421. //-- Parameters:
  422. //-- steps: Number of jitters
  423. //-- T: Period of one jitter
  424. //-- h: height (Values between 5 - 25)
  425. //---------------------------------------------------------
  426. void Otto::Jitter(float steps, int period, int height) {
  427. //-- Both feet are 180 degrees out of phase
  428. //-- Feet amplitude and offset are the same
  429. //-- Initial phase for the right foot is -90, so that it starts
  430. //-- in one extreme position (not in the middle)
  431. //-- h is constrained to avoid hit the feets
  432. height = std::min(25, height);
  433. int A[SERVO_COUNT] = {height, height, 0, 0, 0, 0};
  434. int O[SERVO_COUNT] = {0, 0, 0, 0, HAND_HOME_POSITION, 180 - HAND_HOME_POSITION};
  435. double phase_diff[SERVO_COUNT] = {DEG2RAD(-90), DEG2RAD(90), 0, 0, 0, 0};
  436. //-- Let's oscillate the servos!
  437. Execute(A, O, period, phase_diff, steps);
  438. }
  439. //---------------------------------------------------------
  440. //-- Otto gait: Ascending & turn (Jitter while up&down)
  441. //-- Parameters:
  442. //-- steps: Number of bends
  443. //-- T: Period of one bend
  444. //-- h: height (Values between 5 - 15)
  445. //---------------------------------------------------------
  446. void Otto::AscendingTurn(float steps, int period, int height) {
  447. //-- Both feet and legs are 180 degrees out of phase
  448. //-- Initial phase for the right foot is -90, so that it starts
  449. //-- in one extreme position (not in the middle)
  450. //-- h is constrained to avoid hit the feets
  451. height = std::min(13, height);
  452. int A[SERVO_COUNT] = {height, height, height, height, 0, 0};
  453. int O[SERVO_COUNT] = {
  454. 0, 0, height + 4, -height + 4, HAND_HOME_POSITION, 180 - HAND_HOME_POSITION};
  455. double phase_diff[SERVO_COUNT] = {DEG2RAD(-90), DEG2RAD(90), DEG2RAD(-90), DEG2RAD(90), 0, 0};
  456. //-- Let's oscillate the servos!
  457. Execute(A, O, period, phase_diff, steps);
  458. }
  459. //---------------------------------------------------------
  460. //-- Otto gait: Moonwalker. Otto moves like Michael Jackson
  461. //-- Parameters:
  462. //-- Steps: Number of steps
  463. //-- T: Period
  464. //-- h: Height. Typical valures between 15 and 40
  465. //-- dir: Direction: LEFT / RIGHT
  466. //---------------------------------------------------------
  467. void Otto::Moonwalker(float steps, int period, int height, int dir) {
  468. //-- This motion is similar to that of the caterpillar robots: A travelling
  469. //-- wave moving from one side to another
  470. //-- The two Otto's feet are equivalent to a minimal configuration. It is known
  471. //-- that 2 servos can move like a worm if they are 120 degrees out of phase
  472. //-- In the example of Otto, the two feet are mirrored so that we have:
  473. //-- 180 - 120 = 60 degrees. The actual phase difference given to the oscillators
  474. //-- is 60 degrees.
  475. //-- Both amplitudes are equal. The offset is half the amplitud plus a little bit of
  476. //- offset so that the robot tiptoe lightly
  477. int A[SERVO_COUNT] = {0, 0, height, height, 0, 0};
  478. int O[SERVO_COUNT] = {
  479. 0, 0, height / 2 + 2, -height / 2 - 2, HAND_HOME_POSITION, 180 - HAND_HOME_POSITION};
  480. int phi = -dir * 90;
  481. double phase_diff[SERVO_COUNT] = {0, 0, DEG2RAD(phi), DEG2RAD(-60 * dir + phi), 0, 0};
  482. //-- Let's oscillate the servos!
  483. Execute(A, O, period, phase_diff, steps);
  484. }
  485. //----------------------------------------------------------
  486. //-- Otto gait: Crusaito. A mixture between moonwalker and walk
  487. //-- Parameters:
  488. //-- steps: Number of steps
  489. //-- T: Period
  490. //-- h: height (Values between 20 - 50)
  491. //-- dir: Direction: LEFT / RIGHT
  492. //-----------------------------------------------------------
  493. void Otto::Crusaito(float steps, int period, int height, int dir) {
  494. int A[SERVO_COUNT] = {25, 25, height, height, 0, 0};
  495. int O[SERVO_COUNT] = {
  496. 0, 0, height / 2 + 4, -height / 2 - 4, HAND_HOME_POSITION, 180 - HAND_HOME_POSITION};
  497. double phase_diff[SERVO_COUNT] = {90, 90, DEG2RAD(0), DEG2RAD(-60 * dir), 0, 0};
  498. //-- Let's oscillate the servos!
  499. Execute(A, O, period, phase_diff, steps);
  500. }
  501. //---------------------------------------------------------
  502. //-- Otto gait: Flapping
  503. //-- Parameters:
  504. //-- steps: Number of steps
  505. //-- T: Period
  506. //-- h: height (Values between 10 - 30)
  507. //-- dir: direction: FOREWARD, BACKWARD
  508. //---------------------------------------------------------
  509. void Otto::Flapping(float steps, int period, int height, int dir) {
  510. int A[SERVO_COUNT] = {12, 12, height, height, 0, 0};
  511. int O[SERVO_COUNT] = {
  512. 0, 0, height - 10, -height + 10, HAND_HOME_POSITION, 180 - HAND_HOME_POSITION};
  513. double phase_diff[SERVO_COUNT] = {
  514. DEG2RAD(0), DEG2RAD(180), DEG2RAD(-90 * dir), DEG2RAD(90 * dir), 0, 0};
  515. //-- Let's oscillate the servos!
  516. Execute(A, O, period, phase_diff, steps);
  517. }
  518. //---------------------------------------------------------
  519. //-- 手部动作: 举手
  520. //-- Parameters:
  521. //-- period: 动作时间
  522. //-- dir: 方向 1=左手, -1=右手, 0=双手
  523. //---------------------------------------------------------
  524. void Otto::HandsUp(int period, int dir) {
  525. if (!has_hands_) {
  526. return;
  527. }
  528. int initial[SERVO_COUNT] = {90, 90, 90, 90, HAND_HOME_POSITION, 180 - HAND_HOME_POSITION};
  529. int target[SERVO_COUNT] = {90, 90, 90, 90, HAND_HOME_POSITION, 180 - HAND_HOME_POSITION};
  530. if (dir == 0) {
  531. target[LEFT_HAND] = 170;
  532. target[RIGHT_HAND] = 10;
  533. } else if (dir == 1) {
  534. target[LEFT_HAND] = 170;
  535. target[RIGHT_HAND] = servo_[RIGHT_HAND].GetPosition();
  536. } else if (dir == -1) {
  537. target[RIGHT_HAND] = 10;
  538. target[LEFT_HAND] = servo_[LEFT_HAND].GetPosition();
  539. }
  540. MoveServos(period, target);
  541. }
  542. //---------------------------------------------------------
  543. //-- 手部动作: 双手放下
  544. //-- Parameters:
  545. //-- period: 动作时间
  546. //-- dir: 方向 1=左手, -1=右手, 0=双手
  547. //---------------------------------------------------------
  548. void Otto::HandsDown(int period, int dir) {
  549. if (!has_hands_) {
  550. return;
  551. }
  552. int target[SERVO_COUNT] = {90, 90, 90, 90, HAND_HOME_POSITION, 180 - HAND_HOME_POSITION};
  553. if (dir == 1) {
  554. target[RIGHT_HAND] = servo_[RIGHT_HAND].GetPosition();
  555. } else if (dir == -1) {
  556. target[LEFT_HAND] = servo_[LEFT_HAND].GetPosition();
  557. }
  558. MoveServos(period, target);
  559. }
  560. //---------------------------------------------------------
  561. //-- 手部动作: 挥手
  562. //-- Parameters:
  563. //-- period: 动作周期
  564. //-- dir: 方向 LEFT/RIGHT/BOTH
  565. //---------------------------------------------------------
  566. void Otto::HandWave(int period, int dir) {
  567. if (!has_hands_) {
  568. return;
  569. }
  570. if (dir == BOTH) {
  571. HandWaveBoth(period);
  572. return;
  573. }
  574. int servo_index = (dir == LEFT) ? LEFT_HAND : RIGHT_HAND;
  575. int current_positions[SERVO_COUNT];
  576. for (int i = 0; i < SERVO_COUNT; i++) {
  577. if (servo_pins_[i] != -1) {
  578. current_positions[i] = servo_[i].GetPosition();
  579. } else {
  580. current_positions[i] = 90;
  581. }
  582. }
  583. int position;
  584. if (servo_index == LEFT_HAND) {
  585. position = 170;
  586. } else {
  587. position = 10;
  588. }
  589. current_positions[servo_index] = position;
  590. MoveServos(300, current_positions);
  591. vTaskDelay(pdMS_TO_TICKS(300));
  592. // 左右摆动5次
  593. for (int i = 0; i < 5; i++) {
  594. if (servo_index == LEFT_HAND) {
  595. current_positions[servo_index] = position - 30;
  596. MoveServos(period / 10, current_positions);
  597. vTaskDelay(pdMS_TO_TICKS(period / 10));
  598. current_positions[servo_index] = position + 30;
  599. MoveServos(period / 10, current_positions);
  600. } else {
  601. current_positions[servo_index] = position + 30;
  602. MoveServos(period / 10, current_positions);
  603. vTaskDelay(pdMS_TO_TICKS(period / 10));
  604. current_positions[servo_index] = position - 30;
  605. MoveServos(period / 10, current_positions);
  606. }
  607. vTaskDelay(pdMS_TO_TICKS(period / 10));
  608. }
  609. if (servo_index == LEFT_HAND) {
  610. current_positions[servo_index] = HAND_HOME_POSITION;
  611. } else {
  612. current_positions[servo_index] = 180 - HAND_HOME_POSITION;
  613. }
  614. MoveServos(300, current_positions);
  615. }
  616. //---------------------------------------------------------
  617. //-- 手部动作: 双手同时挥手
  618. //-- Parameters:
  619. //-- period: 动作周期
  620. //---------------------------------------------------------
  621. void Otto::HandWaveBoth(int period) {
  622. if (!has_hands_) {
  623. return;
  624. }
  625. int current_positions[SERVO_COUNT];
  626. for (int i = 0; i < SERVO_COUNT; i++) {
  627. if (servo_pins_[i] != -1) {
  628. current_positions[i] = servo_[i].GetPosition();
  629. } else {
  630. current_positions[i] = 90;
  631. }
  632. }
  633. int left_position = 170;
  634. int right_position = 10;
  635. current_positions[LEFT_HAND] = left_position;
  636. current_positions[RIGHT_HAND] = right_position;
  637. MoveServos(300, current_positions);
  638. // 左右摆动5次
  639. for (int i = 0; i < 5; i++) {
  640. // 波浪向左
  641. current_positions[LEFT_HAND] = left_position - 30;
  642. current_positions[RIGHT_HAND] = right_position + 30;
  643. MoveServos(period / 10, current_positions);
  644. // 波浪向右
  645. current_positions[LEFT_HAND] = left_position + 30;
  646. current_positions[RIGHT_HAND] = right_position - 30;
  647. MoveServos(period / 10, current_positions);
  648. }
  649. current_positions[LEFT_HAND] = HAND_HOME_POSITION;
  650. current_positions[RIGHT_HAND] = 180 - HAND_HOME_POSITION;
  651. MoveServos(300, current_positions);
  652. }
  653. void Otto::EnableServoLimit(int diff_limit) {
  654. for (int i = 0; i < SERVO_COUNT; i++) {
  655. if (servo_pins_[i] != -1) {
  656. servo_[i].SetLimiter(diff_limit);
  657. }
  658. }
  659. }
  660. void Otto::DisableServoLimit() {
  661. for (int i = 0; i < SERVO_COUNT; i++) {
  662. if (servo_pins_[i] != -1) {
  663. servo_[i].DisableLimiter();
  664. }
  665. }
  666. }