我们学习了如何用电压来控制直流电机的转速,但要在我们的机器人中成功使用直流电机,我们需要控制的不仅仅是电机的速度,还有电机的位置。基本上有两种方法可以做到这一点:开环(Open loop)控制或反馈(Feedback)控制。在这篇文章中,我们将学习这些选项之间的区别。
开环控制和反馈控制之间的基本区别在于是否使用传感器。在开环控制中,不使用传感器,反馈控制中则使用传感器。我们可以使用一种叫做方块图的东西来可视化这两种控制类型之间的差异。在方块图中,我们使用一个方块来显示系统的每个部分,它接收输入并产生输出,我们使用箭头来显示系统中的每个信号。在我们的系统中,信号是任何随时间变化的量。这里有几个例子:在我们的控制系统中,我们有一个电机,它将由一个方块表示。电机接收输入电压并产生输出速度。电压和速度都是信号,因为它们的大小是可以随时间变化的。我们控制电压信号,电机转动,将电压转换为速度。

开环控制方块图
我们还可以添加另一个方块,这是一个积分器(Integral),这样就可以输出位置而不是速度。反馈控制有一个额外的方块,它读取位置。然后我们使用读取到的位置来决定为电机产生什么电压。

反馈控制方块图
由于不需要传感器,开环控制更简单、更便宜,我们将了解更多关于这方面的内容。另一方面,反馈控制更准确。让我们通过尝试这两种控制方式来了解更多。
让我们从开环控制开始。为了实现开环控制,我们将计算电机达到期望位置所需的时间,然后设置电机的速度,等待指定的时间,然后关闭电机。让我们尝试一下。我们已经知道电机在每个比较值下会以多快的速度转动,所以我们可以实现开环控制。假设我们将应用1伏电压,以便电机以1879转每分钟的速度转动,正如我们之前学到的,假设我们希望电机转动90°或四分之一转:
比较值 = 255*(0.25/1879*60) = 2
连接布局(采用不带编码器的普通电机):

// Define the pin connections for the L293D
int IN1 = 8; // Control pin 1
int IN2 = 9; // Control pin 2
int ENABLE1 = 10; // PWM pin for speed control
void setup() {
// Set the motor control pins as outputs
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(ENABLE1, OUTPUT);
}
void loop() {
// Example: Run the motor forward at full speed for 3 seconds
digitalWrite(IN1, HIGH); // Set IN1 high
digitalWrite(IN2, LOW); // Set IN2 low
analogWrite(ENABLE1, 2); // Set speed to 2 (255 is full PWM)
delay(1000); // Run for 1 seconds
// Stop the motor for 1 second
analogWrite(ENABLE1, 0); // Stop motor by setting speed to 0
delay(1000);
}
让这个运行几个不同的周期,并对你所看到的做一些观察。当我们观察电机转动时,注意一些特性。电机转动的量非常接近90°,但并不完全准确。随着转动次数的增加,电机开始漂移(drift),即误差随时间累积。但运动非常非常平滑且快速。另外可以用手转动电机转子,控制算法根本不在乎。这种外部力影响电机位置的事件被称为干扰(disturbance)。开环控制的一个特性是无法拒绝这些干扰。

开环控制电机转1/4圈
接下来,让我们设置反馈控制。最简单的反馈控制类型叫做开关控制(on off control)。在这种控制中,我们将首先将电机向前转动。接下来,我们将从传感器读取并检查当前位置是否小于目标位置。目标位置是我们试图让电机移动到的位置。如果位置小于目标位置,我们希望继续向前转动电机。如果位置不小于目标位置,我们接下来要做的是检查位置是否大于目标位置。如果位置大于目标位置,在这种情况下,我们希望将电机向后转动,以回到目标位置。如果位置不大于目标位置,唯一剩下的可能就是位置完全等于目标位置。在这种情况下,我们希望关闭电机。现在,我们不想在这里结束,我们想立即回去检查位置是否小于目标位置。通过这样做,我们可以成功地拒绝干扰。换句话说,如果我伸出手,将电机轴从目标位置转开,我们可以通过使用传感器并纠正它来注意到这一点。
另外,注意我在这里画的流程图中,我们有循环。我们有几条箭头循环回来创建循环。这是反馈控制的一个特性。在反馈控制中,你将有循环将传感器检查连接到电机动作。在开环控制中,我们根本没有循环。

连接布局(采用带编码器的电机)

#include <Encoder.h> // Include Encoder library
// Define motor control pins
int IN1 = 8;
int IN2 = 9;
int ENABLE1 = 10; // PWM for speed
// Define encoder pins and create Encoder object
Encoder myEncoder(2, 3); // Channel A = pin 2, Channel B = pin 3
long targetPosition = 250; // 1/4 cycle, assuming 1000 pulses for a full cycle
long currentPosition = 0; // Current position from the encoder
void setup() {
// Set motor control pins as outputs
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(ENABLE1, OUTPUT);
// Initialize serial communication for debugging
Serial.begin(9600);
// Reset encoder position to 0 at start
myEncoder.write(0);
}
void loop() {
// Read the current encoder position
currentPosition = myEncoder.read();
// Print positions for debugging
Serial.print("Current Position: ");
Serial.print(currentPosition);
Serial.print(" | Target Position: ");
Serial.println(targetPosition);
// Check if the motor needs to move to reach the target position
if (currentPosition < targetPosition - 5) {
// Rotate forward
digitalWrite(IN1, HIGH); // Forward direction
digitalWrite(IN2, LOW);
analogWrite(ENABLE1, 20); // Adjust speed (200 out of 255)
} else if (currentPosition > targetPosition + 5) {
// Rotate backward
digitalWrite(IN1, LOW); // Backward direction
digitalWrite(IN2, HIGH);
analogWrite(ENABLE1, 20); // Adjust speed
} else {
// Stop the motor when the target position is reached
analogWrite(ENABLE1, 0); // Stop motor by setting speed to 0
}
delay(100); // Small delay for stability
}
当我们运行这个时,注意几件事。首先,这种控制是不稳定的。你观察到的抖动(jiterring)是因为电机超过了目标点,反向,再次超调(overshoot),再次反向,如此反复,永远。这种不稳定性总是出现在反馈控制而不是开环控制,因为开环控制不会有反转方向。

开-关反馈控制
其次,如果你将电机从目标点转开,然后放开它,电机会弹回到目标点。这种干扰拒绝(disturbance rejection)只出现在反馈控制,而非开环控制。