123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472 |
- #include "movements.h"
- #include <algorithm>
- #include <cstring>
- #include "oscillator.h"
- static const char* TAG = "Movements";
- Otto::Otto() {
- is_otto_resting_ = false;
- for (int i = 0; i < SERVO_COUNT; i++) {
- servo_pins_[i] = -1;
- servo_trim_[i] = 0;
- }
- }
- Otto::~Otto() {
- DetachServos();
- }
- unsigned long IRAM_ATTR millis() {
- return (unsigned long)(esp_timer_get_time() / 1000ULL);
- }
- void Otto::Init(int right_pitch, int right_roll, int left_pitch, int left_roll, int body,
- int head) {
- servo_pins_[RIGHT_PITCH] = right_pitch;
- servo_pins_[RIGHT_ROLL] = right_roll;
- servo_pins_[LEFT_PITCH] = left_pitch;
- servo_pins_[LEFT_ROLL] = left_roll;
- servo_pins_[BODY] = body;
- servo_pins_[HEAD] = head;
- AttachServos();
- is_otto_resting_ = false;
- }
- ///////////////////////////////////////////////////////////////////
- //-- ATTACH & DETACH FUNCTIONS ----------------------------------//
- ///////////////////////////////////////////////////////////////////
- void Otto::AttachServos() {
- for (int i = 0; i < SERVO_COUNT; i++) {
- if (servo_pins_[i] != -1) {
- servo_[i].Attach(servo_pins_[i]);
- }
- }
- }
- void Otto::DetachServos() {
- for (int i = 0; i < SERVO_COUNT; i++) {
- if (servo_pins_[i] != -1) {
- servo_[i].Detach();
- }
- }
- }
- ///////////////////////////////////////////////////////////////////
- //-- OSCILLATORS TRIMS ------------------------------------------//
- ///////////////////////////////////////////////////////////////////
- void Otto::SetTrims(int right_pitch, int right_roll, int left_pitch, int left_roll, int body,
- int head) {
- servo_trim_[RIGHT_PITCH] = right_pitch;
- servo_trim_[RIGHT_ROLL] = right_roll;
- servo_trim_[LEFT_PITCH] = left_pitch;
- servo_trim_[LEFT_ROLL] = left_roll;
- servo_trim_[BODY] = body;
- servo_trim_[HEAD] = head;
- for (int i = 0; i < SERVO_COUNT; i++) {
- if (servo_pins_[i] != -1) {
- servo_[i].SetTrim(servo_trim_[i]);
- }
- }
- }
- ///////////////////////////////////////////////////////////////////
- //-- BASIC MOTION FUNCTIONS -------------------------------------//
- ///////////////////////////////////////////////////////////////////
- void Otto::MoveServos(int time, int servo_target[]) {
- if (GetRestState() == true) {
- SetRestState(false);
- }
- final_time_ = millis() + time;
- if (time > 10) {
- for (int i = 0; i < SERVO_COUNT; i++) {
- if (servo_pins_[i] != -1) {
- increment_[i] = (servo_target[i] - servo_[i].GetPosition()) / (time / 10.0);
- }
- }
- for (int iteration = 1; millis() < final_time_; iteration++) {
- partial_time_ = millis() + 10;
- for (int i = 0; i < SERVO_COUNT; i++) {
- if (servo_pins_[i] != -1) {
- servo_[i].SetPosition(servo_[i].GetPosition() + increment_[i]);
- }
- }
- vTaskDelay(pdMS_TO_TICKS(10));
- }
- } else {
- for (int i = 0; i < SERVO_COUNT; i++) {
- if (servo_pins_[i] != -1) {
- servo_[i].SetPosition(servo_target[i]);
- }
- }
- vTaskDelay(pdMS_TO_TICKS(time));
- }
- // final adjustment to the target.
- bool f = true;
- int adjustment_count = 0;
- while (f && adjustment_count < 10) {
- f = false;
- for (int i = 0; i < SERVO_COUNT; i++) {
- if (servo_pins_[i] != -1 && servo_target[i] != servo_[i].GetPosition()) {
- f = true;
- break;
- }
- }
- if (f) {
- for (int i = 0; i < SERVO_COUNT; i++) {
- if (servo_pins_[i] != -1) {
- servo_[i].SetPosition(servo_target[i]);
- }
- }
- vTaskDelay(pdMS_TO_TICKS(10));
- adjustment_count++;
- }
- };
- }
- void Otto::MoveSingle(int position, int servo_number) {
- if (position > 180)
- position = 90;
- if (position < 0)
- position = 90;
- if (GetRestState() == true) {
- SetRestState(false);
- }
- if (servo_number >= 0 && servo_number < SERVO_COUNT && servo_pins_[servo_number] != -1) {
- servo_[servo_number].SetPosition(position);
- }
- }
- void Otto::OscillateServos(int amplitude[SERVO_COUNT], int offset[SERVO_COUNT], int period,
- double phase_diff[SERVO_COUNT], float cycle = 1) {
- for (int i = 0; i < SERVO_COUNT; i++) {
- if (servo_pins_[i] != -1) {
- servo_[i].SetO(offset[i]);
- servo_[i].SetA(amplitude[i]);
- servo_[i].SetT(period);
- servo_[i].SetPh(phase_diff[i]);
- }
- }
- double ref = millis();
- double end_time = period * cycle + ref;
- while (millis() < end_time) {
- for (int i = 0; i < SERVO_COUNT; i++) {
- if (servo_pins_[i] != -1) {
- servo_[i].Refresh();
- }
- }
- vTaskDelay(5);
- }
- vTaskDelay(pdMS_TO_TICKS(10));
- }
- void Otto::Execute(int amplitude[SERVO_COUNT], int offset[SERVO_COUNT], int period,
- double phase_diff[SERVO_COUNT], float steps = 1.0) {
- if (GetRestState() == true) {
- SetRestState(false);
- }
- int cycles = (int)steps;
- //-- Execute complete cycles
- if (cycles >= 1)
- for (int i = 0; i < cycles; i++)
- OscillateServos(amplitude, offset, period, phase_diff);
- //-- Execute the final not complete cycle
- OscillateServos(amplitude, offset, period, phase_diff, (float)steps - cycles);
- vTaskDelay(pdMS_TO_TICKS(10));
- }
- ///////////////////////////////////////////////////////////////////
- //-- HOME = Otto at rest position -------------------------------//
- ///////////////////////////////////////////////////////////////////
- void Otto::Home(bool hands_down) {
- if (is_otto_resting_ == false) { // Go to rest position only if necessary
- MoveServos(1000, servo_initial_);
- is_otto_resting_ = true;
- }
- vTaskDelay(pdMS_TO_TICKS(1000));
- }
- bool Otto::GetRestState() {
- return is_otto_resting_;
- }
- void Otto::SetRestState(bool state) {
- is_otto_resting_ = state;
- }
- ///////////////////////////////////////////////////////////////////
- //-- PREDETERMINED MOTION SEQUENCES -----------------------------//
- ///////////////////////////////////////////////////////////////////
- //---------------------------------------------------------
- //-- 统一手部动作函数
- //-- Parameters:
- //-- action: 动作类型 1=举左手, 2=举右手, 3=举双手, 4=放左手, 5=放右手, 6=放双手,
- //-- 7=挥左手, 8=挥右手, 9=挥双手, 10=拍打左手, 11=拍打右手, 12=拍打双手
- //-- times: 重复次数
- //-- amount: 动作幅度 (10-50)
- //-- period: 动作时间
- //---------------------------------------------------------
- void Otto::HandAction(int action, int times, int amount, int period) {
- // 限制参数范围
- times = 2 * std::max(3, std::min(100, times));
- amount = std::max(10, std::min(50, amount));
- period = std::max(100, std::min(1000, period));
- int current_positions[SERVO_COUNT];
- for (int i = 0; i < SERVO_COUNT; i++) {
- current_positions[i] = (servo_pins_[i] != -1) ? servo_[i].GetPosition() : servo_initial_[i];
- }
- switch (action) {
- case 1: // 举左手
- current_positions[LEFT_PITCH] = 180;
- MoveServos(period, current_positions);
- break;
- case 2: // 举右手
- current_positions[RIGHT_PITCH] = 0;
- MoveServos(period, current_positions);
- break;
- case 3: // 举双手
- current_positions[LEFT_PITCH] = 180;
- current_positions[RIGHT_PITCH] = 0;
- MoveServos(period, current_positions);
- break;
- case 4: // 放左手
- case 5: // 放右手
- case 6: // 放双手
- // 回到初始位置
- memcpy(current_positions, servo_initial_, sizeof(current_positions));
- MoveServos(period, current_positions);
- break;
- case 7: // 挥左手
- current_positions[LEFT_PITCH] = 150;
- MoveServos(period, current_positions);
- for (int i = 0; i < times; i++) {
- current_positions[LEFT_PITCH] = 150 + (i % 2 == 0 ? -30 : 30);
- MoveServos(period / 10, current_positions);
- vTaskDelay(pdMS_TO_TICKS(period / 10));
- }
- memcpy(current_positions, servo_initial_, sizeof(current_positions));
- MoveServos(period, current_positions);
- break;
- case 8: // 挥右手
- current_positions[RIGHT_PITCH] = 30;
- MoveServos(period, current_positions);
- for (int i = 0; i < times; i++) {
- current_positions[RIGHT_PITCH] = 30 + (i % 2 == 0 ? 30 : -30);
- MoveServos(period / 10, current_positions);
- vTaskDelay(pdMS_TO_TICKS(period / 10));
- }
- memcpy(current_positions, servo_initial_, sizeof(current_positions));
- MoveServos(period, current_positions);
- break;
- case 9: // 挥双手
- current_positions[LEFT_PITCH] = 150;
- current_positions[RIGHT_PITCH] = 30;
- MoveServos(period, current_positions);
- for (int i = 0; i < times; i++) {
- current_positions[LEFT_PITCH] = 150 + (i % 2 == 0 ? -30 : 30);
- current_positions[RIGHT_PITCH] = 30 + (i % 2 == 0 ? 30 : -30);
- MoveServos(period / 10, current_positions);
- vTaskDelay(pdMS_TO_TICKS(period / 10));
- }
- memcpy(current_positions, servo_initial_, sizeof(current_positions));
- MoveServos(period, current_positions);
- break;
- case 10: // 拍打左手
- current_positions[LEFT_ROLL] = 20;
- MoveServos(period, current_positions);
- for (int i = 0; i < times; i++) {
- current_positions[LEFT_ROLL] = 20 - amount;
- MoveServos(period / 10, current_positions);
- current_positions[LEFT_ROLL] = 20 + amount;
- MoveServos(period / 10, current_positions);
- }
- current_positions[LEFT_ROLL] = 0;
- MoveServos(period, current_positions);
- break;
- case 11: // 拍打右手
- current_positions[RIGHT_ROLL] = 160;
- MoveServos(period, current_positions);
- for (int i = 0; i < times; i++) {
- current_positions[RIGHT_ROLL] = 160 + amount;
- MoveServos(period / 10, current_positions);
- current_positions[RIGHT_ROLL] = 160 - amount;
- MoveServos(period / 10, current_positions);
- }
- current_positions[RIGHT_ROLL] = 180;
- MoveServos(period, current_positions);
- break;
- case 12: // 拍打双手
- current_positions[LEFT_ROLL] = 20;
- current_positions[RIGHT_ROLL] = 160;
- MoveServos(period, current_positions);
- for (int i = 0; i < times; i++) {
- current_positions[LEFT_ROLL] = 20 - amount;
- current_positions[RIGHT_ROLL] = 160 + amount;
- MoveServos(period / 10, current_positions);
- current_positions[LEFT_ROLL] = 20 + amount;
- current_positions[RIGHT_ROLL] = 160 - amount;
- MoveServos(period / 10, current_positions);
- }
- current_positions[LEFT_ROLL] = 0;
- current_positions[RIGHT_ROLL] = 180;
- MoveServos(period, current_positions);
- break;
- }
- }
- //---------------------------------------------------------
- //-- 统一身体动作函数
- //-- Parameters:
- //-- action: 动作类型 1=左转, 2=右转,3=回中心
- //-- times: 转动次数
- //-- amount: 旋转角度 (0-90度,以90度为中心左右旋转)
- //-- period: 动作时间
- //---------------------------------------------------------
- void Otto::BodyAction(int action, int times, int amount, int period) {
- // 限制参数范围
- times = std::max(1, std::min(10, times));
- amount = std::max(0, std::min(90, amount));
- period = std::max(500, std::min(3000, period));
- int current_positions[SERVO_COUNT];
- for (int i = 0; i < SERVO_COUNT; i++) {
- if (servo_pins_[i] != -1) {
- current_positions[i] = servo_[i].GetPosition();
- } else {
- current_positions[i] = servo_initial_[i];
- }
- }
- int body_center = servo_initial_[BODY];
- int target_angle = body_center;
- switch (action) {
- case 1: // 左转
- target_angle = body_center + amount;
- target_angle = std::min(180, target_angle);
- break;
- case 2: // 右转
- target_angle = body_center - amount;
- target_angle = std::max(0, target_angle);
- break;
- case 3: // 回中心
- target_angle = body_center;
- break;
- default:
- return; // 无效动作
- }
- current_positions[BODY] = target_angle;
- MoveServos(period, current_positions);
- vTaskDelay(pdMS_TO_TICKS(100));
- }
- //---------------------------------------------------------
- //-- 统一头部动作函数
- //-- Parameters:
- //-- action: 动作类型 1=抬头, 2=低头, 3=点头, 4=回中心, 5=连续点头
- //-- times: 重复次数 (仅对连续点头有效)
- //-- amount: 角度偏移 (1-15度范围内)
- //-- period: 动作时间
- //---------------------------------------------------------
- void Otto::HeadAction(int action, int times, int amount, int period) {
- // 限制参数范围
- times = std::max(1, std::min(10, times));
- amount = std::max(1, std::min(15, abs(amount)));
- period = std::max(300, std::min(3000, period));
- int current_positions[SERVO_COUNT];
- for (int i = 0; i < SERVO_COUNT; i++) {
- if (servo_pins_[i] != -1) {
- current_positions[i] = servo_[i].GetPosition();
- } else {
- current_positions[i] = servo_initial_[i];
- }
- }
- int head_center = 90; // 头部中心位置
- switch (action) {
- case 1: // 抬头
- current_positions[HEAD] = head_center + amount; // 抬头是增加角度
- MoveServos(period, current_positions);
- break;
- case 2: // 低头
- current_positions[HEAD] = head_center - amount; // 低头是减少角度
- MoveServos(period, current_positions);
- break;
- case 3: // 点头 (上下运动)
- // 先抬头
- current_positions[HEAD] = head_center + amount;
- MoveServos(period / 3, current_positions);
- vTaskDelay(pdMS_TO_TICKS(period / 6));
- // 再低头
- current_positions[HEAD] = head_center - amount;
- MoveServos(period / 3, current_positions);
- vTaskDelay(pdMS_TO_TICKS(period / 6));
- // 回到中心
- current_positions[HEAD] = head_center;
- MoveServos(period / 3, current_positions);
- break;
- case 4: // 回到中心位置
- current_positions[HEAD] = head_center;
- MoveServos(period, current_positions);
- break;
- case 5: // 连续点头
- for (int i = 0; i < times; i++) {
- // 抬头
- current_positions[HEAD] = head_center + amount;
- MoveServos(period / 2, current_positions);
- // 低头
- current_positions[HEAD] = head_center - amount;
- MoveServos(period / 2, current_positions);
- vTaskDelay(pdMS_TO_TICKS(50)); // 短暂停顿
- }
- // 回到中心
- current_positions[HEAD] = head_center;
- MoveServos(period / 2, current_positions);
- break;
- default:
- // 无效动作,回到中心
- current_positions[HEAD] = head_center;
- MoveServos(period, current_positions);
- break;
- }
- }
|