Arduino 平台 - 差动间隙控制 (太阳跟踪器)
通过差分间隙控制实现追踪太阳东西运动的简单方法
引言
本文对在 Arduino 平台上编写差分间隙控制器进行了非常简单的介绍。我使用了一个 Duemilanove 作为此示例。
该项目由两个输入组成,用于追踪东西方向的光照水平,然后用这些输入来移动一个伺服电机,旋转东西方向以追踪最强的光照水平。
原型机的所有荣耀......多余的 MSDN 光盘终于找到了用武之地
工作原理
两个光传感器是基本的光敏电阻,它们彼此成 90' 角安装,想象一下它们是你的眼睛,如果你直视一堵墙,左眼会指向左侧 45',右眼会指向右侧 45'。这些传感器也被屏蔽,因此当它们直接指向光源时,它们将看到最亮的光照水平。如果光源移动,会在传感器上投下阴影,改变其电阻。
当追踪阳光,例如用于太阳能电池板时,您将需要最大的阳光强度,为了实现这一点,两个传感器都需要看到相同强度的光。这就是我们确定间隙控制器输入的方式。
读取两个输入传感器的值,并进行比较,0 差值表示它们处于相同的光照水平,负误差值表示光照在右侧更亮,正误差值表示光照在左侧更亮。
然后将伺服电机发送一个位置值,我们只需在每次扫描时递增或递减输出,即可将平台东西旋转,以再次找到传感器上最佳的平衡光照水平。
在代码中,也有上下限,以防止伺服电机因过度驱动而损坏。代码中还建立了一个死区值。这实际上意味着,除非两个输入之间的误差大于某个值,否则输出将不会改变。死区可以防止传感器的抖动和不断抽搐。
我还添加了一个非常基本的 2 点平均值,以帮助平滑输入传感器中的尖峰。实际上,您可能希望进一步过滤掉它以过滤掉不需要的噪声或尖峰。
Using the Code
下载中提供的草图文件可以上传到 Arduino。现在让我们更详细地看一下代码。
代码的第一部分用于建立 IO 引脚分配,用于保存输入读数、误差和滚动误差平均值的变量。还定义了死区范围,以及伺服电机的上下限,以及伺服电机的初始起始点。
#include
语句引用了一个预先构建的库,用于处理 Arduino 上的伺服电机。它基本上允许将一个简单的值写入伺服电机对象,然后处理用于设置伺服电机位置的脉冲宽度调制。
#include <servo.h>
//IO Pins
int pinL = 5; //Left Sensor IO Pin
int pinR = 4; //Right Sensor IO Pin
int pinServo = 11; //Servo PWM pin
int leftValue = 0; //The left Sensor Value
int rightValue = 0; //The right Sensor Value
int error =0; //The Deviation between the 2 sensors
int errorAVG = 0; //Error Average - Rolling 2 Point
int deadband = 10; //Range for which to do nothing with output 10 = -10 to +10
//Servo Stuff
Servo hServo; //The servo object
int Position = 45; //Position to write out
int minPos = 5; //Min Position
int maxPos = 150; //Max Position
float output = (maxPos - minPos) /2; //Initial output Position
代码的下一部分是 Arduino Setup 方法。这运行一次,实际上用于在主代码循环执行之前初始化您想要的一切。在此示例中,我所做的只是将 Servo 输出设置为 Min、Max 和 MidPoint,每个持续 5 秒钟,以便在我的桌面上进行硬件定位测试。Serial 语句仅将消息输出到串行端口,可以在 PC 上进行监视。
void setup()
{
Serial.begin(9600);
hServo.attach(pinServo);
//Set Servo to Centre for Alignment Purpose
Serial.println("Moving Servo to Minimum Position");
hServo.write(minPos);
delay(5000);
Serial.println("Moving Servo to Maximum Position");
hServo.write(maxPos);
delay(5000);
Serial.println("Moving Servo to Mid-Point");
hServo.write(output);
delay(5000);
Serial.println("Going Live................");
}
代码的最后一部分是主循环体,这是将持续运行的循环,直到电源关闭或将新代码下载到 Arduino。
首先读取输入值,然后将一些调试信息输出到串行端口。计算误差值,并通过添加 getTravel()
返回的值来确定传感器的修订新位置。也检查了极限值,以确保我们没有超过这些。
void loop()
{
//Input Reading
leftValue = analogRead(pinL);
rightValue = analogRead(pinR);
Serial.print("L = "); Serial.print(leftValue); Serial.print(" | ");
Serial.print("R = "); Serial.print(rightValue); Serial.print(" | ");
Serial.print("E = "); Serial.print(error); Serial.print(" | ");
Serial.print("Eavg = "); Serial.print(errorAVG);
Serial.println();
//Calculate
error = leftValue - rightValue;
errorAVG = (errorAVG + error) / 2;
float newOutput = output + getTravel();
if (newOutput > maxPos)
{
Serial.println("At Upper Limit");
newOutput = maxPos;
}
else
{
if (newOutput < minPos)
{
Serial.println("At Lower Limit");
newOutput = minPos;
}
}
Serial.println("Writing output");
//Output Writing
hServo.write(newOutput);
output = newOutput;
}
我还有一个辅助方法 getTravel()
,用于确定我是否需要在每次扫描时向左旋转、向右旋转或什么都不做(例如,在死区内)。它只是返回一个 +1、-1 或 0,然后将其添加到当前位置,然后再写入伺服电机。
int getTravel()
{
// -1 = Left; +1 = Right
if (errorAVG < (deadband * -1))
{
return 1;
}
else
{
if (errorAVG > deadband)
{
return -1;
}
else
{
//Do not move within deadband
return 0;
}
}
}
正在运行的原型
可以在 这里 找到原型运行的视频。
关注点
就这么简单。您可以增强此功能的几种方法是
- 在输入信号上实现改进的噪声过滤
- 为控制算法添加某种形式的 PID(比例/积分/微分)
- 添加第二个伺服电机和额外的传感器以进行垂直运动
其他
访问我的其他文章或我的网站以获取更多 Arduino 的东西。在 CodeProject 上搜索 Arduino,还有其他人发布的更多内容。
历史
- 2010 年 9 月 22 日 - 文章的第一个版本