Arduino控制带编码器的直流电机速度

Arduino DC Motor Speed Control with Encoder, Arduino DC Motor Encoder

作者

  • How to control dc motor with encoder:
  • DC Motor with Encoder + Arduino, Circuit Diagram:
  • Driving the Motor with Encoder and Arduino:
  • Control DC motor using Encoder feedback loop:

How to control dc motor with encoder:

Arduino DC Motor Speed Control with Encoder- I have been using different types of stepper motors, Servo motors, and DC Motors for quite a long time in different intermediate and advanced level projects. DC motors are more frequently used than Stepper Motors and Servo Motors. If you have watched my videos and read my articles then you should know DC motors are quite different from Stepper Motors and servo Motors. These three types of motors have a different construction. The stepper motors and servo motors are designed in a way that we can control their position. We can control the steps in the forward and reverse directions. Servos can move from 0 to 180 degrees, so you can move to any position between 0 and 180. Likewise, in stepper motors, you can control the steps precisely and this is the reason stepper motors are used in CNC machines, 3d printers, etc.
使用编码器控制 Arduino 直流电机速度–我在不同的中高级项目中使用不同类型的步进电机、伺服电机和直流电机已经有很长一段时间了。 直流电机比步进电机和伺服电机更常用。 如果你看过我的视频和文章,就应该知道直流电机与步进电机和伺服电机有很大不同。 这三种电机的结构各不相同。 步进电机和伺服电机的设计方式使我们可以控制它们的位置。 我们可以控制步进的前进和后退方向。 舵机可以移动到 0 至 180 度之间的任何位置。 同样,步进电机可以精确控制步数,这也是步进电机被用于数控机床、3d 打印机等的原因。
On the other hand, when a dc motor is powered up it immediately starts rotating, it continuously rotates, you can’t exactly control its position until you use a specific technique. You can’t 100% control a DC motor like Stepper motor and Servo, but if you add an encoder it can really change the whole game. With an encoder being added, you can keep track of the motor revolutions, the amount of distance it has covered, and this way you can make a nice feedback system that can be used to control the DC motor. Then you can stop the DC motor at the position where you want it to stop. The control of a DC motor using an encoder is not that simple, you just simply can’t start by adding an encoder with the DC Motor and start controlling the DC motor, to use an encoder you will need a controller, the controller will read the encoder and then will accordingly control the DC motor as per the pre-defined instructions written by the programmer. for this project, you will need a microcontroller board like the Arduino Uno or Arduino Nano, or Arduino Mega, or Arduino pro mini, etc. I know beginners are more comfortable with Arduino Uno, Arduino mega, and Arduino Nano, so I will start with the Arduino Uno, the same connections and programs you can also try on Arduino Nano and Arduino Mega.

另一方面,直流电机通电后会立即开始旋转,并持续旋转,除非使用特定技术,否则无法准确控制其位置。 你无法像控制步进电机和伺服电机那样百分之百地控制直流电机,但如果添加一个编码器,就能真正改变整个游戏规则。 有了编码器,你就可以跟踪电机的转数和运行距离,这样你就可以建立一个很好的反馈系统,用来控制直流电机。 然后,你就可以让直流电机停在你希望它停的位置。 使用编码器控制直流电机并不那么简单,你不能一开始就在直流电机上添加一个编码器,然后开始控制直流电机,要使用编码器,你需要一个控制器,控制器将读取编码器,然后根据程序员编写的预定义指令相应地控制直流电机。 我知道初学者更喜欢 Arduino Uno、Arduino mega 和 Arduino Nano,所以我将从 Arduino Uno 开始,同样的连接和程序你也可以在 Arduino Nano 和 Arduino Mega 上尝试。

To get started, you will need Arduino Uno, a Motor driver, a DC Motor, and of course an Encoder. To read the Encoder, we will connect the encoder output pins with Arduino’s pins 2 and 3 which are the interrupt pins. The power wires of the encoder will be connected with the Arduino’s 5V and GND. To keep things simpler, I will start with the simple example code in which I will use pins 2 and 3 as the normal digital pins, we won’t activate the interrupts and then in the second example code, we will use the interrupts. Without any further delay, let’s get started!!!

要开始使用,您需要 Arduino Uno、一个电机驱动器、一个直流电机,当然还有一个编码器。 为了读取编码器,我们将把编码器的输出引脚与 Arduino 的中断引脚 2 和 3 连接起来。 编码器的电源线将与 Arduino 的 5V 和 GND 连接。 为了简化操作,我将从简单的示例代码开始,其中我将把引脚 2 和 3 用作普通的数字引脚,我们不会激活中断,然后在第二个示例代码中,我们将使用中断。 事不宜迟,让我们开始吧

