pid自平衡杆

主函数:

#include <WiFi.h>          //wifi功能需要的库
#include <MPU6050_tockn.h> //mpu6050陀螺仪库
#include "Motor.hpp"

const char *remoteIP = "192.168.4.2";
uint16_t remotePort = 2222;

WiFiUDP Udp; // 声明UDP对象.服务端开启,监听并记录来自客户端的ip,端口

MPU6050 mpu6050(Wire);
Motor motor(7, 10, 0, 1); // 前后平衡控制 空心杯马达引脚

bool sw = false; // 手势感应,倾倒检测

const int ledpin1 = 13, ledpin2 = 12;
int motor_pwm; // 前后平衡控制 马达的PWM

float kp = 16, ki = 0.03, kd = 19.00;
float balanceAngle = 1.55, keepAngle;
float ax, gx, integrate, bias, gy; // 角度,角速度,积分,误差

void detect_sw()
{
  static bool sw1, sw2;

  if (gy > 450)
  {
    sw1 = true;
  }
  if (gy < -450)
  {
    sw1 = false;
  }

  if ((ax > -45) && (ax < 45))
  {
    sw2 = true;
  }
  else
  {
    sw2 = false;
  }

  sw = (sw1 && sw2) ? true : false;
}

void pwm_calculation()
{
  bias = ax - keepAngle;
  integrate += bias;
  integrate = constrain(integrate, -200, 200);
  motor_pwm = kp * bias + ki * integrate + kd * gx;
}

void motor_ctrl()
{
  if (!sw)
  {
    motor_pwm = 0;
  }
  motor.run(motor_pwm);
}

void udp_print_val()
{
  Udp.beginPacket(remoteIP, remotePort); // 准备发送数据到目标IP和目标端口
  String angle_gyro = String(ax) + '\t' + String(gx) + '\t';
  Udp.println(angle_gyro); // 将接收到的数据放入发送的缓冲区
  Udp.endPacket();         // 向目标IP目标端口发送数据
  delay(50);
}

void udp_debug()
{
  if (Udp.parsePacket()) // parsePacket()返回解析到的数据长度,不为0则有数据
  {
    char val = Udp.read(); // 读取1字节数据;
    Serial.println(val);
    if (val == '0')
    {
      kp -= 1;
    }
    if (val == '1')
    {
      kp += 1;
    }
    if (val == '2')
    {
      ki -= 0.01;
    }
    if (val == '3')
    {
      ki += 0.01;
    }
    if (val == '4')
    {
      kd -= 0.1;
    }
    if (val == '5')
    {
      kd += 0.1;
    }
    if (val == 'u')
    {
      keepAngle += 0.1;
    }
    if (val == 'd')
    {
      keepAngle -= 0.1;
    }
    if (val == 'c')
    {
      keepAngle = 15;
    }
    Udp.beginPacket(remoteIP, remotePort); // 准备发送数据到目标IP和目标端口
    String pid_val = String(kp) + '\t' + String(ki) + '\t' + String(kd) + '\t' + String(keepAngle);
    Udp.println(pid_val); // 将接收到的数据放入发送的缓冲区
    Udp.endPacket();      // 向目标IP目标端口发送数据
  }
}

void led_effect()
{
  int ledPWM = abs(motor_pwm);
  if (motor_pwm < 0)
  {
    analogWrite(ledpin1, ledPWM);
  }
  else
  {
    analogWrite(ledpin2, ledPWM);
  }
}

void setup()
{
  Serial.begin(115200);                // 初始化波特率
  WiFi.softAP("ESP32_Udp_server", ""); // 打开ESP32热点,ESP32默认IP是192.168.4.1
  Udp.begin(1111);                     // 启动UDP监听这个端口
  Wire.begin(4, 5);
  mpu6050.begin();
  mpu6050.calcGyroOffsets(true);
  keepAngle = balanceAngle;
  motor.flameout(); // 防止因部分引脚开机启动默认为高电平,导致马达转动
  analogWrite(ledpin1, 125);
  analogWrite(ledpin2, 125);
  delay(500);
}

void loop()
{
  mpu6050.update();

  ax = mpu6050.getAngleX();
  gx = mpu6050.getGyroX();
  gy = mpu6050.getGyroY();

  pwm_calculation();
  detect_sw();
  motor_ctrl();

  led_effect();

  udp_debug();
  // udp_print_val();
}


motor(马达)代码:

#pragma once
#include <Arduino.h>

#define LEDC_FREQ 500 // LEDC频率
#define LEDC_BIT 8    // LEDC分辨率(精度) 0-255

class Motor
{
private:
    int motorPIN1, motorPIN2; // ADC、马达控制引脚
    int channel1, channel2;   // esp32的ledc通道
public:
    Motor(int, int, int, int);
    void run(int);
    void brake();    // 马达静止(高阻)
    void flameout(); // 马达熄火(无阻力)
};

Motor::Motor(int mpin1, int mpin2, int ch1 = 0, int ch2 = 1)
{
    motorPIN1 = mpin1;
    motorPIN2 = mpin2;
    channel1 = ch1;
    channel2 = ch2;
    ledcSetup(channel1, LEDC_FREQ, LEDC_BIT);
    ledcSetup(channel2, LEDC_FREQ, LEDC_BIT);
    ledcAttachPin(motorPIN1, channel1);
    ledcAttachPin(motorPIN2, channel2);
}

// 马达运动PWM控制
void Motor::run(int pwm)
{
    pwm = constrain(pwm, -255, 255);
    if (pwm >= 0)
    {
        ledcWrite(channel1, pwm);
        ledcWrite(channel2, 0);
    }
    else
    {
        ledcWrite(channel1, 0);
        ledcWrite(channel2, -pwm);
    }
}

// 马达静止(高阻)
void Motor::brake()
{
    ledcWrite(channel1, 255);
    ledcWrite(channel2, 255);
}

// 马达熄火(无阻力)
void Motor::flameout()
{
    ledcWrite(channel1, 0);
    ledcWrite(channel2, 0);
}
清单:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值