为了深入学PID,必须自己实践,因此看到这个迷你掌上平衡车miniBot项目比较容易制作,则开始行动。

硬件部分

按照清单购买了元件,嘉立创白嫖打板,自己焊接。焊接完成后能下载程序,但是电机不输出。贴片焊接难度大,出了问题不知道是哪里虚焊,排查比较麻烦。
焊接
▲施展不开的书桌。好想有个自己的书房,可以放各种设备折腾自己的事情,无奈房子太小了。

为了焊接两个串联的18650电池,又折腾点焊机,使用率极低,得不偿失o(╥﹏╥)o还是应该使用电池盒,下次其它项目电池还可以使用。
电焊机
▲点焊机

请输入图片描述
▲焊接完成电机不能输出

最终自己又按照原理图利用模块化拼装思路,重新绘制了PCB板,这样出问题的概率就低很多。过程中入门了嘉立创PCB的绘制,PCB在线绘制简单易用。又重新白嫖打板,购买模块化元件。
嘉立创专业版 miniBot模块化PCB文件:ProProject_miniBot模块化_2023-11-03.zip

模块化的PCB
▲模块化的PCB

请输入图片描述
▲模块化的miniBot,成功点亮和输出。

程序部分

硬件部分已经做完很长时间,用作者的程序调试始终都不太稳定。准备自己好好研究源程序及相应的库对其做优化,深入理解PID代码及姿态控制算法,可一直没花时间去做这个事情。后续计划看什么时候把这个坑补上。。。。

未完待续。。。

20240229更新

自己按照这个博主的教程重新整理了代码,在PID调试时始终不太平稳。自己评估一是可能重心太高且重量太重,二是3.3V供给选型的N20电机转速也偏小。后续可改成一节18650供电配升压模块。
minibot_go

用以下程序需交换两个电机的插头。
蓝牙调试工具(Android):BtSerialDebugAndControl.zip

代码如下

/*
 * pwm+为前进,pwm+-为后退
 * 左马达IN1 IN2,OUT1 OUT2 , pwm   9起转。
 * 右马达IN3 IN4,OUT3 OUT4, PWM   9起转。
 * 
 */

#include <Arduino.h>
//#include<analogWrite.h>
#include "BluetoothSerial.h"
#include <MPU6050_tockn.h>
#include <Wire.h>

#define IN1 32  //AIN1
#define IN2 33  //AIN2
#define IN3 21  //BIN1
#define IN4 27  //BIN2


int sda_pin = 18, scl_pin = 19; //自定义eps32的I2C引脚

/*---调试和预设定值的变量--------*/
float Balance_Angle_raw = -4;    //测试出的静态机械平衡角度。
int leftMotorPwmOffset = 9, rightMotorPwmOffset = 9; //测试出的左右轮的启动pwm值,pwm达到一定电压马达才开始转动。
float kp = 14, ki = 1.2, kd = 1.0;     //根据调试测试得到设置kp ki kd的值
int pwm = 0;

/*---调试和控制变量--------*/
float Keep_Angle, bias, integrate;              //保持角度,角度偏差,偏差积分变量
float AngleY, GyroY, GyroZ;                     // mpu6050输出的角度值为浮点数,两位有效小数
int vertical_PWM, turn_PWM, PWM, L_PWM, R_PWM;  //各种PWM计算值

BluetoothSerial SerialBT; //实例化esp32的蓝牙串口对象
MPU6050 mpu6050(Wire);    //实例化mpu6050对象


/*---电机启动输出--------*/
void motor(int left_EN, int right_EN)
{
  if (left_EN == 0)
  {
    analogWrite(IN1, 0);
    analogWrite(IN2, 0);
  }
  if (left_EN < 0) //左边反转
  {
    if (left_EN < -255)
      left_EN = -255;
    analogWrite(IN1, 0);
    analogWrite(IN2, 0 - left_EN);
  }
  if (left_EN > 0)//左边正转
  {
    if (left_EN > 255)
      left_EN = 255;
    analogWrite(IN1, left_EN);
    analogWrite(IN2, 0);
  }
  if (right_EN == 0)
  {
    analogWrite(IN3, 0);
    analogWrite(IN4, 0);
  }
  if (right_EN < 0)
  {
    if (right_EN < -255)
      right_EN = -255;
    analogWrite(IN3, 0);
    analogWrite(IN4, 0 - right_EN);

  }
  if (right_EN > 0)
  {
    if (right_EN > 255)
      right_EN = 255;
    analogWrite(IN3, right_EN);
    analogWrite(IN4, 0);
  }
}