DC Motor with Encoder + Arduino, Circuit Diagram:

The type of the DC motor as you can see in the circuit diagram given below has a built-in encoder. So, it’s totally up to you whether you want to use it as the simple dc motor or you want to use the encoder, or you can use the motor and encoder together at the same time. As you can see in the circuit diagram, the power wires which are the Red and Black wires are not connected but the encoder wires are connected. For this first example, we will only be using the encoder to understand the basics this way you will easily understand how an encoder works. So, we will rotate the motor shaft by hand to see the trigger signals.

从下面的电路图中可以看到,这种直流电机内置了编码器。 因此,你完全可以决定是将其用作简单的直流电机,还是使用编码器,或者同时使用电机和编码器。 如电路图所示,电源线(红线和黑线)没有连接,但编码器线已经连接。 在第一个示例中,我们将只使用编码器来了解基础知识,这样你就会很容易理解编码器的工作原理。 因此,我们将用手旋转电机轴来查看触发信号。
在这里插入图片描述

An encoder works by observing changes to the magnetic field created by a magnet attached to the motor shaft, as the motor rotates the encoder outputs will trigger periodically. When the magnet spins clockwise, output “a” will trigger first, and when rotated counterclockwise on the other hand output “b” will trigger. This way you know exactly which way the motor shaft is rotating. This can be quite handy in situations where you need to control the forward and reverse movement of the DC Motor.

编码器的工作原理是观察连接在电机轴上的磁铁所产生的磁场变化,当电机旋转时,编码器输出将周期性地触发。 当磁铁顺时针旋转时,输出端 "a "将首先触发,反之,当逆时针旋转时,输出端 "b "将触发。 这样,您就能准确知道电机轴的旋转方向。 在需要控制直流电机正反转的情况下,这将非常方便。
Arduino DC Motor Encoder

Let’s write a very simple program to understand how an encoder works and how to read the encoder outputs.
让我们编写一个非常简单的程序,了解编码器的工作原理以及如何读取编码器的输出。

Arduino Encoder Code:

#define ENCA 2 // pin2 of the Arduino
#define ENCB 3 // Pin3 of the Arduino
int ENCA_DATA;
int ENCB_DATA;void setup() {Serial.begin(9600); // Activates Serial communicationpinMode(ENCA,INPUT); // sets pin2 as the inputpinMode(ENCB,INPUT); // sets pin3 as the input
}void loop() {ENCA_DATA = digitalRead(ENCA); 
// We simply read Pin2 of the Arduino and store the result in variable ENCA_DATAENCB_DATA = digitalRead(ENCB); 
// We simply read Pin3 of the Arduino and store the result in variable bSerial.print(ENCA_DATA*5); Serial.print(" ");Serial.print(ENCB_DATA*5);Serial.println();
}
Arduino Encoder Code Explanation:

We don’t need any libraries for this basic program. First of all, I started off by defining the Arduino pins 2 and 3. I will call these pins the ENCA and ENCB. These two pins will be connected with the Encoder outputs.
Next, I defined two variables ENCA_DATA and ENCB_DATA.

这个基本程序不需要任何库。 首先,我定义了 Arduino 的 2 号和 3 号引脚。 我将这两个引脚称为 ENCA 和 ENCB。 接下来,我定义了两个变量 ENCA_DATA 和 ENCB_DATA。

#define ENCA 2
#define ENCB 3int ENCA_DATA;
int ENCB_DATA;

Next, we will need to tell the Arduino whether we want to use the Serial communication? And the pins we just defined are going to be used as the inputs or outputs? All this is done in the void setup() function.

接下来,我们需要告诉 Arduino 是否要使用串行通信? 我们刚刚定义的引脚将用作输入还是输出? 所有这些都将在 void setup() 函数中完成。

void setup() {Serial.begin(9600);pinMode(ENCA,INPUT);pinMode(ENCB,INPUT);}

In the void setup() function, I simply activated the serial communication and I selected 9600 as the Baud rate. Next, I set the two pins ENCA and ENCB as the inputs using the pinMode() functions.

The void setup() function executes only once with the Arduino board is first turned ON. The actual code is placed inside the loop() function which executes repeatedly.

在 void setup() 函数中,我只需激活串行通信,并选择 9600 作为波特率。 接下来,我使用 pinMode() 函数将两个引脚 ENCA 和 ENCB 设置为输入。 void setup() 函数只在 Arduino 板首次打开时执行一次。 实际代码放在loop()函数中重复执行。

