肥仔教程网

SEO 优化与 Web 开发技术学习分享平台

Huawei's Kirin 9020 Return Signals New Era for China's Semiconductor Industry

Model of a semiconductor hybrid bonding device, photographed by the author during the Semiconductor Equipment, Core Components & Materials Exhibition (CSEAC 2025)

TMTPOST -- Huawei’s latest product launch marks the return of its Kirin 9020 chip after four years, a move industry experts say could reshape China’s semiconductor sector.

Fairness, justice most important value of int'l community, says Chinese premier

Chinese Premier Li Qiang delivers a speech at the general debate of the 80th session of the UN General Assembly at the UN headquarters in New York, Sept. 26, 2025. [Photo byLiu Bin/Xinhua]

China-CEEC expo is reiteration of Beijing's commitment to openness

By Azhar Azam

The 4th China-CEEC (Central and Eastern European Countries) Expo & International Consumer Goods Fair is being held at Ningbo, Zhejiang between May 22 and 25. The event is expected to be one of the major platforms for CEEC to showcase their products, expand exports to one of the world's largest consumer markets and promote economic and trade cooperation with the East Asian economic powerhouse.

Global Governance Initiative a vision for revitalizing global governance

Chinese President Xi Jinping addresses the United Nations Climate Summit 2025 in New York by video on September 24, 2025. [Photo/Xinhua]

By Pan Deng

Ethnic costume fashion show staged in Beijing

Caption 1:Miao ethnic designer Yang Chunlin and his mother, Yang Shiying, an inheritor of Miao embroidery, pose for photosalongside modelsduring an ethnic costume fashion show in Beijing,Sept. 12, 2025. [Photo by Zhang Junmian/China.org.cn]

Upholding ideals and purpose of UN vital to realizing community with a shared future

Upholdingideals and purpose of UN vital to realizing community with a shared future: China Daily editorial - Opinion - Chinadaily.com.cn

This is an editorial from China Daily.

Beyond tourism: ROK-China visa shift sparks new dialogue

By Xiang Haoyu

Starting from Monday, the Republic of Korea (ROK) will implement a temporary visa-free policy for Chinese tour groups lasting nine months. This move is a positive response to China's unilateral visa exemption for South Korean visitors introduced last November. It is expected not only to deliver a strong boost to Seoul's economy, but also to serve as encouraging news for the development of China-ROK relations.

报告说“半月板2级损伤”,医生却说没事?

50多岁的王阿姨最近发现,上下楼梯时总感觉膝关节疼痛,过了2周时间症状也没有明显好转。身边的朋友都说,可能是膝关节半月板出了问题。

How common values of humanity address global challenges

By Zheng Haizhen

In September 2015, while attending the General Debate of the 70th Session of the United Nations General Assembly and delivering an important speech, Chinese President Xi Jinping emphasized that "peace, development, equity, justice, democracy and freedom are common values of all humanity and the lofty goals of the United Nations." Since then, President Xi has on many occasions stressed the need to carry forward the common values of humanity.

(五)如何一步一步实现两轮平衡车_两轮平衡车怎么调整平衡

通过串口调整KP,KI,KD,初步实现直立平衡

#include <Wire.h>
#include <MPU6050.h>


MPU6050 mpu;

// PID参数
float kp = 14.0;   // 比例系数
float ki = 0.6;    // 积分系数
float kd = 0.8;    // 微分系数
float ki_limit = 50.0; // 积分限幅

// 控制参数
float target_angle = -5.0;
const int motor_deadzone = 30;
const int motor_max = 255;
const float max_angle = 40.0;   // 最大允许角度
const float min_angle = -40.0;  // 最小允许角度

// PID计算变量
float error = 0, last_error = 0;
float integral = 0, derivative = 0;
float output = 0;

// 控制模式
enum ControlMode { MANUAL, AUTOMATIC };
ControlMode control_mode = AUTOMATIC;

// MPU变量
float angleY = 0;
float gyroY = 0;
unsigned long last_time = 0;

// 电机引脚定义
const int motor1_pwm = 15;
const int motor1_dir = 16;
const int motor2_pwm =17;
const int motor2_dir = 18;

// I2C引脚定义
const int i2c_sda = 41;
const int i2c_scl = 42;

bool mpu_connected = false;

// 串口参数调节相关变量
bool param_adjust_mode = false;
char adjust_param_type = ' ';
String inputString = "";

