Arduino太阳能跟踪器
该项目展示了一个基于Arduino Uno的太阳能跟踪器开发平台。该平台利用太阳能电池板检测光照变化,并通过伺服电机实现方位调节以追踪太阳位置。硬件系统包括太阳能电池板、按钮开关、微型伺服电机等模块,而软件则通过PWM信号控制电机运动并实现自动或手动模式切换。此外,系统还集成了一套虚拟仪器(如Excel),用于实时采集并分析光伏数据。该解决方案采用低成本且易于维护的硬件配置,在学生及研究人员中具有广泛的应用潜力。
Arduino太阳能跟踪器
-
- 介绍
- 组件和耗材
- 应用和平台
- 项目描述
- 代码
介绍
开放式的硬件平台/软件测试套件(可访问软件测试)主要针对具有虚拟仪器支持的太阳能追踪系统。

组件和耗材
1-UNO系列Arduino芯片
1-小型太阳能发电组件
2-手动控制按钮(单独按钮)
1-可旋转调节旋钮(通用型号)
2-SG90型微型伺服马达
4-阻值为330欧姆的电阻元件
4-LDR光敏传感器
应用和平台
Arduino IDE
项目描述
本项目开发了一款开放式的硬件/软件综合测试平台用于研究太阳能追踪装置。采用Arduino Uno作为控制器的双轴式太阳能能追踪装置是该方案的核心组件ArduinoUno微控制器搭配一个开源的软件架构能够满足模块化设计的需求。这种设计不仅便于维护还能够扩展功能以适应不同场景的需求。在系统运行过程中可以通过光相关电阻器(LDR)传感器实现自动运行的同时也可以通过电位计进行手动调节以适应不同的实验需求此外该测试平台还集成了一个基于Excel的数据采集与分析工具能够实时记录并显示系统的运行数据这一系统选用的所有组件均经过精心挑选以保证其价格低廉体积小巧而且功能多样化的特点。拟开展的研究项目旨在帮助学习者深入理解控制理论及其在实际系统中的应用从而培养其在能源设备开发领域的专业能力。
此款试验台设计直观(如图1所示),它基于太阳能追踪器系统,在四个LDR传感器与两个伺服电机(SM1与SM2)的支持下即可完成自动旋转追踪太阳的功能。此外,在两种运行模式间切换可通过操作按钮轻松实现:一种是自动模式由太阳能驱动实现追踪功能;另一种则通过电位计进行手动控制调节方向。特别地,在两种控制模式下均可分别选择上下伺服电机(SM1)或左右伺服电机(SM2)进行链接配置,并通过操作按钮调节其运动状态。值得注意的是,在此系统中计算机不仅可作为虚拟仪器工具使用,并且能够根据MS Excel的时间表可视化光伏电池板的工作模式及其电流、电压和功率参数变化情况;Arduino Uno 板则负责满足系统所有软件需求。

采用CATIA软件进行建模,在该系统中构建了一个完整的太阳能跟踪装置三维模型。该模型由光伏组件支撑架设、左右两端驱动机构以及上下支撑单元构成。其中水平轴系通过轴承与上下驱动单元平行安装以保证运动灵活性。该系统具有两个独立的运动自由度:向东向西运动主要受左右驱动机构控制;向南向北运动则由上下驱动单元负责实现。此外,在光伏组件四个角端点布置了专门的检测元件,并将其顶端设有若干个小孔作为结构传感器。这些传感器不仅用于接收太阳光信号还能起到聚光作用以增强装置的整体性能稳定运行能力

图3展示了本文所提出的测试平台的电子电路配置。在自动模式下,该微控制器通过将LDR传感器(引脚A0至A3)的模拟信号转换为数字信号来实现对太阳追踪功能的支持。随后系统利用两个脉宽调制(PWM)信号(引脚5和6)驱动上下及左右两个伺服电机进行动作调节。这些电机按照从东到西的日间太阳方位角以及从南到北的季节性太阳高程变化进行旋转运动以确保追踪效果。当切换至手动模式时,则通过电位计(引脚A4)控制伺服电机运行并配备两个按钮分别用于连接不同方向的伺服电机以及在不同模式间切换操作。此外,在测量PV系统输出参数方面,PV电压通过Arduino的模拟引脚A5采集后计算PV电流值(因负载电阻已知)。最后将采集到的PV电压、电流及功率数据与时间信息同步传输至计算机端以便于在MS Excel中实时可视化这些参数的变化情况