void loop() {ENCA_DATA = digitalRead(ENCA);ENCB_DATA = digitalRead(ENCB);

I simply defined a variable “ENCA_DATA” which is of the type integer. Then we read the ENCA pin using the digitalRead() function and store the value in variable ENCA_DATA, exactly the same thing I did for the ENCB.

我们使用 digitalRead() 函数读取 ENCA 引脚,并将值存储到变量 ENCA_DATA,在 ENCB 上所做的完全相同。

Serial.print(ENCA_DATA*5);Serial.print(” “);Serial.print(ENCB_DATA*5);Serial.println();}

Next, to write outputs to the computer screen I used the Serial.print() and Serial.println() functions. Inside the parenthesis, you can see I am multiplying the values by 5 to make the plot easier to read.

All you need is to compile the code first to check if any keywords are misspelled, and then you can upload the code.

After the code has been uploaded, you can go ahead and open the Serial Monitor and select the 9600 Baud Rate. Now, you can start by rotating the DC Motor shaft which has the encoder. The Encode signal changes as you rotate the motor shaft, these changes are easier to understand with the serial plotter. So, output “a” is triggered when you rotate the shaft Clockwise and similarly, the output “b” is triggered when you rotate the shaft anti-clockwise. This code has nothing to do with the motor shaft position, the purpose of this code was just to help you understand how these two outputs “a” and “b” are triggered.

Now let’s measure the position of the DC motor shaft. Nothing is changed on the hardware side. We are using the same connections.

接下来,为了将输出写入电脑屏幕,我使用了 Serial.print() 和 Serial.println() 函数。 在括号内,你可以看到我将数值乘以 5,以便更容易读取图表。 你只需要先编译代码,检查是否有关键字拼错,然后就可以上传代码了。 代码上传后,你可以继续打开串行监视器,选择 9600 波特率。 现在,你可以开始旋转带有编码器的直流电机轴。 编码器信号会随着电机轴的旋转而变化,使用串行绘图仪更容易理解这些变化。 因此,顺时针旋转电机轴时,输出 "a "被触发;同样,逆时针旋转电机轴时,输出 "b "被触发。 这段代码与电机轴的位置无关,其目的只是帮助你理解这两个输出 "a "和 "b "是如何触发的。 现在我们来测量直流电机轴的位置。 硬件方面没有任何变化。 我们使用的是相同的连接。

Position of the encoder Arduino Code:

#include <Arduino.h>#define Encoder_output_A 2 // pin2 of the Arduino
#define Encoder_output_B 3 // pin 3 of the Arduino
// these two pins has the hardware interrupts as well.int Count_pulses = 0;void DC_Motor_Encoder();
void setup()
{Serial.begin(9600);               // activates the serial communicationpinMode(Encoder_output_A, INPUT); // sets the Encoder_output_A pin as the inputpinMode(Encoder_output_B, INPUT); // sets the Encoder_output_B pin as the inputattachInterrupt(digitalPinToInterrupt(Encoder_output_A), DC_Motor_Encoder, RISING);
}void loop()
{Serial.println("Result: ");Serial.println(Count_pulses);
}void DC_Motor_Encoder()
{int b = digitalRead(Encoder_output_B);if (b > 0){Count_pulses++;}else{Count_pulses--;}
}
Position of the encoder Arduino Code Explanation:

This code is the modified version of the code that I just explained above. I made some changes, which I am sure you can clearly see. Let’s talk about these changes in detail. The pins 2 and 3 connections remain exactly the same.

这段代码是我上面解释过的代码的修改版。 做了一些改动,让我们来详细谈谈这些改动。 引脚 2 和引脚 3 的连接方式保持不变。

#define Encoder_output_A 2 // pin2 of the Arduino
#define Encoder_output_B 3 // pin 3 of the Arduino
// these two pins has the hardware interrupts as well.

I defined a global variable Count_pulses and initially stored a value of 0 in it. As this is a global variable so I can access this variable from anywhere inside my Arduino code.

我定义了一个全局变量 Count_pulses,初始值为 0。 由于这是一个全局变量,因此我可以从 Arduino 代码的任何地方访问该变量。
int Count_pulses = 0;

Inside the void setup() function, you can clear see the first three lines of code are exactly the same.

void setup() {
Serial.begin(9600); // activates the serial communication
pinMode(Encoder_output_A,INPUT); // sets the Encoder_output_A pin as the input
pinMode(Encoder_output_B,INPUT); // sets the Encoder_output_B pin as the input
attachInterrupt(digitalPinToInterrupt(Encoder_output_A),DC_Motor_Encoder,RISING);
}