void initializeMPU6050() ;
void automaticControl();
void readMPU6050();
void stopMotors();
void setMotorSpeed(int pwm, bool forward);
void serialEvent() ;
void displayStatus();
void calculatePID();
void showHelp();


void setup() {
  Serial.begin(115200);
  delay(1000);
  
  Serial.println("PID自平衡小车控制程序");
  
  // 初始化I2C
  Wire.begin(i2c_sda, i2c_scl, 400000);
  delay(100);
  
  // 初始化MPU6050
  initializeMPU6050();
  
  // 设置电机引脚
  pinMode(motor1_pwm, OUTPUT);
  pinMode(motor1_dir, OUTPUT);
  pinMode(motor2_pwm, OUTPUT);
  pinMode(motor2_dir, OUTPUT);
  
  // 初始停止电机
  stopMotors();
  
  last_time = micros();
  
  Serial.println("\n=== PID自平衡小车控制程序 ===");
  Serial.println("角度范围限制: -40° 到 +40°");
  Serial.println("目标角度: " + String(target_angle) + "°");
  Serial.println("当前PID参数: Kp=" + String(kp, 2) + " Ki=" + String(ki, 3) + " Kd=" + String(kd, 2));
  Serial.println("控制模式:");
  Serial.println("  a - 自动平衡模式");
  Serial.println("  m - 手动控制模式");
  Serial.println("手动控制命令:");
  Serial.println("  f - 正转");
  Serial.println("  b - 反转");
  Serial.println("  s - 停止");
  Serial.println("PID参数调节:");
  Serial.println("  p - 调节Kp (或直接输入 p数值,如 p14.0)");
  Serial.println("  i - 调节Ki (或直接输入 i数值,如 i0.1)");
  Serial.println("  d - 调节Kd (或直接输入 d数值,如 d0.8)");
  Serial.println("  r - 重置PID积分项");
  Serial.println("  t - 调整目标角度 (或直接输入 t数值,如 t6.0)");
  Serial.println("  ? - 显示帮助信息");
  Serial.println("当前模式: 自动平衡");
  Serial.println("----------------------------");
}

void initializeMPU6050() {
  mpu.initialize();
  mpu_connected = mpu.testConnection();
  if (mpu_connected) {
    Serial.println("MPU6050连接成功");
    
    // 配置MPU6050
    mpu.setFullScaleGyroRange(MPU6050_GYRO_FS_250);
    mpu.setFullScaleAccelRange(MPU6050_ACCEL_FS_2);
    mpu.setDLPFMode(MPU6050_DLPF_BW_10);
  } else {
    Serial.println("MPU6050连接失败");
  }
}

void loop() {
  // 读取MPU6050数据(如果连接)
  if (mpu_connected) {
    readMPU6050();
  }
  
  // 根据当前模式执行相应控制
  if (control_mode == AUTOMATIC) {
    // 自动平衡模式 - 使用PID控制
    calculatePID();
    automaticControl();
  }
  
  // 显示状态
  static unsigned long last_display = 0;
  if (millis() - last_display > 500) {
    displayStatus();
    last_display = millis();
  }
  
  serialEvent();
  delay(10);
}

void readMPU6050() {
  int16_t ax, ay, az, gx, gy, gz;
  mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
  
  // 计算角度
  angleY = atan2(ax, az) * 180.0 / PI;
  
  // 计算陀螺仪角速度 (度/秒)
  gyroY = gy / 131.0; // ±250°/s 量程,灵敏度 131 LSB/(°/s)
  
  // 互补滤波:融合加速度计和陀螺仪数据
  unsigned long current_time = micros();
  float dt = (current_time - last_time) / 1000000.0;
  last_time = current_time;
  
  float alpha = 0.96; // 互补滤波系数
  static float angle_filtered = 0;
  angle_filtered = alpha * (angle_filtered + gyroY * dt) + (1 - alpha) * angleY;
  angleY = angle_filtered;
}

void calculatePID() {
  // 计算误差
  error = target_angle - angleY;
  
  // 积分项 (防饱和)
  integral += error;
  if (integral > ki_limit) integral = ki_limit;
  if (integral < -ki_limit) integral = -ki_limit;
  
  // 微分项 (使用陀螺仪数据作为微分项)
  derivative = -gyroY; // 负号是因为方向
  
  // PID输出
  output = kp * error + ki * integral + kd * derivative;
  
  // 限制输出范围
  output = constrain(output, -motor_max, motor_max);
}

