如何使用PID控制和超声波传感器控制步进电机的速度?

问题描述

小故事: 我目前正在做这个项目,涉及使用两辆汽车,分别称为A块和B块,B块必须使用PID,PD,PI或P与A块保持10厘米的距离。我正在使用PID 。 B块使用Arduino,而A块则由用户手动控制。模块B使用单极步进电机作为执行器,并使用超声波传感器来感应距离。我的教授希望电动机沿两个方向移动并具有不同的速度(慢速,中速和快速)。我一直在使用brett的PID,因为我以前在以前的实验室中都使用过它。

问题: 我对于如何为B块创建不同的速度存在问题,就像直观地知道,我想让B块移动,例如,如果汽车大于20厘米,则;如果汽车大于20 cm,则 medium汽车在20厘米至14厘米之间,如果在14厘米至10厘米之间则慢。但是我只是不能直接使用从传感器获取的输入值来控制电动机,因为这会使它成为开放系统。因此,我使用了从Brett的PID代码中检索到的错误来控制步进电机。到目前为止,我已经通过设置myPID.SetoutputLimits(-800,800);得到了工作指导。但是,当它试图使用误差来控制速度时,这是不可能的,因为误差总是在特定距离处波动。例如,在12厘米处,我会得到800或300左右。目前,我对如何通过PID实现对步进电机速度的控制感到困惑,对此问题的任何帮助将不胜感激。

代码代码是通过Arduino IDE进行的。

#include "SR04.h"
#include <Stepper.h>
#include <PID_v1.h>

#define TRIG_PIN 7
#define ECHO_PIN 6

//intialization of Ultrasonic sensor
SR04 sr04 = SR04(ECHO_PIN,TRIG_PIN);
long s; 

//intializing motor variables
int stepsPerRevolution = 2048;
int motorSpeed = 6;
Stepper myStepper (stepsPerRevolution,8,10,9,11);

//Declared PID variables
double Setpoint = 10; //desired temp value
double Input;    //thermsitor
double Output;   //DC motor
double Error;

//defined variables for PID parameters
double Kp=100,Ki=10,Kd=1;

//PID equation
PID myPID(&Input,&Output,&Setpoint,Kp,Kd,Ki,REVERSE);


void setup(){
  Serial.begin(9600);

  //setting PID
  myPID.SetMode(AUTOMATIC);
  myPID.SetoutputLimits(-800,800);

  //speed intialized
  myStepper.setSpeed(motorSpeed);
 

}

void loop(){
  s=sr04.distance();
  Input = s;
  myPID.Compute();
  Error = Input - Setpoint;
  //Serial.print(Input);
  //Serial.print(",");
  //Serial.println(Setpoint);
  Serial.println(Output);
  //Serial.print(",");
  //Serial.println(Error);
  Error = Output; 
  
//Away from Block B
 if (0<Error<800){
    myStepper.setSpeed(motorSpeed);
    myStepper.step(-300);
  } //slow speed
  
   if (Error>=800){
    myStepper.setSpeed(motorSpeed*2);
    myStepper.step(-128);
  } //fast speed

//Towards Block B
  if (-800<Error<0) {
    myStepper.setSpeed(motorSpeed);
    myStepper.step(128);
  } //slow speed
  
  if (Error<=-800) {
    myStepper.setSpeed(motorSpeed*2);
    myStepper.step(128);
  }//Fast speed
 }
  

解决方法

您需要做的是计算需要多少更改当前速度以最小化距离误差。

您的错误计算方法不正确。