This time I added this attachInterrupt(digitalPinToInterrupt(Encoder_output_A),DC_Motor_Encoder,RISING); this line of code. The attachinterrupt() function is used to activate the hardware interrupt. The attachinterrupt() function takes three arguments as the input. The first one is the pin digitalPinToInterrupt(Encoder_output_A), the second argument is the function name, this function will execute each time when an interrupt happens on the Encoder_output_A pin of the Arduino which is pin 2. The 3rd argument is to tell whether to take action on the rising edge or the falling edge. So, our interrupt setting is completed.

This time inside the loop function many things are changed. This time inside the loop() function we are only using 2 lines of code, the first line of code prints the text Result and the “Serial.println(Count_pulses);” which prints the value stored in the variable Count_pulses.

这次我添加了attachInterrupt(digitalPinToInterrupt(Encoder_output_A),DC_Motor_Encoder,RISING);这行代码。 attachinterrupt() 函数用于激活硬件中断。 attachinterrupt() 函数将三个参数作为输入。 第一个参数是引脚 digitalPinToInterrupt(Encoder_output_A),第二个参数是函数名称,每次当 Arduino 的Encoder_output_A引脚(即引脚 2)发生中断时,该函数就会执行。 第三个参数是告诉我们是在上升沿还是下降沿采取行动。 这样,我们的中断设置就完成了。我们在 loop() 函数中只使用了两行代码,第一行代码打印文本 Result 和 “Serial.println(Count_pulses);”,后者打印存储在变量 Count_pulses 中的值。

void loop() {
Serial.println(“Result:);
Serial.println(Count_pulses);
}

DC_Motor_Encoder() function is a user-defined function it has no return type and does not take any arguments as the input. This is the function that is executed when an interrupt happens on pin2 of the Arduino. So, inside this function we are simply reading the Encoder_output_B pin, the value is stored in variable b. Next, we use an if condition to check if a signal is detected then increment the Count_pulses by 1 or else decrement the Count_pulses.

DC_Motor_Encoder() 函数是一个用户自定义函数,它没有返回类型,也不将任何参数作为输入。 当 Arduino 的引脚 2 发生中断时,该函数将被执行。 因此,在该函数中,我们只需读取 Encoder_output_B 引脚的值,并将其存储在变量 b 中。接下来,我们使用 if 条件来检查是否检测到信号,然后将 Count_pulses 递增 或递减 。

void DC_Motor_Encoder(){
int b = digitalRead(Encoder_output_B);
if(b > 0){
Count_pulses++;
}
else{
Count_pulses–;
}
}

Upload the code, open the serial monitor, and start rotating the encoder. Rotate the motor shaft in the clockwise direction and also in the anti-clockwise direction. In one direction the value will increase and in the other direction the value will decrease.
上传代码,打开串行监视器,开始旋转编码器。 顺时针和逆时针旋转电机轴。 在一个方向上,数值会增加,在另一个方向上,数值会减少。

Driving the Motor with Encoder and Arduino:

Now, I am sure you have completely understood how an Encoder works, how the Encoder outputs are triggered, and then how to write a simple code to count the pulses. So far we were manually rotating the DC motor shaft to trigger the Encoder outputs, now to do everything automatically it’s time to connect a motor driver so that we can read the position measurements from the Encoder. Start by connecting the DC motor wires to the outputs of the motor driver circuit. The motor driver also needs an appropriate power supply, which you will need to select as per your DC motor specs. Next, connect the Motor driver ground to the Arduino ground, the PWM input of the motor driver should be connected to an Arduino PWM pin here I have used pin 5.

现在,我相信你已经完全了解了编码器的工作原理、编码器输出的触发方式以及如何编写简单的代码来计数脉冲。 到目前为止,我们都是通过手动旋转直流电机轴来触发编码器输出,现在要想自动完成所有操作,就需要连接电机驱动器,以便读取编码器的位置测量值。 首先将直流电机导线连接到电机驱动器电路的输出端。 电机驱动器还需要适当的电源,您需要根据直流电机的规格来选择。 接下来,将电机驱动器的地线连接到 Arduino 的地线上,电机驱动器的 PWM 输入应连接到 Arduino 的 PWM 引脚上,这里我使用的是第 5 引脚。

在这里插入图片描述

The other two motor driver pins can be connected to any of the remaining Arduino digital pins. Before writing the control algorithm, Let’s test the motor driver start by defining the pins that you connected to the motor driver.

另外两个电机驱动器引脚可以连接到 Arduino 其余的任何数字引脚上。 在编写控制算法之前,让我们先测试一下电机驱动器,定义连接到电机驱动器的引脚。

Driving the Motor with Encoder, Arduino Code:

