BH1750FVI Based Dual Axis Solar Tracker

by MD Jahid Hassan in Circuits > Arduino

1335 Views, 9 Favorites, 0 Comments

BH1750FVI Based Dual Axis Solar Tracker

Capture.JPG

Solar power converts energy from sunlight into electricity, either directly using photovoltaics (PV) or indirectly using concentrated solar power. Here we will make a solar tracker to increase the solar energy-taking process more efficiently.

Working Principle:

A dual-axis solar panel works by continuously tracking the movement of the sun in two axes, allowing the solar panel to always face the sun directly and maximize the amount of sunlight it receives. This tracking system enables the solar panel to capture the maximum available solar energy throughout the day.

The two axes in a dual-axis solar panel system are:

  1. Azimuth Axis: The azimuth axis allows the solar panel to rotate horizontally or azimuthally. It enables the panel to track the sun's movement from east to west along the horizon. This axis ensures that the solar panel is always facing the sun as it moves across the sky during the day.
  2. Elevation Axis: The elevation axis allows the solar panel to tilt or elevate vertically. It enables the panel to track the sun's position in relation to its elevation angle. The elevation angle varies throughout the day and depends on factors such as the latitude of the installation location and the season. By adjusting the tilt angle, the solar panel can optimize the angle of incidence between the sun's rays and the solar panel's surface, maximizing the energy captured.

To track the sun's movement accurately, a dual-axis solar panel system typically utilizes sensors, such as light-dependent resistors (LDRs) or BH1750FVI digital Ambient Light Sensors, to detect the intensity of sunlight. These sensors provide feedback to the tracking system, which controls the movement of the azimuth and elevation axes to orient the solar panel toward the sun.

The tracking system can be implemented using various techniques, such as using microcontrollers like Arduino or dedicated solar tracking controllers. The control system calculates the desired position of the solar panel based on the sun's position, as determined by the sensor readings, and commands the motors or actuators connected to the azimuth and elevation axes to adjust the panel's orientation accordingly.

By continuously tracking the sun's movement on both axes, a dual-axis solar panel system can significantly increase the solar panel's energy output compared to fixed-tilt or single-axis tracking systems. This increased efficiency makes dual-axis solar panels an attractive option for applications where maximizing solar energy production is essential, such as in solar power plants or off-grid solar systems.

Our Goal: Inexpensive, "smart" computer-controlled, dual-axis tracker for school and home use.

Supplies

Uno.jpg
mg996.jpg
bread board.jpg
bh1750 sensor.png
Adapter Power Supply - 5V DC 2A.jpg
CD4051.jpg
pvc board.jpg
jumpers wire.jpg
solar panel.jpg

Materials we needed for this project:

  • Arduino UNO
  • Servo motor-mg996
  • Solar panel
  • Breadboard
  • BH1750 sensor
  • Jumpers wire
  • 5v power supply
  • PVC board
  • Super glue
  • Anti cutter

BH1750 Sensor

BH1750-Light-Sensor-Pinout.png

The BH1750 is a digital light sensor module that measures the intensity of ambient light. It uses the I2C communication protocol, making it easy to interface with microcontrollers like Arduino, Raspberry Pi, and other platforms. The BH1750 sensor is popular due to its accuracy, simplicity of use, and low power consumption.


Key features of the BH1750 sensor include:


1. Light Measurement Range: The BH1750 sensor can measure light intensity in a wide range, typically from 1 lux to 65,535 lux. It provides accurate readings even in low-light conditions.


2. Digital Output: The sensor provides a digital output, making it straightforward to read the light intensity values. It utilizes the I2C interface, allowing for easy integration into projects using I2C communication.


3. High Sensitivity: The BH1750 sensor has high sensitivity, enabling it to detect even small changes in light intensity. This makes it suitable for applications requiring precise light measurements.


4. Measurement Modes: The sensor supports different measurement modes, including continuous and one-time measurements. In continuous mode, the sensor continuously updates the light intensity value, while in one-time mode, it provides a single measurement and then enters power-saving mode.