void automaticControl() {
  // 检查角度是否超出安全范围
  if (angleY > max_angle || angleY < min_angle) {
    // 角度超出安全范围,停止电机
    stopMotors();
    integral = 0; // 重置积分项
    return;
  }
  
  // 使用PID输出控制电机
  int motor_pwm = abs(output);
  
  // 处理死区
  if (motor_pwm < motor_deadzone) {
    motor_pwm = 0;
  }
  
  // 根据PID输出方向控制电机
  if (output > 0) {
    setMotorSpeed(motor_pwm, true); // 正转
  } else if (output < 0) {
    setMotorSpeed(motor_pwm, false); // 反转
  } else {
    stopMotors(); // 停止
  }
}

void stopMotors() {
  // 设置PWM为0
  analogWrite(motor1_pwm, 0);
  analogWrite(motor2_pwm, 0);
  
  // 设置方向引脚为确定状态
  digitalWrite(motor1_dir, LOW);
  digitalWrite(motor2_dir, LOW);
}

void setMotorSpeed(int pwm, bool forward) {
  // 如果PWM为0,停止电机
  if (pwm == 0) {
    stopMotors();
    return;
  }
  
  // 处理死区
  if (pwm < motor_deadzone) {
    stopMotors();
    return;
  }
  
  // 限制PWM值
  pwm = constrain(pwm, motor_deadzone, motor_max);
  
  // 控制电机
  if (forward) {
    digitalWrite(motor1_dir, HIGH);
    digitalWrite(motor2_dir, HIGH);
  } else {
    digitalWrite(motor1_dir, LOW);
    digitalWrite(motor2_dir, LOW);
  }
  
  analogWrite(motor1_pwm, pwm);
  analogWrite(motor2_pwm, pwm);
}

void displayStatus() {
  Serial.print("角度: ");
  Serial.print(angleY, 1);
  Serial.print("° | 目标: ");
  Serial.print(target_angle, 1);
  Serial.print("° | 误差: ");
  Serial.print(error, 2);
  Serial.print(" | PID输出: ");
  Serial.print(output, 2);
  
  Serial.print(" | 积分: ");
  Serial.print(integral, 2);
  Serial.print(" | 微分: ");
  Serial.print(derivative, 2);
  
  Serial.print(" | PID参数: Kp=");
  Serial.print(kp, 2);
  Serial.print(" Ki=");
  Serial.print(ki, 3);
  Serial.print(" Kd=");
  Serial.print(kd, 2);
  
  Serial.print(" | 模式: ");
  Serial.print(control_mode == AUTOMATIC ? "自动" : "手动");
  
  // 显示角度状态
  if (angleY > max_angle || angleY < min_angle) {
    Serial.print(" | 状态: 超出安全范围!");
  } else if (output > 0) {
    Serial.print(" | 状态: 正转");
  } else if (output < 0) {
    Serial.print(" | 状态: 反转");
  } else {
    Serial.print(" | 状态: 平衡");
  }
  
  Serial.println();
}

// 处理直接参数设置命令 (如 "p14.0")
bool processDirectCommand(String command) {
  if (command.length() < 2) return false;
  
  char param_type = command.charAt(0);
  String value_str = command.substring(1);
  float new_value = value_str.toFloat();
  
  switch(param_type) {
    case 'p': // kp
      kp = new_value;
      Serial.print("Kp设置为: ");
      break;
    case 'i': // ki  
      ki = new_value;
      Serial.print("Ki设置为: ");
      break;
    case 'd': // kd
      kd = new_value;
      Serial.print("Kd设置为: ");
      break;
    case 't': // 目标角度
      target_angle = new_value;
      Serial.print("目标角度设置为: ");
      break;
    default:
      return false; // 未知命令
  }
  
  Serial.println(new_value, 4);
  displayStatus();
  return true;
}