#include <Arduino.h>#define ENCA 2
#define ENCB 3
#define PWM 5
#define IN2 6
#define IN1 7int pos = 0;void setMotor(int dir, int pwmVal, int pwm, int in1, int in2);
// void setMotor(int, int, int, int, int);
void readEncoder();void setup()
{Serial.begin(9600);pinMode(ENCA, INPUT);pinMode(ENCB, INPUT);attachInterrupt(digitalPinToInterrupt(ENCA), readEncoder, RISING);
}void loop()
{setMotor(1, 25, PWM, IN1, IN2);delay(200);Serial.println(pos);setMotor(-1, 25, PWM, IN1, IN2);delay(200);Serial.println(pos);setMotor(0, 25, PWM, IN1, IN2);delay(20);Serial.println(pos);
}void setMotor(int dir, int pwmVal, int pwm, int in1, int in2)
{analogWrite(pwm, pwmVal);if (dir == 1){digitalWrite(in1, HIGH);digitalWrite(in2, LOW);}else if (dir == -1){digitalWrite(in1, LOW);digitalWrite(in2, HIGH);}else{digitalWrite(in1, LOW);digitalWrite(in2, LOW);}
}void readEncoder()
{int b = digitalRead(ENCB);if (b > 0){pos++;}else{pos--;}
}

It is useful to define a function that will set the motor direction and speed. The interface for the setMotor function, I have written here sets the direction and speed of a motor with the pins defined in the last three inputs. Inside the function, I have set the speed with an analog write command. if the direction integer is 1 then the motor will rotate one way by writing a high low combination to the input pins of the driver. If you reverse the order to a low-high combination the motor will rotate in the other direction. Inside the loop function, you can call the setMotor function to drive the motor also write the position to the serial line.

定义一个可以设置电机方向和速度的函数非常有用。 我在这里编写的 setMotor 函数接口使用最后三个输入中定义的引脚来设置电机的方向和速度。 如果方向整数为 1,那么通过向驱动器的输入引脚写入高-低组合,电机将单向旋转。 如果将顺序颠倒为低-高组合,电机将向另一个方向旋转。 在循环函数中,可以调用 setMotor 函数来驱动电机,同时将位置写入串行线。

Control DC motor using Encoder feedback loop:

So far we have connected the controller motor driver and motor in a loop but we have not used the position signal from the encoder to control the motor position. We will use a feedback loop. In a feedback loop the control components are often referred to as the plant(motor) here that is the motor and the motor driver. The sensor(encoder) that we are using to measure position is the encoder. In order to actually control the position of the motor you need to provide it with a target position, then you take the difference between the target position and the measured position, the result is the error usually written as e(t).

到目前为止,我们已将控制器电机驱动器和电机连接成一个环路,但还没有使用编码器的位置信号来控制电机位置。 我们将使用反馈回路。 在反馈回路中,控制部件通常被称为设备(电机),这里指的是电机和电机驱动器。 我们用来测量位置的传感器(编码器)就是编码器。 为了实际控制电机的位置,需要为其提供一个目标位置,然后求出目标位置与测量位置之间的差值,其结果就是误差,通常写为 e(t)。
Arduino DC Motor Encoder

Now that the error has been computed you can use a controller to compute a control signal that is sent to the plant(motor). The control signal is configured so that it will attempt to reduce the error. The control signal is typically written as u(t).

In this project, we will use the PID control algorithm to generate the control signal u(t) the PID control signal is constructed using a sum of three terms a proportional, derivative, and integral term that is what PID stands for. The proportional term is the most important as it is directly responsible for reducing the error, the derivative and integral terms are typically used to smooth out the control system response. The three constants kp, ki and kd determine how strongly each term is represented in the control loop; you can adjust these constants to tune your response. You can estimate the integral and derivative of the error using the simple finite difference approximation. The integral term accumulates the error over time and the derivative computes how quickly the error is changing with the feedback control loop. Complete, you’re ready to write code to control the position of the motor.

既然误差已经计算出来,那么就可以使用控制器来计算发送给设备(电机)的控制信号。 控制信号经过配置后,来减小误差。 在本项目中,我们将使用 PID 控制算法来生成控制信号 u(t)。PID 控制信号由比例项、导数项和积分项三个项的总和构成,这就是 PID 的含义。 比例项最为重要,因为它直接负责减少误差,而导数和积分项通常用于平滑控制系统的响应。 三个常数 kp、ki 和 kd 决定了每个项在控制回路中的体现程度;您可以调整这些常数来调整响应。 您可以使用简单的有限差分近似估算误差的积分和导数。 积分项计算误差随时间的累积,导数项计算误差随反馈控制回路变化的速度。 完成后,您就可以编写代码来控制电机的位置了。