本研究中的LDR传感器电路采用了分压器电路的设计方案。光强度的变化与其对应的分压器输出电压呈正相关。其中顶端接至5伏电源(VCC),底部接地至零伏(GND)。将该电路的输出端子连接至单片机的模拟输入端子:随后将该模块连接至单片机上:模数转换部分通过ADC芯片完成数字信号转换工作。其中所使用的电阻均为330欧姆。根据所得数字代码可以推断出光照强度的不同等级。
采用两个180度角行程的高精度伺服电机,在本系统中分别负责太阳能跟踪器的纵向和横向运动控制。其中左侧为纵向运动控制器右侧为横向运动控制器。本系统还配备SG90型号的小型伺服电机用于水平轴上的太阳能跟踪器控制。该小型驱动单元负责垂直方向上的运动操作。
本系统采用嵌入式软件设计旨在实现对硬件组件的有效监控与管理。
嵌入式软件旨在满足以下功能需求:
该设计允许我们仅通过一条低电流线即可实现对伺服电机状态的各种操作包括启动停止以及速度调节。所有驱动单元均与Arduino UNO R3微控制器相连并通过一根三芯电缆实现供电与数据传输。
试验台有两种模式:手动和自动。按钮连接到引脚 12,可在两种模式之间切换。
如果手动模式处于活动状态,则可以通过电位器分别控制不同方向的伺服motor. 具体而言,在东西走向上操作左端至右端的servo motor,在南北走向上操作南端至北端的servo motor. 通过引脚 11配置的一个button可实现对不同方向motor的操作切换配置.
如果自动模式处于活动状态,则将执行图 4 中所示的算法。后者使用LDR传感器返回的模拟值。例如,考虑方位角或垂直轴,比较两个右LDR和两个左LDR的平均值,如果左组LDR接收到更多的光,太阳能跟踪器将通过左右伺服电机向该方向移动。后者将继续旋转,直到差异结果在 [−10, 10] 范围内。该范围用于稳定控制器,一旦太阳能跟踪器垂直于太阳,就不再进行进一步的控制。另一方面,如果右组LDR接收到更多的光,则太阳能跟踪器通过左右伺服电机沿该方向移动,并将继续旋转,直到差异结果在[-10,10]范围内。 高程轴也使用相同的方式。此外,我们还确定了四个LDR传感器之间的平均辐射,以及该值是否小于一点值(8:经过实际调整和测试的值,当辐照为零时返回)。也就是说,夜晚已经到来。在这种情况下,太阳能跟踪器必须返回到太阳的上升位置。例如,如果在左右伺服电机中设置0度,在上下伺服电机中设置30度可以达到太阳的上升位置。这可以通过C函数“servox”轻松完成。write(angle)“由Arduino IDE提供。 经过实际调整和测试的值,当辐照为零时返回)。也就是说,夜晚已经到来。在这种情况下,太阳能跟踪器必须返回到太阳的上升位置。例如,如果在左右伺服电机中设置0度,在上下伺服电机中设置30度可以达到太阳的上升位置。这可以通过C函数“servox”轻松完成。write(angle)“由Arduino IDE提供。 经过实际调整和测试的值,当辐照为零时返回)。也就是说,夜晚已经到来。在这种情况下,太阳能跟踪器必须返回到太阳的上升位置。例如,如果在左右伺服电机中设置0度,在上下伺服电机中设置30度可以达到太阳的上升位置。这可以通过C函数“servox”轻松完成。write(angle)“由Arduino IDE提供。
涉及模拟引脚A5采集的光伏电压数据将被用于计算相应的光伏电流值及其功率参数。随后将这些数据与实际模式进行对比,并通过USB接口将采集到的数据传输至计算机,在Excel中进行详细对比分析。
此PLX-DAQ Excel宏主要用于实现Arduino微控制器与Excel电子表格之间的数据采集与传输。安装此程序后即可开始使用。
安装程序完成后,在电脑桌面上会自动生成一个名为"PLX-DAQ"的文件夹,并在此文件夹中包含一个快捷方式"PLX-DAQ电子表格"。
随后设置好硬件通信参数(包括波特率和串口端口号),打开Excel并启动PLX-DAQ界面(如图5所示)。完成以上设置后点击"连接"按钮即可实现设备与电脑之间的实时数据同步更新。

图6呈现了处于分离与组装状态下的太阳能追踪装置。如所述, 整个框架采用木制材料搭建, 显然, 所有提及的组件均用于构建具备手动与自动模式的太阳能追踪装置(包括LDR传感器、Arduino Uno、伺服马达、电位计、按钮及小型光伏板)。

如图7所示,在实验台上安装了带有虚拟仪器的人工智能太阳能追踪装置,并配置了一盏人造日光灯用于模拟光照环境。该装置通过USB接口与计算机建立了数据传输通道。当系统采集到光伏组件(PV)电压值后,则会立即启动数据处理程序,并基于此计算出相应的光伏电流及功率参数值。随后系统会将所有采集到的数据传输至计算机端,在电子表格软件MSExcel中进行了详细的数据展示与分析。从图5和图6可以看出,在这种设计下所构建的实验测试台具有体积小、操作简便且灵活性强等特点。它不仅能够方便地应用于教学环境中的算法验证工作,在后续研究开发大型光伏跟踪系统时也具有重要的参考价值