5. Accuracy and Resolution: The BH1750 sensor offers good accuracy and resolution for light measurements. It typically has a resolution of 1 lux, allowing for precise readings.


6. Integration Flexibility: The sensor can be easily integrated into various projects and applications. It requires minimal external components and operates at a wide range of supply voltages.


The BH1750 sensor finds applications in a range of fields, including:


- Smart lighting systems: They can be used to adjust the brightness of indoor or outdoor lighting based on ambient light conditions.

- Energy management systems: The sensor can optimize energy usage by controlling artificial lighting based on the availability of natural light.

- Automatic brightness adjustment in displays: It can be employed in devices like smartphones, laptops, or digital signage to adjust screen brightness based on ambient light levels.

- Weather stations: The sensor can measure ambient light conditions as part of weather monitoring systems.

- Robotics and automation: It can be utilized in robots and automation systems to detect light conditions and trigger appropriate actions.


Overall, the BH1750 sensor is a versatile and reliable solution for measuring light intensity in various applications, offering convenience and accuracy in a compact package.


The specifications of the BH1750 sensor:

  1. Measurement Range:
  • Measurement Modes: Two selectable measurement modes:
  • High-resolution mode: 0 lux to 65,535 lux
  • Low-resolution mode: 0 lux to 54612 lux
  1. Sensitivity:
  • High sensitivity allows the detection of small changes in light intensity.
  1. Accuracy and Resolution:
  • Resolution: 1 lux (both high and low-resolution modes)
  • Accuracy: Typically ±20% under normal operating conditions
  1. Operating Voltage:
  • Supply Voltage Range: 2.4V to 3.6V
  1. Interface:
  • Communication Protocol: I2C (Inter-Integrated Circuit)
  • I2C Address: The BH1750 sensor has a fixed I2C address of 0x23 or 0x5C, depending on the device variant.
  1. Power Consumption:
  • Low power consumption for efficient operation, especially in battery-powered applications.
  • Power-saving mode is available to further reduce power consumption.
  1. Operating Temperature Range:
  • -40°C to +85°C
  1. Package:
  • The BH1750 sensor is available in various package options, including surface-mount packages.
  1. Additional Features:
  • Supports continuous and one-time measurements.
  • Integrated 16-bit analog-to-digital converter (ADC) for accurate light intensity readings.


Circuit Diagram

Schematic_bh1750based DAST_2023-06-04.png
IMG_20230604_013259.jpg

In this circuit diagram, the solar panel is connected to two servo motors. One servo motor controls the azimuth axis (east-west movement), and the other servo motor controls the elevation axis (north-south movement) of the solar panel.

The BH1750 light sensors are positioned in the east, west, north, and south directions. These sensors detect the light intensity and provide feedback to the Arduino board. The Arduino board processes the sensor data and calculates the necessary adjustments for the servo motors to keep the solar panel aligned with the sun's position.

Source Code/Program

The code starts by including the necessary libraries: Wire.h for I2C communication and Servo.h for controlling the servo motors.

Constant definitions are provided for different power modes, measurement modes, and I2C addresses specific to the BH1750 sensor.

Pin assignments for the servo motors and control pins are defined. These pins will be used to connect the servo motors and control signals.

The setup() function is executed once at the beginning. It initializes the Wire library, sets the pin modes for the control pins, attaches the servo motors to their respective pins, and sets their initial angles.

The loop() function is the main program loop that executes repeatedly.

Inside the loop(), the enable switch is enabled by setting the s_en pin low. This allows the multiplexer (if used) to be enabled.

The loop() then iterates through the four LDR sensors using the readMux() function. This function selects the appropriate MUX channel by setting the control pins accordingly.

The init_BH1750() function is called to initialize the BH1750 sensor with the specified I2C address and measurement mode.