DC Motor control with Encoder Feedback, Arduino Code:

#include <Arduino.h>#define ENCA 2
#define ENCB 3
#define PWM 5
#define IN2 6
#define IN1 7int pos = 0;
long prevT = 0;
float eprev = 0;
float eintegral = 0;void setMotor(int dir, int pwmVal, int pwm, int in1, int in2);
void readEncoder();void setup()
{Serial.begin(9600);pinMode(ENCA, INPUT);pinMode(ENCB, INPUT);attachInterrupt(digitalPinToInterrupt(ENCA), readEncoder, RISING);Serial.println("target pos");
}void loop()
{// set target positionint target = 1200;// target = 250*sin(prevT/1e6);// PID constantsfloat kp = 1;float kd = 0.025;float ki = 0.0;// time differencelong currT = micros();float deltaT = ((float)(currT - prevT)) / (1.0e6);prevT = currT;// errorint e = pos - target;// derivativefloat dedt = (e - eprev) / (deltaT);// integraleintegral = eintegral + e * deltaT;// control signalfloat u = kp * e + kd * dedt + ki * eintegral;// motor powerfloat pwr = fabs(u);if (pwr > 255){pwr = 255;}// motor directionint dir = 1;if (u < 0){dir = -1;}// signal the motorsetMotor(dir, pwr, PWM, IN1, IN2);// store previous erroreprev = e;Serial.print(target);Serial.print(" ");Serial.print(pos);Serial.println();
}void setMotor(int dir, int pwmVal, int pwm, int in1, int in2)
{analogWrite(pwm, pwmVal);if (dir == 1){digitalWrite(in1, HIGH);digitalWrite(in2, LOW);}else if (dir == -1){digitalWrite(in1, LOW);digitalWrite(in2, HIGH);}else{digitalWrite(in1, LOW);digitalWrite(in2, LOW);}
}void readEncoder()
{int b = digitalRead(ENCB);if (b > 0){pos++;}else{pos--;}
}

Start by defining global storage variables that can be used to save values between time steps, these are used in the finite difference estimates for the integral and derivative. The first thing that you need to do in the loop function is set a target for the control loop; the control signal will be adjusted over time as the measured position becomes closer to the target. Next, define the constants used in the PID control algorithm start by setting kp to 1 and kd and ki to 0. you can come back and adjust these later to compute the finite difference approximations. We need to compute the time difference t start by recording the current time in microseconds using the micros function then compute t in seconds by taking the difference between the current time and the previous time, be careful that you are performing floating-point arithmetic not integer arithmetic; complete the calculation by storing the current time in the previous time variable for use.

首先要定义全局存储变量,用于保存周期内的值,这些值将用于积分和导数的有限差分估算。 在loop()函数中需要做的第一件事是为控制环路设置一个目标值;当测量位置变得更接近目标值时,控制信号将随时间而调整。 接下来,定义 PID 控制算法中使用的常数,将 kp 设为 1,kd 和 ki 设为 0。 我们需要计算时间差 t,首先使用 micros() 函数记录当前时间(以微秒为单位),然后计算当前时间与前一时间的差值(以秒为单位),注意是浮点运算而不是整数运算;完成计算后,将当前时间存储到前一时间变量中备用。
In the next iteration of the loop, the error is computed as the difference between the target and measured positions here I have reversed the order because of the way that I wired the motor leads if you find that your control algorithm is not working you can try switching the sign of the error term as I did now compute the derivative and integral of the arrow signal using the finite difference approximations with all that work done you are finally ready to compute your control signal. it is surprisingly simple is not it this signal will tell the plant the direction and speed to turn the motor to send the signal to the motor. We need to convert it into a speed and direction start by computing the PWM signal as the floating-point absolute value of the control signal U.

在循环的下一次迭代中,误差被计算为目标位置和测量位置之间的差值。在这里,由于电机引线的接线方式不同,我将顺序颠倒了一下,如果您发现控制算法不起作用,可以尝试像我一样转换误差项的符号。 这个信号将告诉工厂电机的旋转方向和速度,并将信号发送给电机。 我们需要通过计算 PWM 信号作为控制信号 U 的浮点绝对值,将其转换为速度和方向起始信号。

You also need to cap the PWM signal at 255 as that is the maximum value we can write next to determine the direction by computing the sign of the control signal u with the motor speed and direction computed from the control signal call the setMotor function to write to the motor driver to complete the loop function store the previous value of the error also print your target and measure positions to the serial com, so you can test how well your control algorithm is performing with these parameters. I am seeing a little overshoot after reaching the target. In other words, the motor spins too far and has to reverse directions to achieve the target position one way to reduce overshoot is to increase the derivative term here I have set kd equal to 0.025 this is enough to completely remove the overshoot for this system. Once your system works to achieve a constant target try setting a target that changes with time here I have set a sinusoidal target depending on your target and loading conditions you will need to further tune your PID parameters.