代码
//Servo motor library
#include <Servo.h>
//Initialize variables
int mode = 0;
int axe = 0;
int buttonState1 = 0;
int buttonState2 = 0;
int prevButtonState1 = 0;
int prevButtonState2 = 0;
int ldrtopr= 0; // top-right LDR
int ldrtopl = 1; // top-left LDR
int ldrbotr = 2; // bottom-right LDR
int ldrbotl = 3; // bottom-left LDR
int topl = 0;
int topr = 0;
int botl = 0;
int botr = 0;
//Declare two servos
Servo servo_updown;
Servo servo_rightleft;
int threshold_value=10; //measurement sensitivity
void setup()
{
Serial.begin(9600); //serial connection setup //opens serial port, sets data rate to 9600 bps
Serial.println("CLEARDATA"); //clear all data that’s been place in already
Serial.println("LABEL,t,voltage,current,power,Mode"); //define the column headings (PLX-DAQ command)
pinMode(12, INPUT); //Mode switch Button
pinMode(11, INPUT); //Axis switch
pinMode(A4, INPUT); //Potentiometer for right-left movement and for up-down movement
servo_updown.attach(5); //Servo motor up-down movement
servo_rightleft.attach(6); //Servo motor right-left movement
}
void loop()
{
// pv_power();
char Mode;
float volt = analogRead(A5)*5.0/1023;
float voltage = 2*volt; // Volt=(R1/R1+R2)*Voltage / R1=R2=10Ohms => voltage=2*volt)
float current = voltage/20; // I=voltage/(R1+R2)
float power = voltage*current;
Serial.print("DATA,TIME,"); // PLX-DAQ command
Serial.print(voltage); //send the voltage to serial port
Serial.print(",");
Serial.print(current); //send the current to serial port
Serial.print(",");
Serial.print(power); //send the power to serial port
Serial.print(",");
// Serial.println(Mode);
buttonState1 = digitalRead(12);
if (buttonState1 != prevButtonState1) {
if (buttonState1 == HIGH) {
//Change mode and ligh up the correct indicator
if (mode == 1) {
mode = 0;
} else {
mode = 1;
}
}
}
prevButtonState1 = buttonState1;
delay(50); // Wait for 50 millisecond(s)
if (mode == 0) {
Mode='M';
Serial.println(Mode); //send Mode "Manual" to serial port
manualsolartracker();
} else { // mode automatic
Mode = 'A';
Serial.println(Mode);
automaticsolartracker(); //send Mode "Automatic" to serial port
}
}
void automaticsolartracker(){
//capturing analog values of each LDR
topr= analogRead(ldrtopr); //capturing analog value of top right LDR
topl= analogRead(ldrtopl); //capturing analog value of top left LDR
botr= analogRead(ldrbotr); //capturing analog value of bot right LDR
botl= analogRead(ldrbotl); //capturing analog value of bot left LDR
// calculating average
int avgtop = (topr + topl) / 2; //average of top LDRs
int avgbot = (botr + botl) / 2; //average of bottom LDRs
int avgleft = (topl + botl) / 2; //average of left LDRs
int avgright = (topr + botr) / 2; //average of right LDRs
//Get the different
int diffelev = avgtop - avgbot; //Get the different average betwen LDRs top and LDRs bot
int diffazi = avgright - avgleft; //Get the different average betwen LDRs right and LDRs left
//left-right movement of solar tracker
if (abs(diffazi) >= threshold_value){ //Change position only if light difference is bigger then the threshold_value
if (diffazi > 0) {
if (servo_rightleft.read() < 180) {
servo_rightleft.write((servo_updown.read() + 2));
}
}
if (diffazi < 0) {
if (servo_rightleft.read() > 0) {
servo_rightleft.write((servo_updown.read() - 2));
}
}
}
//up-down movement of solar tracker
if (abs(diffelev) >= threshold_value){ //Change position only if light difference is bigger then thethreshold_value
if (diffelev > 0) {
if (servo_updown.read() < 180) {
servo_updown.write((servo_rightleft.read() - 2));
}
}
if (diffelev < 0) {
if (servo_updown.read() > 0) {
servo_updown.write((servo_rightleft.read() + 2));
}
}
}
}
void manualsolartracker(){
buttonState2 = digitalRead(13);
if (buttonState2 != prevButtonState2) {
if (buttonState2 == HIGH) {
//Change mode and ligh up the correct indicator
if (axe == 1) {
axe = 0;
} else {
axe = 1;
}
}
}
prevButtonState2 = buttonState2;
delay(50); // Wait for 50 millisecond(s)
if (axe == 0) { //control right-left movement
servo_rightleft.write(map(analogRead(A4), 0, 1023, 0, 180));
} else { // //control up-down movement
servo_updown.write(map(analogRead(A4), 0, 1023, 0, 180));
}
}
