增加重力感应,主打身段要柔软
This commit is contained in:
1 parent
45d8bc4e32
commit
42fd44c28e
2 files changed
+84
-22
No files matched your search
@@ -55,3 +55,5 @@ B站演示地址:https://space.bilibili.com/25336365
|
|||||||
增加手柄震动功能,右扳机按下时,触发震动,连接时震动,断开时震动,起立时震动。
|
增加手柄震动功能,右扳机按下时,触发震动,连接时震动,断开时震动,起立时震动。
|
||||||
|
|
||||||
2025-10-19 v1.2版本优化前后左右跳跃功能,前后长时间倒地后自恢复功能。
|
2025-10-19 v1.2版本优化前后左右跳跃功能,前后长时间倒地后自恢复功能。
|
||||||
|
|
||||||
|
2025-10-30 v1.2增加重力感应,主打身段要柔软。
|
||||||
@@ -15,12 +15,12 @@ Modify by Tommy 2025
|
|||||||
|
|
||||||
|
|
||||||
/************函数申明*************/
|
/************函数申明*************/
|
||||||
|
|
||||||
// 平衡算法函数
|
// 平衡算法函数
|
||||||
void lqr_balance_loop();
|
void lqr_balance_loop();
|
||||||
void yaw_loop();
|
void yaw_loop();
|
||||||
void leg_loop();
|
void leg_loop();
|
||||||
void jump_loop();
|
void jump_loop();
|
||||||
|
void obstacle_jump_loop();
|
||||||
void resetZeroPoint();
|
void resetZeroPoint();
|
||||||
void jump_charge(); // 腿部弯曲(蓄能)
|
void jump_charge(); // 腿部弯曲(蓄能)
|
||||||
|
|
||||||
@@ -28,6 +28,9 @@ void jump_charge(); // 腿部弯曲(蓄能)
|
|||||||
void processControllerData(const XboxControllerNotificationParser& data);
|
void processControllerData(const XboxControllerNotificationParser& data);
|
||||||
void runActionSequence();
|
void runActionSequence();
|
||||||
|
|
||||||
|
// 障碍检测函数
|
||||||
|
void detectObstacle();
|
||||||
|
|
||||||
const int deadZone = 10; // 摇杆死区阈值
|
const int deadZone = 10; // 摇杆死区阈值
|
||||||
bool last_btnA = 0;
|
bool last_btnA = 0;
|
||||||
bool last_btnB = 0;
|
bool last_btnB = 0;
|
||||||
@@ -83,6 +86,7 @@ SMS_STS sms_sts;
|
|||||||
// MPU6050实例
|
// MPU6050实例
|
||||||
MPU6050 mpu6050(I2Ctwo);
|
MPU6050 mpu6050(I2Ctwo);
|
||||||
|
|
||||||
|
|
||||||
/************参数定义*************/
|
/************参数定义*************/
|
||||||
#define pi 3.1415927
|
#define pi 3.1415927
|
||||||
|
|
||||||
@@ -112,6 +116,10 @@ s16 Position[2];
|
|||||||
u16 Speed[2];
|
u16 Speed[2];
|
||||||
byte ACC[2];
|
byte ACC[2];
|
||||||
|
|
||||||
|
int last_servo_load = 0; // 上一时刻的舵机2负载
|
||||||
|
unsigned long last_servo_sample_time = 0; // 上一次负载采样时间
|
||||||
|
const unsigned long SERVO_SAMPLE_INTERVAL = 300; // 负载采样间隔(500毫秒)
|
||||||
|
|
||||||
// 腿部高度逻辑
|
// 腿部高度逻辑
|
||||||
// float leg_height_base 20 # 基准值
|
// float leg_height_base 20 # 基准值
|
||||||
// float LegHeightDiff ; # 根据前后转向运动时,智能计算两腿高度差
|
// float LegHeightDiff ; # 根据前后转向运动时,智能计算两腿高度差
|
||||||
@@ -137,6 +145,7 @@ float LQR_u = 0;
|
|||||||
float angle_zeropoint = 8; // 5 设定默认俯仰角度,向前到正,向后倒负
|
float angle_zeropoint = 8; // 5 设定默认俯仰角度,向前到正,向后倒负
|
||||||
float original_angle_zeropoint = 8; // 保存原始的角度零点
|
float original_angle_zeropoint = 8; // 保存原始的角度零点
|
||||||
float distance_zeropoint = 0.5f; // 轮部位移零点偏置
|
float distance_zeropoint = 0.5f; // 轮部位移零点偏置
|
||||||
|
// float pitch_adjust = 0.0f; // 俯仰角度调整
|
||||||
|
|
||||||
// YAW轴控制数据
|
// YAW轴控制数据
|
||||||
float YAW_gyro = 0;
|
float YAW_gyro = 0;
|
||||||
@@ -152,18 +161,23 @@ const unsigned long SPEED_RECORD_INTERVAL = 100; // 转速记录间隔(毫秒)
|
|||||||
float last_lqr_speed = 0; // 记录上一时刻的轮部转速
|
float last_lqr_speed = 0; // 记录上一时刻的轮部转速
|
||||||
float robot_speed_diff = 0; // 速度差
|
float robot_speed_diff = 0; // 速度差
|
||||||
|
|
||||||
|
|
||||||
int jump_flag = 0; // 跳跃过程计数
|
int jump_flag = 0; // 跳跃过程计数
|
||||||
|
int jump_pre_flag = 0; // 跳跃前蓄能计数
|
||||||
|
|
||||||
int forward_jump_flag = 0; // 前跳跃标志位
|
int forward_jump_flag = 0; // 前跳跃标志位
|
||||||
int back_jump_flag = 0; // 后跳跃标志位
|
int back_jump_flag = 0; // 后跳跃标志位
|
||||||
int left_jump_flag = 0; // 左跳跃标志位
|
int left_jump_flag = 0; // 左跳跃标志位
|
||||||
int right_jump_flag = 0; // 右跳跃标志位
|
int right_jump_flag = 0; // 右跳跃标志位
|
||||||
int jump_pre_flag = 0; // 跳跃前蓄能计数
|
|
||||||
int wheel_ground_flag = 1; // 轮子是否离地标记 默认离地
|
|
||||||
|
|
||||||
|
int wheel_ground_flag = 1; // 轮子是否离地标记 默认离地
|
||||||
|
|
||||||
// 倒地恢复计数
|
// 倒地恢复计数
|
||||||
int fallRecoveryResetCounter = 0;
|
int fallRecoveryResetCounter = 0;
|
||||||
|
|
||||||
|
// 快速下坠检测相关参数
|
||||||
|
bool is_falling = false; // 快速下坠状态标志
|
||||||
|
|
||||||
// 小车状态控制
|
// 小车状态控制
|
||||||
// bool robot_enabled = true; // 小车使能状态,true为起立状态,false为坐下状态
|
// bool robot_enabled = true; // 小车使能状态,true为起立状态,false为坐下状态
|
||||||
// bool last_robot_enabled = true; // 记录上一次的小车状态
|
// bool last_robot_enabled = true; // 记录上一次的小车状态
|
||||||
@@ -173,8 +187,9 @@ int fallRecoveryResetCounter = 0;
|
|||||||
bool robot_enabled = false; // 开机禁用平衡,默认坐下
|
bool robot_enabled = false; // 开机禁用平衡,默认坐下
|
||||||
bool last_robot_enabled = false; // 同步初始状态
|
bool last_robot_enabled = false; // 同步初始状态
|
||||||
int sitting_down = 1; // 开机直接进入“坐下状态”,避免无控制
|
int sitting_down = 1; // 开机直接进入“坐下状态”,避免无控制
|
||||||
|
int stand_up_count = 0; // 站立标志位
|
||||||
|
|
||||||
// 动作执行状态管理
|
// 动作组执行状态管理
|
||||||
bool isExecutingAction = false;
|
bool isExecutingAction = false;
|
||||||
bool isPausing = false;
|
bool isPausing = false;
|
||||||
unsigned long currentPauseDuration = 0;
|
unsigned long currentPauseDuration = 0;
|
||||||
@@ -296,9 +311,12 @@ void loop()
|
|||||||
bat_check(); // 电压检测
|
bat_check(); // 电压检测
|
||||||
delayMicroseconds(1500);
|
delayMicroseconds(1500);
|
||||||
mpu6050.update(); // IMU数据更新
|
mpu6050.update(); // IMU数据更新
|
||||||
|
|
||||||
lqr_balance_loop(); // lqr自平衡控制
|
lqr_balance_loop(); // lqr自平衡控制
|
||||||
|
|
||||||
yaw_loop(); // yaw轴转向控制
|
yaw_loop(); // yaw轴转向控制
|
||||||
jump_loop(); // 跳跃动作
|
jump_loop(); // 跳跃动作
|
||||||
|
|
||||||
leg_loop(); // 腿部动作控制
|
leg_loop(); // 腿部动作控制
|
||||||
|
|
||||||
runActionSequence(); // 执行动作序列
|
runActionSequence(); // 执行动作序列
|
||||||
@@ -332,29 +350,30 @@ void loop()
|
|||||||
// 达到平衡角度后,重置重置计数器
|
// 达到平衡角度后,重置重置计数器
|
||||||
if( abs(LQR_angle) < 25.0f){
|
if( abs(LQR_angle) < 25.0f){
|
||||||
fallRecoveryResetCounter = 0;
|
fallRecoveryResetCounter = 0;
|
||||||
|
stand_up_count = 0;
|
||||||
}
|
}
|
||||||
|
// Serial.println(String(LQR_angle));
|
||||||
|
|
||||||
// 向左跳跃
|
// 向左跳跃
|
||||||
if ( left_jump_flag > 2 && left_jump_flag < 20) {
|
if ( left_jump_flag > 2) {
|
||||||
motor1.target = 5.0; // 脉冲
|
motor1.target = 5.0; // 脉冲
|
||||||
motor2.target = -5.0;
|
motor2.target = -5.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 向右跳跃
|
// 向右跳跃
|
||||||
if ( right_jump_flag > 2 && right_jump_flag < 20) {
|
if ( right_jump_flag > 2) {
|
||||||
motor1.target = -5.0; // 脉冲
|
motor1.target = -5.0; // 脉冲
|
||||||
motor2.target = 5.0;
|
motor2.target = 5.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 向前跳跃
|
// 向前跳跃
|
||||||
if ( forward_jump_flag > 2 && forward_jump_flag < 20) {
|
if ( forward_jump_flag > 2) {
|
||||||
motor1.target = 2.3; // 脉冲
|
motor1.target = 2.3; // 脉冲
|
||||||
motor2.target = 2.3;
|
motor2.target = 2.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 向后跳跃
|
// 向后跳跃
|
||||||
if ( back_jump_flag > 2 && back_jump_flag < 15) {
|
if ( back_jump_flag > 2 ) {
|
||||||
motor1.target = -1.0; // 脉冲
|
motor1.target = -1.0; // 脉冲
|
||||||
motor2.target = -1.0;
|
motor2.target = -1.0;
|
||||||
}
|
}
|
||||||
@@ -442,9 +461,13 @@ void lqr_balance_loop()
|
|||||||
LQR_distance = (-0.5) * (motor1.shaft_angle + motor2.shaft_angle); // 两个电机的旋转角度(shaft_angle),单位:弧度(rad)实际位移量
|
LQR_distance = (-0.5) * (motor1.shaft_angle + motor2.shaft_angle); // 两个电机的旋转角度(shaft_angle),单位:弧度(rad)实际位移量
|
||||||
LQR_speed = (-0.5) * (motor1.shaft_velocity + motor2.shaft_velocity); // 两个电机角速度(shaft_velocity),单位:弧度 / 秒(rad/s)
|
LQR_speed = (-0.5) * (motor1.shaft_velocity + motor2.shaft_velocity); // 两个电机角速度(shaft_velocity),单位:弧度 / 秒(rad/s)
|
||||||
LQR_angle = (float)mpu6050.getAngleY(); // mpu6050 pitch 角度,单位:度(°)
|
LQR_angle = (float)mpu6050.getAngleY(); // mpu6050 pitch 角度,单位:度(°)
|
||||||
|
|
||||||
|
// Serial.print("LQR_angle:");
|
||||||
|
// Serial.println(LQR_angle);
|
||||||
|
|
||||||
LQR_gyro = (float)mpu6050.getGyroY(); // pitch Y轴角速度,单位:度 / 秒(°/s)
|
LQR_gyro = (float)mpu6050.getGyroY(); // pitch Y轴角速度,单位:度 / 秒(°/s)
|
||||||
|
|
||||||
angle_control = pid_angle(LQR_angle - angle_zeropoint);
|
angle_control = pid_angle(LQR_angle - angle_zeropoint); // pitch_adjust
|
||||||
gyro_control = pid_gyro(LQR_gyro);
|
gyro_control = pid_gyro(LQR_gyro);
|
||||||
|
|
||||||
// 前进后退跳跃的系数都不一样
|
// 前进后退跳跃的系数都不一样
|
||||||
@@ -468,23 +491,22 @@ void lqr_balance_loop()
|
|||||||
|
|
||||||
if(robot_speed_diff > 18.0) // 轮子离地
|
if(robot_speed_diff > 18.0) // 轮子离地
|
||||||
{
|
{
|
||||||
wheel_ground_flag = 0; // 轮子离地标记
|
// wheel_ground_flag = 0; // 轮子离地标记
|
||||||
// Serial.print("TAKE OFF");
|
// Serial.print("TAKE OFF");
|
||||||
// Serial.print(wheel_ground_flag);
|
// Serial.print(wheel_ground_flag);
|
||||||
// Serial.print(",robot_speed_diff:");
|
// Serial.print(",robot_speed_diff:");
|
||||||
// Serial.print(robot_speed_diff);
|
// Serial.println(robot_speed_diff);
|
||||||
// Serial.print(",jump_flag:");
|
// Serial.print(",jump_flag:");
|
||||||
// Serial.println(jump_flag); // 100 左右
|
// Serial.println(jump_flag); // 100 左右
|
||||||
}
|
}
|
||||||
if( robot_speed_diff < -9.0) // 轮子着地
|
if( robot_speed_diff < -9.0) // 轮子着地
|
||||||
{
|
{
|
||||||
wheel_ground_flag = 1; // 轮子着地标记
|
// wheel_ground_flag = 1; // 轮子着地标记
|
||||||
// Serial.print("LANDING:");
|
// Serial.print("LANDING:");
|
||||||
// Serial.print(",robot_speed_diff:");
|
// Serial.print(",robot_speed_diff:");
|
||||||
// Serial.print(robot_speed_diff);
|
// Serial.println(robot_speed_diff);
|
||||||
// Serial.print(",jump_flag:");
|
// Serial.print(",jump_flag:");
|
||||||
// Serial.println(jump_flag); // 120左右
|
// Serial.println(jump_flag); // 120左右
|
||||||
|
|
||||||
if( jump_flag ){ // 落地点作为新的位移零点
|
if( jump_flag ){ // 落地点作为新的位移零点
|
||||||
resetZeroPoint();
|
resetZeroPoint();
|
||||||
}
|
}
|
||||||
@@ -550,12 +572,39 @@ void lqr_balance_loop()
|
|||||||
void leg_loop()
|
void leg_loop()
|
||||||
{
|
{
|
||||||
// 如果坐下就不控制腿部
|
// 如果坐下就不控制腿部
|
||||||
if(sitting_down || jump_flag || jump_pre_flag || left_jump_flag || right_jump_flag || forward_jump_flag || back_jump_flag){
|
if(sitting_down
|
||||||
|
|| jump_flag || jump_pre_flag
|
||||||
|
|| left_jump_flag || right_jump_flag || forward_jump_flag || back_jump_flag){
|
||||||
return; // 跳过后续leg高度计算
|
return; // 跳过后续leg高度计算
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 1. 获取并处理MPU6050 Z轴加速度
|
||||||
|
float z_accel = mpu6050.getAccZ(); // 1.1~1.2左右
|
||||||
|
|
||||||
// 机身大角度,譬如倒地时,强制腿部收缩
|
// 2. 快速下坠检测与处理
|
||||||
|
if (z_accel >1.8f && !is_falling && stand_up_count == 0) {
|
||||||
|
is_falling = true;
|
||||||
|
// 腿部收缩
|
||||||
|
ACC[0] = 250;
|
||||||
|
ACC[1] = 250;
|
||||||
|
Speed[0] = 1000;
|
||||||
|
Speed[1] = 1000;
|
||||||
|
Position[0] = SERVO0_MIN + 150;
|
||||||
|
Position[1] = SERVO1_MIN - 150;
|
||||||
|
sms_sts.SyncWritePosEx(ID, 2, Position, Speed, ACC);
|
||||||
|
return; // 跳过后续正常高度计算
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 下坠结束判断与恢复逻辑
|
||||||
|
if (is_falling) {
|
||||||
|
if (!sms_sts.ReadMove(ID[0]) && !sms_sts.ReadMove(ID[1])) {
|
||||||
|
is_falling = false;
|
||||||
|
}else{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 机身大角度倒地时,强制腿部收缩
|
||||||
if (abs(LQR_angle) > 25.0f)
|
if (abs(LQR_angle) > 25.0f)
|
||||||
{
|
{
|
||||||
// 默认舵机速度和加速度
|
// 默认舵机速度和加速度
|
||||||
@@ -569,6 +618,7 @@ void leg_loop()
|
|||||||
return; // 跳过后续leg高度计算
|
return; // 跳过后续leg高度计算
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 正常腿部高度计算
|
||||||
ACC[0] = wrobot.acc0; // 强转为byte(舵机库要求)
|
ACC[0] = wrobot.acc0; // 强转为byte(舵机库要求)
|
||||||
ACC[1] = wrobot.acc1;
|
ACC[1] = wrobot.acc1;
|
||||||
Speed[0] = wrobot.speed0; // 强转为u16(舵机库要求)
|
Speed[0] = wrobot.speed0; // 强转为u16(舵机库要求)
|
||||||
@@ -648,28 +698,28 @@ void jump_loop()
|
|||||||
if( left_jump_flag ){
|
if( left_jump_flag ){
|
||||||
left_jump_flag ++ ;
|
left_jump_flag ++ ;
|
||||||
|
|
||||||
if( left_jump_flag >= 20 ){
|
if( left_jump_flag > 20 ){
|
||||||
left_jump_flag = 0;
|
left_jump_flag = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}else if( right_jump_flag ){
|
}else if( right_jump_flag ){
|
||||||
right_jump_flag ++ ;
|
right_jump_flag ++ ;
|
||||||
|
|
||||||
if( right_jump_flag >= 20 ){
|
if( right_jump_flag > 20 ){
|
||||||
right_jump_flag = 0;
|
right_jump_flag = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}else if( forward_jump_flag ){
|
}else if( forward_jump_flag ){
|
||||||
forward_jump_flag ++ ;
|
forward_jump_flag ++ ;
|
||||||
|
|
||||||
if(forward_jump_flag >= 15){ // 向前跳跃只有20个脉冲
|
if(forward_jump_flag > 20){ // 向前跳跃只有20个脉冲
|
||||||
forward_jump_flag = 0;
|
forward_jump_flag = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}else if( back_jump_flag ){
|
}else if( back_jump_flag ){
|
||||||
back_jump_flag ++ ;
|
back_jump_flag ++ ;
|
||||||
|
|
||||||
if(back_jump_flag >= 20){
|
if(back_jump_flag > 15){
|
||||||
back_jump_flag = 0;
|
back_jump_flag = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -803,7 +853,6 @@ void processControllerData(const XboxControllerNotificationParser& remoteData) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 坐下
|
// 坐下
|
||||||
if (remoteData.btnLB && !last_btnLB && robot_enabled) {
|
if (remoteData.btnLB && !last_btnLB && robot_enabled) {
|
||||||
robot_enabled = false;
|
robot_enabled = false;
|
||||||
@@ -820,6 +869,7 @@ void processControllerData(const XboxControllerNotificationParser& remoteData) {
|
|||||||
if (remoteData.btnRB && !robot_enabled) {
|
if (remoteData.btnRB && !robot_enabled) {
|
||||||
robot_enabled = true;
|
robot_enabled = true;
|
||||||
sitting_down = 0; // 清除坐下动作标记
|
sitting_down = 0; // 清除坐下动作标记
|
||||||
|
stand_up_count ++; // 站立标志位
|
||||||
}
|
}
|
||||||
last_btnRB = remoteData.btnRB;
|
last_btnRB = remoteData.btnRB;
|
||||||
|
|
||||||
@@ -880,6 +930,7 @@ void processControllerData(const XboxControllerNotificationParser& remoteData) {
|
|||||||
if(remoteData.btnDirUp) {
|
if(remoteData.btnDirUp) {
|
||||||
leg_height_base -= 0.20;
|
leg_height_base -= 0.20;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 下降
|
// 下降
|
||||||
if(remoteData.btnDirDown) {
|
if(remoteData.btnDirDown) {
|
||||||
leg_height_base += 0.20;
|
leg_height_base += 0.20;
|
||||||
@@ -957,6 +1008,15 @@ void processControllerData(const XboxControllerNotificationParser& remoteData) {
|
|||||||
XboxtrigRTVibration();
|
XboxtrigRTVibration();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 舵机中位校准 中间十字左右键同时按下
|
||||||
|
if (remoteData.btnSelect && !last_btnSelect && remoteData.btnStart && !last_btnStart) {
|
||||||
|
sms_sts.CalibrationOfs(ID[0]);
|
||||||
|
sms_sts.CalibrationOfs(ID[1]);
|
||||||
|
XboxKeyVibration(100,1000); // 震动
|
||||||
|
Serial.println("CalibrationOfs");
|
||||||
|
}
|
||||||
|
last_btnSelect = remoteData.btnSelect;
|
||||||
|
last_btnStart = remoteData.btnStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 执行连续动作的函数
|
// 执行连续动作的函数
|
||||||
|
|||||||
Reference in new issue
Block a user