此外,您还需要将 PWM 信号的上限设定为 255,因为这是我们可以写入的最大值。接下来,通过计算控制信号 u 的符号以及从控制信号中计算出的电机速度和方向来确定方向,调用 setMotor 函数写入电机驱动器,以完成循环功能,存储之前的误差值,并将目标位置和测量位置打印到串行通信端口,这样您就可以测试您的控制算法在使用这些参数时的性能如何。 在达到目标位置后,我看到了一点过冲。 换句话说,电机转得太快,必须反转方向才能达到目标位置。减少过冲的方法之一是增加导数项,在这里我将 kd 设为 0.025,这足以完全消除该系统的过冲。 一旦您的系统能够实现恒定目标,请尝试设置一个随时间变化的目标,在这里我设置了一个正弦目标,具体取决于您的目标和负载条件,您需要进一步调整 PID 参数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/397613.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度学习碎碎念——碎片知识1

1、什么叫模型收敛&#xff1f;什么叫模型欠拟合和过拟合&#xff1f; 什么叫模型收敛&#xff1f;——模型收敛是指在训练过程中&#xff0c;模型的损失函数逐渐减小并且趋于稳定的状态。简而言之&#xff0c;当模型的训练过程达到一个稳定的点&#xff0c;使得进一步的训练不…

CV党福音:YOLOv8实现语义分割(一)

前面我们得知YOLOv8不但可以实现目标检测任务&#xff0c;还包揽了分类、分割、姿态估计等计算机视觉任务。在上一篇博文中&#xff0c;博主已经介绍了YOLOv8如何实现分类&#xff0c;在这篇博文里&#xff0c;博主将介绍其如何将语义分割给收入囊中。 YOLOv8语义分割架构图 …

【C++】特殊类的设计与类型转换

文章目录 1. 特殊类的设计1.1 不能被拷贝的类1.2 只能在堆上创建对象的类1.3 只能在栈上创建对象的类1.4 不能被继承的类1.5 只能创建一个对象的类&#xff08;单列模式&#xff09; 2. 类型转换2.1 C/C的类型转换2.2 C规定的四种类型转换2.2.1 static_cast2.2.2 reinterpret_c…

【吊打面试官系列-Elasticsearch面试题】对于 GC 方面,在使用 Elasticsearch 时要注意什么?

大家好&#xff0c;我是锋哥。今天分享关于 【对于 GC 方面&#xff0c;在使用 Elasticsearch 时要注意什么&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; 对于 GC 方面&#xff0c;在使用 Elasticsearch 时要注意什么&#xff1f; 1、SEE 2、倒排词典的索引需…

vue3使用pnpm运行项目但是运行不起来

运行项目的时候发现根本运行不起来了 尝试过创建.npmr文件 删除node_modules重新下 但是都出现问题了 创建.npmr&#xff1a;不管用 删除node_modules重新下&#xff1a;文字编译乱码&#xff0c;utf-8可能解析处理问题 最后解决方法&#xff1a; 重新创建项目&#xff0…

网络科技公司官网电商软件开发小程序网站pbootcms模板带手机端

免费授权可商用网站模板 PC端移动端后台测试数据 所有页面均都能完全自定义标题/关键词/描述&#xff0c;PHP程序&#xff0c;安全、稳定、快速&#xff0c;响应式同一个后台&#xff0c;数据即时同步&#xff0c;简单适用&#xff0c;附带测试数据&#xff01;&#xff01;

物流仓库安全视频智能管理方案:构建全方位、高效能的防护体系

一、背景分析 随着物流行业的快速发展和仓储需求的日益增长&#xff0c;仓库安全成为企业运营中不可忽视的重要环节。传统的人工监控方式不仅效率低下&#xff0c;且难以做到全天候、无死角覆盖&#xff0c;给仓库资产和人员安全带来潜在风险。因此&#xff0c;引入仓库安全视…

了解细胞外基质:它是啥?有啥作用?

了解细胞外基质&#xff1a;它是啥&#xff1f;有啥作用&#xff1f; 大家好&#xff0c;今天我们来阅读这篇Biofabrication methods for reconstructing extracellular matrix mimetics发表于《Bioactive Materials》上的文章。细胞外基质在人体中起着至关重要的作用&#xff…

同城门户同城分类信息网站源码discuz插件+pc端+小程序端+49款插件