void serial_debug()
{
  if (SerialBT.available() > 0)
  {
    char DATA = SerialBT.read();
    delay(5);
    switch (DATA)
    {
      /*直立环调试*/
      case '0':
        kp -= 1; //调节直立环 比例kp项-
        break;
      case '1':
        kp += 1; //调节直立环 比例kp项+
        break;
      case '2':
        ki -= 0.1; //调节直立环 积分项ki-
        break;
      case '3':
        ki += 0.1; //调节直立环 积分项ki+
        break;
      case '4':
        kd -= 0.1; //调节直立环 微分项kd-
        break;
      case '5':
        kd += 0.1; //调节直立环 微分项kd+
        break;
    }

    /*调试时PID极性限制*/
    if (kp < 0)kp = 0;
    if (ki < 0)ki = 0;
    if (kd < 0)kd = 0;

    /*串口打印输出显示*/
    SerialBT.print("Keep_Angle: ");
    SerialBT.println(Keep_Angle);
    SerialBT.print("kp:");
    SerialBT.print(kp);
    SerialBT.print("  ki:");
    SerialBT.print(ki);
    SerialBT.print("  kd:");
    SerialBT.println(kd);
    SerialBT.println("--------------------");

  }
}

void vertical_pwm_calculation() //直立PMW计算
{
  AngleY = mpu6050.getAngleY();
  GyroY = mpu6050.getGyroY();
  bias = AngleY - Keep_Angle; // 计算角度偏差。bias为小车角度是静态平衡角度的差值。
  integrate += bias; //偏差的积分,integrate为全局变量,一直积累。
  integrate = constrain(integrate, -1000, 1000); //限定误差积分的最大和最小值
  /*==直立PID计算PWM==通过陀螺仪返回数据计算,前倾陀螺仪Y轴为正,后仰陀螺仪Y轴为负。
    前倾车前进,后仰车后退,保持直立。但可能为了直立,车会随时移动。*/
  vertical_PWM = kp * bias + ki * integrate + kd * GyroY;
}

void motor_control() //马达PWM控制函数
{
  /*---【补偿右轮pwm差值】------------*/
  if (PWM >= 0)
  {
    L_PWM = PWM + leftMotorPwmOffset;  //左右轮的启动pwm达到一定电压马达才开始转动。这里为补偿值。
    R_PWM = PWM + rightMotorPwmOffset; //左右轮的启动pwm达到一定电压马达才开始转动。这里为补偿值。
  }
  if (PWM < 0)
  {
    L_PWM = PWM - leftMotorPwmOffset;  //左右轮的启动pwm达到一定电压马达才开始转动。这里为补偿值。
    R_PWM = PWM - rightMotorPwmOffset; //左右轮的启动pwm达到一定电压马达才开始转动。这里为补偿值。
  }


  /*---【控制马达输出】-------------*/
  // L_PWM = constrain(L_PWM, -255, 255); //计算出来的PWM限定大小。255为输出上限。
  // R_PWM = constrain(R_PWM, -255, 255);

  motor(L_PWM, R_PWM);

  /*--------判断是否小车倒下,此时停止马达和编码器计数-----*/
  if (AngleY > 45 || AngleY < -45) //倾角过大(车倒下时),停止马达输出
  {
    motor(0, 0);
  }
}


void setup()
{
  SerialBT.begin("ESP32_car"); // Bluetooth device name
  Wire.begin(sda_pin, scl_pin);
  mpu6050.begin();
  mpu6050.calcGyroOffsets(false);
  Keep_Angle = Balance_Angle_raw; //平衡角度初始化为静态平衡时的陀螺仪角度。Keep_Angle可以改变,才可以控制前进后退。
  motor(0, 0);                    //机器启动时马达确保停止。
  delay(10);                      //循环前延时,确保各种初始和准备完成
}

void loop()
{
  serial_debug();
  mpu6050.update(); //陀螺仪刷新
  vertical_pwm_calculation(); //直立环PWM计算
  PWM = vertical_PWM;
  motor_control();// 电机输出
}

标签: Arduino, 平衡车

添加新评论

返回顶部