65.9K
CodeProject 正在变化。 阅读更多。
Home

Arduino 平台 - 差动间隙控制 (太阳跟踪器)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.95/5 (21投票s)

2010年9月22日

CPOL

4分钟阅读

viewsIcon

164492

downloadIcon

1274

通过差分间隙控制实现追踪太阳东西运动的简单方法

ArduinoLightTrack/LightTracker.png

引言

本文对在 Arduino 平台上编写差分间隙控制器进行了非常简单的介绍。我使用了一个 Duemilanove 作为此示例。

该项目由两个输入组成,用于追踪东西方向的光照水平,然后用这些输入来移动一个伺服电机,旋转东西方向以追踪最强的光照水平。

原型机的所有荣耀......多余的 MSDN 光盘终于找到了用武之地

ArduinoLightTrack/Hardware.JPG

工作原理

两个光传感器是基本的光敏电阻,它们彼此成 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 日 - 文章的第一个版本
© . All rights reserved.