The RawData_BH1750() function is called to read the raw data from the BH1750 sensor. The data is stored in the RawData variable.

The raw sensor data is then divided by 1.2 and stored in the SensorValue array. This is done to convert the raw data to a meaningful sensor value.

The code then prints the sensor values via the Serial monitor for debugging purposes. The values represent the light intensity measured by each sensor.

The code performs calculations based on the sensor values to determine the adjustments needed for the servo motors. Specifically, it calculates the average values for the top, bottom, left, and right sensors, as well as the differences in light intensity between different sensor pairs.

Based on the calculated differences, the code adjusts the angles of the servo motors. If the difference in light intensity exceeds a certain tolerance, the corresponding servo motor angle is incremented or decremented accordingly.

The servo motors' new angles are written to the servo objects (horizontal and vertical) using the write() function.

A delay of dtime milliseconds is added to control the speed of servo movements.

The loop() repeats, and the process continues indefinitely.

Please note that this code assumes the use of a multiplexer (MUX) to connect multiple BH1750 sensors to a single Arduino board. The readMux() function is responsible for selecting the appropriate MUX channel to read sensor values from.

/*
 MODIFIED BY MD JAHID HASSAN
 ME,CUET
 BANGLADESH
*/
#include <Wire.h>
#include <Servo.h>
// Power
#define BH1750_POWER_DOWN 0x00  // No active state
#define BH1750_POWER_ON 0x01    // Waiting for measurement command
#define BH1750_RESET 0x07       // Reset data register value - not accepted in POWER_DOWN mode


// Measurement Mode
#define CONTINUOUS_HIGH_RES_MODE 0x10    // Measurement at 1 lux resolution. Measurement time is approx 120ms
#define CONTINUOUS_HIGH_RES_MODE_2 0x11  // Measurement at 0.5 lux resolution. Measurement time is approx 120ms
#define CONTINUOUS_LOW_RES_MODE 0x13     // Measurement at 4 lux resolution. Measurement time is approx 16ms
#define ONE_TIME_HIGH_RES_MODE 0x20      // Measurement at 1 lux resolution. Measurement time is approx 120ms
#define ONE_TIME_HIGH_RES_MODE_2 0x21    // Measurement at 0.5 lux resolution. Measurement time is approx 120ms
#define ONE_TIME_LOW_RES_MODE 0x23       // Measurement at 4 lux resolution. Measurement time is approx 16ms


// I2C Address
#define BH1750_1_ADDRESS 0x23  // Sensor 1 connected to GND
#define BH1750_2_ADDRESS 0x5C  // Sensor 2 connected to VCC

// Definition of Variable
int16_t s_en = 4;
int16_t A = 5;
int16_t B = 6;
int16_t C = 7;


int16_t RawData;
int16_t SensorValue[4];


//------------servo int


// 180 horizontal MAX
Servo horizontal;  // horizontal servo
int servoh = 90;   // 90;     // stand horizontal servo


int servohLimitHigh = 180;
int servohLimitLow = 65;


// 65 degrees MAX
Servo vertical;   // vertical servo
int servov = 90;  //   90;     // stand vertical servo


int servovLimitHigh = 120;
int servovLimitLow = 15;

void setup() {
  Wire.begin();
  Serial.begin(115200);  // Baud Rate


  pinMode(s_en, OUTPUT);
  pinMode(A, OUTPUT);
  pinMode(B, OUTPUT);
  pinMode(C, OUTPUT);


  digitalWrite(s_en, HIGH);
  digitalWrite(A, HIGH);
  digitalWrite(B, HIGH);
  digitalWrite(C, HIGH);


  horizontal.attach(10);
  vertical.attach(9);
  horizontal.write(180);
  vertical.write(45);
  delay(3000);
}