同城分类信息 同城好店 同城合伙人 同城招聘 同城卡 同城活动 同城优惠抢购 同城商城 同城头条 同城抽奖 同城拼团 同城砍价 同城电话本 同城认证 同城签到 同城拼车 同城红包 同城子站点 同城相亲 同城交友 同城小程序 比较流行的同城信息门户网站源码&#xff0c;基于dz&…

【计算机网络】网络基础概念

目录 计算机网络发展 协议 协议分层 OSI 七层模型 TCP/IP 五层&#xff08;四层&#xff09;模型 究竟什么是协议&#xff1f; 网络与操作系统的关系 网络传输基本流程 局域网网络传输流程 认识 MAC 地址 局域网&#xff08;以太网为例&#xff09;通信原理 数据包…

【前端设计方案】H5 图片懒加载 SDK

实现思路 定义<img srcloading.png data-srcxxx.png/>页面滚动&#xff0c;图片露出时&#xff0c;将 data-src 赋值给 src 注意事项&#xff1a;滚动要节流 技术要点 获取图片的位置 elem.getBoundingClientRect() 图片 top < window.innerHeight 时&#xff0c;图片…

Install pytorch 使用 torch 的例子

如果不知道怎么开始和安装软件 从这里开始 如果需要GPU版本&#xff0c;请选择CUDA&#xff0c;而不是CPU PyTorchhttps://pytorch.org/ Python 3.8.13 | packaged by conda-forge | (default, Mar 25 2022, 06:04:10) [GCC 10.3.0] on linux Type "help", &quo…

opencv 深度图视差图可视化案例

参考:https://www.cnblogs.com/zyly/p/9373991.html(图片这里面下载的) https://blog.csdn.net/He3he3he/article/details/101053457 原理 双目摄像头 视差公式: 三角形对应推算 深度距离转换: 这里d是视差Disparity 代码 下面两种计算视差方法: import os impor…

计算机毕业设计Hadoop+Hive居民用电量分析 居民用电量可视化 电量爬虫 机器学习 深度学习 大数据毕业设计 Spark

《Hadoop居民用电量分析》开题报告 一、研究背景与意义 能源问题在全球范围内一直是热点议题&#xff0c;尤其是随着居民生活水平的提高和城市化进程的加快&#xff0c;居民用电量急剧增长&#xff0c;对电力系统的稳定运行和能源管理提出了更高要求。如何科学合理地管理和分…

T9打卡学习笔记

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 import tensorflow as tfgpus tf.config.list_physical_devices("GPU")if gpus:tf.config.experimental.set_memory_growth(gpus[0], True) #设置…

红黑树的插入

文章目录 3.红黑树3.1概念3.2 性质3.3 RBTree的实现3.3.1 insert的框架3.3.2 insert的处理3.3.3 中序遍历3.3.4检查是否平衡和获取树的高度 3.4完整代码 3.红黑树 3.1概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储位表示结点的颜色&#xf…

07一阶电路和二阶电路的时域分析

一阶电路和二阶电路的时域分析 时域分析、频域分析、复频域分析本应该在信号与系统&#xff0c;或者数字信号处理这一章节里面进行处理的。 但在电路理论中也有这些知识&#xff0c;那就要好好掌握一下&#xff0c;打个底。详细细致的部分放到信号与系统里面去掌握

【单片机开发软件】使用VSCode开发STM32环境搭建

&#x1f48c; 所属专栏&#xff1a;【单片机开发软件技巧】 &#x1f600; 作  者&#xff1a; 于晓超 &#x1f680; 个人简介&#xff1a;嵌入式工程师&#xff0c;专注嵌入式领域基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1f496; 欢迎大家&#xff1…

Java Web —— 第四天(HTTP协议,Tomcat)

HTTP-概述 概念:Hyper Text Transfer Protocol&#xff0c;超文本传输协议&#xff0c;规定了浏览器和服务器之间数据传输的规则 特点: 1. 基于TCP协议:面向连接&#xff0c;安全 2.基于请求-响应模型的:一次请求对应一次响应 3. HTTP协议是无状态的协议: 对于事务处理没有…

ASUS/华硕魔霸新锐2020 G512L系列 原厂win10系统 工厂文件 带F12 ASUS Recovery恢复

华硕工厂文件恢复系统 &#xff0c;安装结束后带隐藏分区&#xff0c;一键恢复&#xff0c;以及机器所有驱动软件。 系统版本&#xff1a;windows10 原厂系统下载网址&#xff1a;http://www.bioxt.cn 需准备一个20G以上u盘进行恢复 请注意&#xff1a;仅支持以上型号专用…