RF method receiver code (via HC-12 module):
// Special thanks to geo bruce at instructables.com.
// Special thanks to Robin2 and his code for parsing data, and others on Arduino forums.
// Special thanks to all my software programming friends.
// HC-12 receiver code for dual axis solar tracking.
// Low photoresistor values means less light is placed on them.
#include <SoftwareSerial.h>
SoftwareSerial HC12(11,10); // (HC-12 TX pin, HC-12 RX)
// Azimuth and elevation PWM (pulse width modulation) pins on each h-bridge must be connected to four pwm pins on arduino.
// For uno/micro/pro mini they are: 3,5,6,9,10,11.
int AREN = 7;
int ARPWM = 6;
int ALEN = 8;
int ALPWM = 9; // motor azimuth adjustment
int EREN = 2;
int ERPWM = 3;
int ELEN = 4;
int ELPWM = 5; // motor elevation adjustment
const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars]; // temporary array for use when parsing
// variables to hold the parsed data
int TL = 0; //top right sensor
int BL = 0; //bottom right
int TR = 0; //top left
int BR = 0; //bottom left
int EA = 0; //elevation angle
// Adjustable variables on receiver end
int DT = 2000; //delay time between readings for motors
int TE = 6; //set tolerance value for difference between sensors
boolean newData = false;
//=======================================================================
void setup() {
Serial.begin(9600);
HC12.begin(9600); //serial port to HC12
pinMode(AREN, OUTPUT); pinMode(ARPWM, OUTPUT); pinMode(ALEN, OUTPUT); pinMode(ALPWM, OUTPUT); //set all motor control pins to outputs
pinMode(EREN, OUTPUT); pinMode(ERPWM, OUTPUT); pinMode(ELEN, OUTPUT); pinMode(ELPWM, OUTPUT);
}
void loop() {
recvWithStartEndMarkers();
if (newData == true) {
strcpy(tempChars, receivedChars);
// this temporary copy is necessary to protect the original data
// because strtok() used in parseData() replaces the commas with \0
parseData();
showParsedData();
newData = false;
}
int avt = (TR + TL) / 2; // average value top
int avd = (BL + BR) / 2;
int avl = (TL + BL) / 2;
int avr = (TR + BR) / 2;
int dv = avt - avd; // average difference of top and bottom light sensors
int dh = avl - avr; // average difference of left and right light sensors
if (-1 * TE > dh || dh > TE) // check if the difference in left and right light sensors is within tolerance range
{
if (avl > avr) // if average light sensor values on left side are greater than right side, azimuth motor rotates clockwise
{
digitalWrite(AREN, HIGH); analogWrite(ARPWM, 255); // set speed out of possible range 0~255
digitalWrite(ALEN, HIGH); digitalWrite (ALPWM, LOW);
Serial.println("AZIMUTH MOTOR MOVES CLOCKWISE");
Serial.println(" ");
}
else // if average light sensor values on right side are greater than on left side, azimuth motor rotates counterclockwise
{
digitalWrite(ALEN, HIGH); analogWrite(ALPWM, 255);
digitalWrite(AREN, HIGH); digitalWrite(ARPWM, LOW);
Serial.println("AZIMUTH MOTOR MOVES COUNTERCLOCKWISE");
Serial.println(" ");
}
}
else if (-1 * TE < dh || dh < TE) // if difference is smaller than tolerance, stop azimuth motor
{
digitalWrite(AREN, LOW); digitalWrite(ALEN, LOW);
Serial.println("AZIMUTH MOTOR STOPS");
Serial.println(" ");
}
if (-1 * TE > dv || dv > TE) // check if the difference in top/bottom light sensors is greater than tolerance
{
if (avt > avd) // if average light sensor values on top side are greater than on bottom side then elevation motor rotates clockwise
{
digitalWrite(EREN, HIGH); analogWrite(ERPWM, 255);
digitalWrite(ELEN, HIGH); digitalWrite(ELPWM, LOW);
Serial.println("ELEVATION MOTOR MOVES CLOCKWISE");
Serial.println(" ");
}
else // if average light sensor values on bottom side are greater than on top side then elevation motor rotates counterclockwise
{
digitalWrite(ELEN, HIGH); analogWrite(ELPWM, 255);
digitalWrite(EREN, HIGH); digitalWrite(ERPWM, LOW);
Serial.println("ELEVATION MOTOR MOVES COUNTERCLOCKWISE");
Serial.println(" ");
}
}
else if (-1 * TE < dv || dv < TE) // if difference is smaller than tolerance, stop elevation motor
{
digitalWrite(EREN, LOW); digitalWrite(ELEN, LOW);
Serial.println("ELEVATION MOTOR STOPS");
Serial.println(" ");
}
else if (abs(EA) > 70)
{
digitalWrite(EREN, LOW); digitalWrite(ELEN, LOW);
Serial.println("ELEVATION MOTOR STOPS");
Serial.println(" ");
}
delay(DT);
}
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (HC12.available() > 0 && newData == false) {
rc = HC12.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
//=====================================================================
void parseData() { // split the data into its parts
char * strtokIndx; // this is used by strtok() as an index
strtokIndx = strtok(tempChars, ","); // get the first part - the string
TL = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
BL = atoi(strtokIndx);
strtokIndx = strtok(NULL, ",");
TR = atoi(strtokIndx);
strtokIndx = strtok(NULL, ",");
BR = atoi(strtokIndx);
strtokIndx = strtok(NULL, ",");
EA = atof(strtokIndx);
}
//=======================================================================
void showParsedData() { // shows parsed data in serial monitor output of PC
Serial.println("<TL,BL,TR,BR,EA,DT,TE>");
Serial.print("<");
Serial.print(TL);
Serial.print(",");
Serial.print(BL);
Serial.print(",");
Serial.print(TR);
Serial.print(",");
Serial.print(BR);
Serial.print(",");
Serial.print(EA);
Serial.print(",");
Serial.print(DT);
Serial.print(",");
Serial.print(TE);
Serial.print(">");
Serial.println();
Serial.println();
}