void loop()
{

    long s=sr04.Distance();
    Input = s;             // using global variables to pass values to your PID 
                           // is not a good idea.  Use function parameters instead.
                           // You are storing a 32 bit value in a 16 bit variable!!!
                           // That's only the start of your problems.  
    myPID.Compute();
    Error = Input - Setpoint; // 

由于我们从一个主要的设计缺陷开始,所以我必须假设您将解决此问题并更改PID代码以接受和计算长整数,既作为输入值作为函数参数,又作为函数的类型。它的返回值。

您要做的是根据距设定点的距离误差计算PID,然后相应地调节当前速度。直接使用PID时效果最好,可以使用7种速度(1个停止,3个前进/ 3个倒退),但是我认为效果不会更好,我会把练习留给您。

我还没有尝试过,我手边没有任何汽车。这是我如何去做的骨架。调整PID应该是花费您最长的时间。

//...

// speeds are in RPMs.
long curSpeed = 0;
const long MAX_SPEED = XXX;  // whatever you max speed is for your car.
const long MIN_NEG_SPEED = -XXX;  // whatever you max speed is for your car going reverse.
const long MIN_SPEED = XXX;  // below this absolute speed,we're stopped. 
const int SLICE_TIME = 10;   // time between readings and adjustments,in ms.
                             // you'll need to adjust this according to you minimum speed,and steps per turn. 
const long STEPS_PER_TURN = 200;  // change to whatever you steps/turn value is.

// you'll need to limit the output of your PID to match the acceleration your
// motors can handle for your particular car.

// returns the number of steps to run for our slice time.  
long Steps(int speed)
{
    if (-MIN_SPEED <= speed && speed <= MIN_SPEED)
        return 0;

    // compute number of steps for our slice time.
    // choose slice time and minimum speed wisely!!
    long steps = (SLICE_TIME * (speed * STEPS_PER_TURN)) / (60000L);
    
    // for very low speeds.  I've added this,because I'm unsure of the 
    // time domain behaviour of stepper library with less than 2 steps
    if (-1 <= steps && steps <= 1)
    {
        if (speed < 0)
            return -2;
        else
            return 2;
    } 
    return int(steps);
}

void loop() 
{
    // You may want to filter the sr04 readings with a median of 5
    // filter to limit input noise.   

    // You want to keep the car at a distance of 'set_point'
    // from the leading car.  distance_error is the error you want to
    // minimize to zero by using the PID,and that's what should be
    // the PID input.
    //
    // The way this works.  We are rolling at speed curSpeed,we
    // measure the error in distance from our set_point,feed that 
    // to the PID,then accelerate or decelerate by subtracting
    // the output of the PID from the current speed. 
    //    
    // Note: you can add or subtract the PID to/from the current speed,// the sign of the PID depends on you coefficients and sensor. 
    // I've used subtraction here because that's how you express 
    // negative feedback mathematically.  In real life,we'll use what
    // best fits our needs.  Usually it's the operation that makes P
    // positive.

    long distance_error = sr04.Distance() - setPoint;

    long pid_out = myPID.Compute(distance_error);

    // increment or decrement the current speed to try and reduce the error.
    long speed = curSpeed - pid_out;  // As usual,PID coefficients do matter 
                                     // for this to work well.

    if (speed > MAX_SPEED)
        speed = MAX_SPEED;
    if (speed < MIN_NEG_SPEED)
        speed = MIN_NEG_SPEED;

    curSpeed = speed;
    if (speed < 0)
        speed = -speed;

    myStepper.setSpeed(speed);     // modulate speed
    int steps = Steps(curSpeed);
    if (steps)
        myStepper.step(steps);     // keep rolling.
}

我也没有尝试对其进行编译,因此这可能无法按原样进行编译。但是,大多数技巧和陷阱都已涵盖,如果您要使用PID路径,这应该给您一个领先的机会。但是我认为您的教授真的会想知道那个人是从哪里来的:)尽管如此,您还是应该尝试使其运行起来,这很有趣。

反之,没有PID,使用设定的速度要简单得多。它也可能更接近练习所需的内容。当然,汽车之间的距离会有所不同。而且它根本不使用PID。

const int MAX_SPEED = 3;
int speed = 0;    // value range is [-MAX_SPEED,+MAX_SPEED]  

long RPMS[MAX_SPEED + 1] = { 0,200,400,800 }; // in RPMs,assuming average speed will be around 400,in this case.
// For 3 speeds,the difference between speeds cannot be higher than max acceleration.  
// You can add as many speeds as desired.  More speeds = more precision.

const long STEPS_PER_TURN = 200;  // change to whatever you steps/turn value is.  MUST be 200 or more.
const int STEPS = STEPS_PER_TURN / 100;  // 3.6° between speed adjustment.
                                         // it is very small right now,so 
                                         // you will want to play with this value.

// this threshold gives some control over aceleration.
// and 'hardness' of distance tracking.  
const long THRESHOLD = 0;

void loop()
{
    // get the error in distance.
    long distance_error = sr04.Distance() - setPoint;

    // modulate speed.  
    if (distance_error > THRESHOLD) 
        ++speed;
    if (distance_error < -THRESHOLD)
        --speed;

    if (speed > MAX_SPEED)
        speed = MAX_SPEED;
    if (speed < -MAX_SPEED)
        speed = -MAX_SPEED;

    long rpm = RPMS[(speed < 0) : -speed : speed];
    if (rpm)
    {
        myStepper.setSpeed(rpm);
        myStepper.setSpeed((speed < 0) ? -STEPS : STEPS)
    }
}

对于此代码,您必须选择速度和STEPS值,以使您获得加速而不会错过任何步骤。