void loop() {


  digitalWrite(s_en, LOW);  // Enabling the Enable Switch


  for (int i = 0; i < 4; i++) {
    readMux(i);


    init_BH1750(BH1750_1_ADDRESS, CONTINUOUS_HIGH_RES_MODE);
    delay(120);
    RawData_BH1750(BH1750_1_ADDRESS);
    SensorValue[i] = RawData / 1.2;
    // delay(20);
  }


  Serial.print("Sensor_1 = ");
  Serial.print(SensorValue[0]);
  Serial.print(" | Sensor_2 = ");
  Serial.print(SensorValue[1]);
  Serial.print(" | Sensor_3 = ");
  Serial.print(SensorValue[2]);
  Serial.print(" | Sensor_4 = ");
  Serial.println(SensorValue[3]);


  int lt = SensorValue[2];  // top left
  int rt = SensorValue[3];  // top right
  int ld = SensorValue[1];  // down left
  int rd = SensorValue[0]; // down rigt


  int dtime = 10;
  int tol = 50;


  int avt = (lt + rt) / 2;  // average value top
  int avd = (ld + rd) / 2;  // average value down
  int avl = (lt + ld) / 2;  // average value left
  int avr = (rt + rd) / 2;  // average value right


  int dvert = avt - avd;   // check the diffirence of up and down
  int dhoriz = avl - avr;  // check the diffirence og left and rigt

  Serial.print(avt);
  Serial.print(" ");
  Serial.print(avd);
  Serial.print(" ");
  Serial.print(avl);
  Serial.print(" ");
  Serial.print(avr);
  Serial.print("   ");
  Serial.print(dtime);
  Serial.print("   ");
  Serial.print(tol);
  Serial.println(" ");

  if (-1 * tol > dvert || dvert > tol)  // check if the diffirence is in the tolerance else change vertical angle
  {
    if (avt > avd) {
      servov = ++servov;
      if (servov > servovLimitHigh) {
        servov = servovLimitHigh;
      }
    } else if (avt < avd) {
      servov = --servov;
      if (servov < servovLimitLow) {
        servov = servovLimitLow;
      }
    }
    vertical.write(servov);
  }


  if (-1 * tol > dhoriz || dhoriz > tol)  // check if the diffirence is in the tolerance else change horizontal angle
  {
    if (avl > avr) {
      servoh = --servoh;
      if (servoh < servohLimitLow) {
        servoh = servohLimitLow;
      }
    } else if (avl < avr) {
      servoh = ++servoh;
      if (servoh > servohLimitHigh) {
        servoh = servohLimitHigh;
      }
    } else if (avl = avr) {
      // nothing
    }
    horizontal.write(servoh);
  }
   delay(dtime);
}


void init_BH1750(int ADDRESS, int MODE) {
  //BH1750 Initializing & Reset
  Wire.beginTransmission(ADDRESS);
  Wire.write(MODE);  // PWR_MGMT_1 register
  Wire.endTransmission(true);
}


void RawData_BH1750(int ADDRESS) {
  Wire.beginTransmission(ADDRESS);
  Wire.requestFrom(ADDRESS, 2, true);        // request a total of 2 registers
  RawData = Wire.read() << 8 | Wire.read();  // Read Raw Data of BH1750
  Wire.endTransmission(true);
}


int readMux(int channel) {
  int controlPin[] = { A, B, C };
  int muxChannel[8][3] = {
    { 0, 0, 0 },  //channel 0
    { 1, 0, 0 },  //channel 1
    { 0, 1, 0 },  //channel 2
    { 1, 1, 0 },  //channel 3
    // {0,0,1}, //channel 4
    // {1,0,1}, //channel 5
    // {0,1,1}, //channel 6
    // {1,1,1}, //channel 7  //loop through the 3 Signals
  };
  for (int i = 0; i < 3; i++) {  // Connecting MUX Channel
    digitalWrite(controlPin[i], muxChannel[channel][i]);
  }
}



Structure of the Dual Axis Solar Tracker

IMG_20230603_232623.jpg
IMG_20230604_013248.jpg

Here I will attach a 3d model in the future.

Final Working Video

DAST