void serialEvent() {
  while (Serial.available()) {
    char cmd = Serial.read();
    
    if (param_adjust_mode) {
      // 参数调节模式 (两步输入)
      if (cmd == '\n') {
        float new_value = inputString.toFloat();
        
        switch(adjust_param_type) {
          case 'p': // kp
            kp = new_value;
            Serial.print("Kp设置为: ");
            break;
          case 'i': // ki  
            ki = new_value;
            Serial.print("Ki设置为: ");
            break;
          case 'd': // kd
            kd = new_value;
            Serial.print("Kd设置为: ");
            break;
          case 't': // 目标角度
            target_angle = new_value;
            Serial.print("目标角度设置为: ");
            break;
        }
        
        Serial.println(new_value, 4);
        displayStatus();
        
        // 退出参数调节模式
        param_adjust_mode = false;
        adjust_param_type = ' ';
        inputString = "";
        
        Serial.println("输入指令继续调节 (p:Kp, i:Ki, d:Kd, t:目标角度, ?:帮助)");
      } else {
        inputString += cmd;
      }
    } else {
      // 命令模式
      switch(cmd) {
        case 'm': // 切换到手动模式
          control_mode = MANUAL;
          stopMotors();
          integral = 0; // 重置积分项
          Serial.println("切换到手动控制模式");
          break;
          
        case 'a': // 切换到自动模式
          control_mode = AUTOMATIC;
          integral = 0; // 重置积分项
          Serial.println("切换到自动平衡模式");
          break;
          
        case 'f': // 正转 (仅在手动模式下有效)
          if (control_mode == MANUAL) {
            setMotorSpeed(100, true);
            Serial.println("正转");
          } else {
            Serial.println("请在手动模式下使用此命令");
          }
          break;
          
        case 'b': // 反转 (仅在手动模式下有效)
          if (control_mode == MANUAL) {
            setMotorSpeed(100, false);
            Serial.println("反转");
          } else {
            Serial.println("请在手动模式下使用此命令");
          }
          break;
          
        case 's': // 停止 (在两种模式下都有效)
          stopMotors();
          integral = 0; // 重置积分项
          Serial.println("停止");
          break;
          
        case 'p': // 调节Kp (两步输入)
          adjust_param_type = 'p';
          param_adjust_mode = true;
          inputString = "";
          Serial.println("请输入Kp值 (当前值: " + String(kp, 2) + "): ");
          break;
          
        case 'i': // 调节Ki (两步输入)
          adjust_param_type = 'i';
          param_adjust_mode = true;
          inputString = "";
          Serial.println("请输入Ki值 (当前值: " + String(ki, 3) + "): ");
          break;
          
        case 'd': // 调节Kd (两步输入)
          adjust_param_type = 'd';
          param_adjust_mode = true;
          inputString = "";
          Serial.println("请输入Kd值 (当前值: " + String(kd, 2) + "): ");
          break;
          
        case 't': // 调节目标角度 (两步输入)
          adjust_param_type = 't';
          param_adjust_mode = true;
          inputString = "";
          Serial.println("请输入目标角度值 (当前值: " + String(target_angle, 1) + "): ");
          break;
          
        case 'r': // 重置积分项
          integral = 0;
          Serial.println("PID积分项已重置");
          break;
          
        case '?': // 显示帮助
          showHelp();
          break;
          
        case '\n': // 忽略换行符
          break;
          
        default:
          // 尝试处理直接命令 (如 "p14.0")
          String fullCommand = String(cmd);
          while (Serial.available()) {
            char nextChar = Serial.read();
            if (nextChar == '\n') break;
            fullCommand += nextChar;
          }
          
          if (!processDirectCommand(fullCommand)) {
            Serial.println("未知命令,输入 ? 查看帮助");
          }
          break;
      }
    }
  }
}

void showHelp() {
  Serial.println("\n=== 自平衡小车控制命令 ===");
  Serial.println("模式控制:");
  Serial.println("  a - 切换到自动平衡模式");
  Serial.println("  m - 切换到手动控制模式");
  Serial.println("手动控制:");
  Serial.println("  f - 正转");
  Serial.println("  b - 反转");
  Serial.println("  s - 停止");
  Serial.println("PID参数调节 (两种方式):");
  Serial.println("  方式1 - 分两步输入:");
  Serial.println("    p - 调节比例系数 Kp");
  Serial.println("    i - 调节积分系数 Ki");
  Serial.println("    d - 调节微分系数 Kd");
  Serial.println("    t - 调整目标角度");
  Serial.println("  方式2 - 直接输入:");
  Serial.println("    p14.0 - 设置Kp为14.0");
  Serial.println("    i0.1 - 设置Ki为0.1");
  Serial.println("    d0.8 - 设置Kd为0.8");
  Serial.println("    t6.0 - 设置目标角度为6.0°");
  Serial.println("其他:");
  Serial.println("  r - 重置PID积分项");
  Serial.println("  ? - 显示此帮助信息");
  Serial.println("----------------------------");
  Serial.println("当前PID参数: Kp=" + String(kp, 2) + " Ki=" + String(ki, 3) + " Kd=" + String(kd, 2));
  Serial.println("目标角度: " + String(target_angle) + "°");
  Serial.println("----------------------------");
}
<< 1 2 > >>
控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言