Initial commit

This commit is contained in:
2026-04-26 21:35:04 +08:00
commit da6ca1b09a
1483 changed files with 115719 additions and 0 deletions

View File

@@ -0,0 +1,577 @@
#include "eda_dog_movements.h"
#include <algorithm>
#include <cmath>
#include "oscillator.h"
static const char *TAG = "EDARobotDogMovements";
#define LEG_HOME_POSITION 90
EDARobotDog::EDARobotDog() {
is_dog_resting_ = false;
// 初始化所有舵机管脚为-1未连接
for (int i = 0; i < SERVO_COUNT; i++) {
servo_pins_[i] = -1;
servo_trim_[i] = 0;
}
}
EDARobotDog::~EDARobotDog() { DetachServos(); }
unsigned long IRAM_ATTR millis() {
return (unsigned long)(esp_timer_get_time() / 1000ULL);
}
void EDARobotDog::Init(int left_front_leg, int left_rear_leg, int right_front_leg,
int right_rear_leg) {
servo_pins_[LEFT_FRONT_LEG] = left_front_leg;
servo_pins_[LEFT_REAR_LEG] = left_rear_leg;
servo_pins_[RIGHT_FRONT_LEG] = right_front_leg;
servo_pins_[RIGHT_REAR_LEG] = right_rear_leg;
AttachServos();
is_dog_resting_ = false;
}
///////////////////////////////////////////////////////////////////
//-- ATTACH & DETACH FUNCTIONS ----------------------------------//
///////////////////////////////////////////////////////////////////
void EDARobotDog::AttachServos() {
for (int i = 0; i < SERVO_COUNT; i++) {
if (servo_pins_[i] != -1) {
servo_[i].Attach(servo_pins_[i]);
}
}
}
void EDARobotDog::DetachServos() {
for (int i = 0; i < SERVO_COUNT; i++) {
if (servo_pins_[i] != -1) {
servo_[i].Detach();
}
}
}
///////////////////////////////////////////////////////////////////
//-- OSCILLATORS TRIMS ------------------------------------------//
///////////////////////////////////////////////////////////////////
void EDARobotDog::SetTrims(int left_front_leg, int left_rear_leg,
int right_front_leg, int right_rear_leg) {
servo_trim_[LEFT_FRONT_LEG] = left_front_leg;
servo_trim_[LEFT_REAR_LEG] = left_rear_leg;
servo_trim_[RIGHT_FRONT_LEG] = right_front_leg;
servo_trim_[RIGHT_REAR_LEG] = right_rear_leg;
for (int i = 0; i < SERVO_COUNT; i++) {
if (servo_pins_[i] != -1) {
servo_[i].SetTrim(servo_trim_[i]);
}
}
}
///////////////////////////////////////////////////////////////////
//-- BASIC MOTION FUNCTIONS -------------------------------------//
///////////////////////////////////////////////////////////////////
void EDARobotDog::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 EDARobotDog::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 EDARobotDog::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 EDARobotDog::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 = Dog at rest position --------------------------------//
///////////////////////////////////////////////////////////////////
void EDARobotDog::Home() {
if (is_dog_resting_ == false) { // Go to rest position only if necessary
int homes[SERVO_COUNT] = {LEG_HOME_POSITION, LEG_HOME_POSITION,
LEG_HOME_POSITION, LEG_HOME_POSITION};
MoveServos(500, homes);
is_dog_resting_ = true;
}
vTaskDelay(pdMS_TO_TICKS(200));
}
bool EDARobotDog::GetRestState() { return is_dog_resting_; }
void EDARobotDog::SetRestState(bool state) { is_dog_resting_ = state; }
///////////////////////////////////////////////////////////////////
//-- BASIC LEG MOVEMENTS ----------------------------------------//
///////////////////////////////////////////////////////////////////
void EDARobotDog::LiftLeftFrontLeg(int period, int height) {
// 获取当前位置
int current_pos[SERVO_COUNT];
for (int i = 0; i < SERVO_COUNT; i++) {
if (servo_pins_[i] != -1) {
current_pos[i] = servo_[i].GetPosition();
} else {
current_pos[i] = LEG_HOME_POSITION;
}
}
// 重复3次摇摆动作
for (int num = 0; num < 3; num++) {
// servo1.write(180); delay(100);
current_pos[LEFT_FRONT_LEG] = 0; // servo1
MoveServos(100, current_pos);
// servo1.write(150); delay(100);
current_pos[LEFT_FRONT_LEG] = 30; // servo1
MoveServos(100, current_pos);
}
// servo1.write(90);
current_pos[LEFT_FRONT_LEG] = 90; // servo1
MoveServos(100, current_pos);
}
void EDARobotDog::LiftLeftRearLeg(int period, int height) {
// 获取当前位置
int current_pos[SERVO_COUNT];
for (int i = 0; i < SERVO_COUNT; i++) {
if (servo_pins_[i] != -1) {
current_pos[i] = servo_[i].GetPosition();
} else {
current_pos[i] = LEG_HOME_POSITION;
}
}
// 重复3次摇摆动作
for (int num = 0; num < 3; num++) {
// servo1.write(180); delay(100);
current_pos[LEFT_REAR_LEG] = 180; // servo1
MoveServos(100, current_pos);
// servo1.write(150); delay(100);
current_pos[LEFT_REAR_LEG] = 150; // servo1
MoveServos(100, current_pos);
}
// servo1.write(90);
current_pos[LEFT_REAR_LEG] = 90; // servo1
MoveServos(100, current_pos);
}
void EDARobotDog::LiftRightFrontLeg(int period, int height) {
// 获取当前位置
int current_pos[SERVO_COUNT];
for (int i = 0; i < SERVO_COUNT; i++) {
if (servo_pins_[i] != -1) {
current_pos[i] = servo_[i].GetPosition();
} else {
current_pos[i] = LEG_HOME_POSITION;
}
}
// 重复3次摇摆动作
for (int num = 0; num < 3; num++) {
// servo1.write(180); delay(100);
current_pos[RIGHT_FRONT_LEG] = 180; // servo1
MoveServos(100, current_pos);
// servo1.write(150); delay(100);
current_pos[RIGHT_FRONT_LEG] = 150; // servo1
MoveServos(100, current_pos);
}
// servo1.write(90);
current_pos[RIGHT_FRONT_LEG] = 90; // servo1
MoveServos(100, current_pos);
}
void EDARobotDog::LiftRightRearLeg(int period, int height) {
// 获取当前位置
int current_pos[SERVO_COUNT];
for (int i = 0; i < SERVO_COUNT; i++) {
if (servo_pins_[i] != -1) {
current_pos[i] = servo_[i].GetPosition();
} else {
current_pos[i] = LEG_HOME_POSITION;
}
}
// 重复3次摇摆动作
for (int num = 0; num < 3; num++) {
// servo1.write(180); delay(100);
current_pos[RIGHT_REAR_LEG] = 0; // servo1
MoveServos(100, current_pos);
// servo1.write(150); delay(100);
current_pos[RIGHT_REAR_LEG] = 30; // servo1
MoveServos(100, current_pos);
}
// servo1.write(90);
current_pos[RIGHT_FRONT_LEG] = 90; // servo1
MoveServos(100, current_pos);
}
///////////////////////////////////////////////////////////////////
//-- DOG GAIT MOVEMENTS -----------------------------------------//
///////////////////////////////////////////////////////////////////
// 舵机方向分析(从 Stretch/Sleep 推断物理前后方向):
//
// Stretch: LF=0, LR=180, RF=180, RR=0
// → 前腿向前伸,后腿向后伸
//
// LEFT_FRONT_LEG (0): 减小=向前, 增大=向后
// LEFT_REAR_LEG (1): 减小=向前, 增大=向后
// RIGHT_FRONT_LEG (2): 增大=向前, 减小=向后
// RIGHT_REAR_LEG (3): 增大=向前, 减小=向后
//
// 即:左侧两腿同向(减=前),右侧两腿同向(增=前)
// 对角线A: 左前 + 右后 → 前进时左前减小, 右后减小(都是各自的"向前"
// 对角线B: 左后 + 右前 → 前进时左后减小, 右前增大(都是各自的"向前"
//
// 抬腿方向(从 Lift 函数):
// LEFT_FRONT_LEG: 0° (减小=抬)
// LEFT_REAR_LEG: 180° (增大=抬)
// RIGHT_FRONT_LEG: 180° (增大=抬)
// RIGHT_REAR_LEG: 0° (减小=抬)
// 辅助:获取当前所有舵机位置
void EDARobotDog::GetCurrentPositions(int pos[SERVO_COUNT]) {
for (int i = 0; i < SERVO_COUNT; i++) {
if (servo_pins_[i] != -1) {
pos[i] = servo_[i].GetPosition();
} else {
pos[i] = LEG_HOME_POSITION;
}
}
}
void EDARobotDog::Turn(float steps, int period, int dir) {
if (GetRestState() == true) {
SetRestState(false);
}
// 转弯 = 左侧后退 + 右侧前进(左转),或反过来(右转)
// 从 Walk 的已验证方向推导:
// 前进: LF=90-s, LR=90-s, RF=90+s, RR=90+s
// 后退: LF=90+s, LR=90+s, RF=90-s, RR=90-s
//
// 左转(d=1): 左侧后退+右侧前进
// LF=90+s, LR=90+s, RF=90+s, RR=90+s → 全部 90+s
// 地面反推: 全部 90-s
//
// 右转(d=-1): 左侧前进+右侧后退
// LF=90-s, LR=90-s, RF=90-s, RR=90-s → 全部 90-s
// 地面反推: 全部 90+s
const int swing = 60;
const int lift = 25;
int t = period / 6;
if (t < 50) t = 50;
int d = (dir == LEFT) ? -1 : 1;
for (int step = 0; step < (int)steps; step++) {
int pos[SERVO_COUNT];
GetCurrentPositions(pos);
// 拍1: 抬ALF+RR
pos[LEFT_FRONT_LEG] = 90 - lift;
pos[RIGHT_REAR_LEG] = 90 - lift;
MoveServos(t, pos);
// 拍2: A空中摆 + B地面反推
pos[LEFT_FRONT_LEG] = 90 - lift + d * swing; // LF空中
pos[RIGHT_REAR_LEG] = 90 - lift + d * swing; // RR空中
pos[LEFT_REAR_LEG] = 90 - d * swing; // LR地面反推
pos[RIGHT_FRONT_LEG] = 90 - d * swing; // RF地面反推
MoveServos(t, pos);
// 拍3: 放下A
pos[LEFT_FRONT_LEG] = 90 + d * swing;
pos[RIGHT_REAR_LEG] = 90 + d * swing;
MoveServos(t / 2, pos);
// 拍4: 抬BLR+RF
pos[LEFT_REAR_LEG] = 90 + lift;
pos[RIGHT_FRONT_LEG] = 90 + lift;
MoveServos(t, pos);
// 拍5: B空中摆 + A地面反推
pos[LEFT_REAR_LEG] = 90 + lift + d * swing; // LR空中
pos[RIGHT_FRONT_LEG] = 90 + lift + d * swing; // RF空中
pos[LEFT_FRONT_LEG] = 90 - d * swing; // LF地面反推
pos[RIGHT_REAR_LEG] = 90 - d * swing; // RR地面反推
MoveServos(t, pos);
// 拍6: 放下B
pos[LEFT_REAR_LEG] = 90 + d * swing;
pos[RIGHT_FRONT_LEG] = 90 + d * swing;
MoveServos(t / 2, pos);
}
// 结束回中
int home[SERVO_COUNT] = {90, 90, 90, 90};
MoveServos(150, home);
}
void EDARobotDog::Walk(float steps, int period, int dir) {
if (GetRestState() == true) {
SetRestState(false);
}
// Trot 对角步态
// 方向: LF减=前, LR减=前, RF增=前, RR增=前
// 抬腿: LF减=抬, LR增=抬, RF增=抬, RR减=抬
const int lift = 25;
const int swing = 30;
int t = period / 6;
if (t < 50) t = 50;
int fwd = (dir == FORWARD) ? 1 : -1;
for (int step = 0; step < (int)steps; step++) {
int pos[SERVO_COUNT];
GetCurrentPositions(pos);
// 拍1: 抬起对角线ALF+RR
pos[LEFT_FRONT_LEG] = 90 - lift;
pos[RIGHT_REAR_LEG] = 90 - lift;
MoveServos(t, pos);
// 拍2: A空中前摆 + B地面后推同时
pos[LEFT_FRONT_LEG] = 90 - lift - fwd * swing; // LF: 保持抬 + 前摆
pos[RIGHT_REAR_LEG] = 90 - lift + fwd * swing; // RR: 保持抬 + 前摆(增=前)
pos[LEFT_REAR_LEG] = 90 + fwd * swing; // LR: 地面后推(增=后)
pos[RIGHT_FRONT_LEG] = 90 - fwd * swing; // RF: 地面后推(减=后)
MoveServos(t, pos);
// 拍3: 放下A着地到前摆位置
pos[LEFT_FRONT_LEG] = 90 - fwd * swing;
pos[RIGHT_REAR_LEG] = 90 + fwd * swing;
MoveServos(t / 2, pos);
// 拍4: 抬起对角线BLR+RF
pos[LEFT_REAR_LEG] = 90 + lift;
pos[RIGHT_FRONT_LEG] = 90 + lift;
MoveServos(t, pos);
// 拍5: B空中前摆 + A地面后推同时
pos[LEFT_REAR_LEG] = 90 + lift - fwd * swing; // LR: 保持抬 + 前摆(减=前)
pos[RIGHT_FRONT_LEG] = 90 + lift + fwd * swing; // RF: 保持抬 + 前摆(增=前)
pos[LEFT_FRONT_LEG] = 90 + fwd * swing; // LF: 地面后推(增=后)
pos[RIGHT_REAR_LEG] = 90 - fwd * swing; // RR: 地面后推(减=后)
MoveServos(t, pos);
// 拍6: 放下B不回中直接衔接下一步
pos[LEFT_REAR_LEG] = 90 - fwd * swing;
pos[RIGHT_FRONT_LEG] = 90 + fwd * swing;
MoveServos(t / 2, pos);
}
// 结束回中
int home[SERVO_COUNT] = {90, 90, 90, 90};
MoveServos(150, home);
}
void EDARobotDog::Sit(int period) {
int current_pos[SERVO_COUNT];
for (int i = 0; i < SERVO_COUNT; i++) {
if (servo_pins_[i] != -1) {
current_pos[i] = servo_[i].GetPosition();
} else {
current_pos[i] = LEG_HOME_POSITION;
}
}
current_pos[LEFT_REAR_LEG] = 0; // servo2
current_pos[RIGHT_REAR_LEG] = 180; // servo4
MoveServos(100, current_pos);
}
void EDARobotDog::Stand(int period) {
// 站立:所有腿回到中立位置
Home();
}
void EDARobotDog::Stretch(int period) {
// 获取当前位置
int current_pos[SERVO_COUNT];
for (int i = 0; i < SERVO_COUNT; i++) {
if (servo_pins_[i] != -1) {
current_pos[i] = servo_[i].GetPosition();
} else {
current_pos[i] = LEG_HOME_POSITION;
}
}
current_pos[LEFT_FRONT_LEG] = 0; // servo1
current_pos[RIGHT_REAR_LEG] = 0; // servo3
current_pos[LEFT_REAR_LEG] = 180; // servo2
current_pos[RIGHT_FRONT_LEG] = 180; // servo4
MoveServos(100, current_pos);
}
void EDARobotDog::Shake(int period) {
// 摇摆:左右摇摆身体,左前腿和右后腿运动方向相反
int A[SERVO_COUNT] = {20, 0, 20, 0}; // 只有前腿摇摆
int O[SERVO_COUNT] = {0, LEG_HOME_POSITION, 0, LEG_HOME_POSITION};
// 左前腿和右前腿反相摇摆
double phase_diff[SERVO_COUNT] = {DEG2RAD(180), 0, DEG2RAD(0), 0};
Execute(A, O, period, phase_diff, 3);
}
void EDARobotDog::EnableServoLimit(int diff_limit) {
for (int i = 0; i < SERVO_COUNT; i++) {
if (servo_pins_[i] != -1) {
servo_[i].SetLimiter(diff_limit);
}
}
}
void EDARobotDog::DisableServoLimit() {
for (int i = 0; i < SERVO_COUNT; i++) {
if (servo_pins_[i] != -1) {
servo_[i].DisableLimiter();
}
}
}
void EDARobotDog::Sleep() {
int current_pos[SERVO_COUNT];
for (int i = 0; i < SERVO_COUNT; i++) {
if (servo_pins_[i] != -1) {
current_pos[i] = servo_[i].GetPosition();
} else {
current_pos[i] = LEG_HOME_POSITION;
}
}
// servo1.write(0); servo3.write(180); servo2.write(180); servo4.write(0);
current_pos[LEFT_FRONT_LEG] = 0; // servo1
current_pos[RIGHT_REAR_LEG] = 180; // servo3
current_pos[LEFT_REAR_LEG] = 180; // servo2
current_pos[RIGHT_FRONT_LEG] = 0; // servo4
MoveServos(100, current_pos);
}