Linear wind turbine dumpload brake control

Hello.
Need some help and ideas in my first project.
I have idea to make small wind turbine automated dump load brake , but not like simple way shorting winding ore just with relays nonlinear dump loading.
Idea is in controller set up trigger voltage when the controller starts opening Mosfets to dump load exes energy to other load. But this going on in linear way. Example if trigger voltage 15V and control range be +/- 0.1V. Controller must fast opening or closing Mosfet to drain exes voltage to other source (resistor, water heater,...), and holding trigger voltage.

For this project I thing about some Arduino, voltage sense circuit, small LCD ore led segment display and buttons for trigger voltage setting and voltage reading, and mosfet control board.
I'm think use Arduino nano 3.0, TFT display with ST7735 Drive IC, couple simple buttons.
I'm not sure about voltage sense circuit if simple voltage divider can do. Input voltage will be 0-60V and have to be max precise. And not sure if Arduino can directly control big mosfets.

So I need help with precise voltage sens and mosfet driving circuits and some software basics.

You need a circuit that converts that input voltage range into corresponding MOSFET gate voltage (full OFF/ON). This circuit will control the current through the MOSFET and consequently the energy spent in the MOSFET (heat). A fixed resistor load in series with the MOSFET will help to distribute the heat between resistor and MOSFET. Depending on the heat a 12V fan can be added as both a load and cooling device for the bulk load.

Yes that's what I'm looking for. I think it's can be done in analog way. But try to make digital variant, because I want option to setting trigger voltage and see on display input voltage set trigger voltage and in the future more functions / parameters.

I have some basic code for my project, but I can't get exactly what I need in analog Out, maybe someone can help.

float outputValue = map( (inputVoltage - setVoltage) , -40, 40, 0, 255 );     
  analogWrite(analogOutPin, outputValue);

InputVoltage variables from 0.00 - 50.00
setVoltage = 12.00

If I understand correctly digital PWM out is from 0 to 255 digital and 0 - 5V analog.
I need that it's start output from 2-5V and only if InputVotage > setVoltage. And output rise exponential.

Did you read the documentation on the "map" function?
The map() function uses integer math so will not generate fractions, when the math might indicate that it should do so. Fractional remainders are truncated, and are not rounded or averaged..

There's a mapf() function for floating point.

When using map(), it is important to know that it will happily extrapolate for input values outside the input domain, this is why it is often used with constrain(), for which casual searching turns up no corresponding floating point function.

But constraining either type is a few simple if statements.

For that matter, mapping either type is simple enough mathematics.

a7

Hello,
slowly I'm getting some wear with my project, but I have small problem with stable input voltage reading. Right now input Voltage is unstable and jumping around 0.02V. Even if power supply and multi meter dose not.
Maybe there is some options to improve my code?

float vIN = 0.00;
float R1 = 15850.0;
float R2 = 1194.0;
float Vdata = 0;


  for(int i = 0; i < 180; i++){
    Vdata = Vdata + analogRead(voltageSensePin);
    delay(1);
  }
 Vdata = Vdata / 180;
 vIN = ((Vdata*5.0) / 1024.0 / (R2/(R1+R2)));

Did you read the documentation on the "map" function?
The map() function uses integer math so will not generate fractions, when the math might indicate that it should do so. Fractional remainders are truncated, and are not rounded or averaged..

True
Created a fast float mapping just because - GitHub - RobTillaart/FastMap: Arduino library for Fast mapping and constraining
includes constrained mapping too ==> you do not always want to extrapolate outside the range.
It caches / calculates as much as possible in front.

If I understand correctly digital PWM out is from 0 to 255 digital and 0 - 5V analog.
I need that it's start output from 2-5V and only if InputVotage > setVoltage. And output rise exponential.

Exponential implies non-linearity, you might find this one useful

Why analog.Read pins, jumping +/- 20 -30 bits if input voltage is stable?

That could be noise, quantitation error or several other things. Your volt meter is dampened so it probably will not show that. Posting an annotated schematic showing exactly how this is wired will help solve the problem. Note any wires over 10"/25cm.

In AnalogIN(A0) simplest voltage divider with 2 resistors. R1=15.85K and R2=1.18K. For 0 -- +50V.

I observe if processor have some hard calculations for some analog out processes then this input jumping +/- gets worse.

First +/- working prototype..

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <EEPROM.h>
#include <math.h>
#include <averager.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET    -1  
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

const int voltageSensePin = A1;   // Voltage sense pin
const int upButtonPin = 2;        // Pin number for the "UP" button
const int downButtonPin = 3;      // Pin number for the "DOWN" button
const int analogOutPin = 9;       // Pin number for analog output
const int setButtonHoldTime = 4000;  // Time to hold the button for entering setting mode (4 seconds)

float setVoltage = 10.00;         // Set voltage in setting mode
bool settingMode = false;         // Flag to indicate if in setting mode
unsigned long lastButtonPressTime = 0;  // Variable to store the time of the last button press
unsigned long readingSum = 0;

float alpha = 0.05;
averager<float> average;

float vIN = 0.00;
float R1 = 15850.0;
float R2 = 1174.0;
float Vdata = 0;
float vRaw=0;
int Vtest = 0;


void setup() {
  Serial.begin(9600);
  pinMode(upButtonPin, INPUT_PULLUP);    // Set the "UP" button pin as an input with pull-up resistor
  pinMode(downButtonPin, INPUT_PULLUP);  // Set the "DOWN" button pin as an input with pull-up resistor
  pinMode(analogOutPin, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.setTextSize(2);
  display.display();  // Clear the display buffer
  delay(2000);        // Pause for 2 seconds
  display.clearDisplay(); // Clear the display
  average.setExponentialMovingAverageAlpha(alpha);
  int address = 0;
  
  EEPROM.get(address, setVoltage);
  setVoltage = constrain(setVoltage, 10.00, 50.00);
}

void loop() {
 
    for(int i = 0; i < 100; i++){
    Vdata = Vdata + analogRead(voltageSensePin);
    delayMicroseconds(20);
    }
 Vdata = Vdata / 100;
 vRaw = ((Vdata*5.0) / 1024.0 / (R2/(R1+R2)));
  uint16_t new_value = analogRead(voltageSensePin);
    average.updateExponentialMovingAverage(new_value);


 vIN = ((average.getExponentialMovingAverage()*5.0) / 1024.0 / (R2/(R1+R2)));

  // Check if in setting mode
  if (settingMode) {
    handleSettingMode();
  } else {
    
    updateDisplay("IN", vIN);

    // Read the state of the "UP" and "DOWN" buttons
    int upButtonState = digitalRead(upButtonPin);
    int downButtonState = digitalRead(downButtonPin);

    // Check if either button is pressed
    if (upButtonState == LOW || downButtonState == LOW) {
      lastButtonPressTime = millis();
    }

    // Check if the "UP" button is pressed and enter setting mode
    if (upButtonState == LOW && downButtonState == HIGH) {
      enterSettingMode();
    }

    // Check if the "DOWN" button is pressed and enter setting mode
    if (downButtonState == LOW && upButtonState == HIGH) {
      
      enterSettingMode();
    }
  }

  adjustAnalogOutput();

  // Check for inactivity to save set voltage to EEPROM
  if (millis() - lastButtonPressTime > setButtonHoldTime && settingMode) {
    saveSetVoltageToEEPROM();
    settingMode = false; 
  }
}

void enterSettingMode() {
  settingMode = true;
  lastButtonPressTime = millis();  // Update the time of the last button press
  display.clearDisplay(); // Clear the display
  int address = 0;
  EEPROM.get(address, setVoltage);

  // Check if the read value is a valid number
  if (isnan(setVoltage) || setVoltage < 10.00 || setVoltage > 50.00) {
    // If not valid, set a default value
    setVoltage = 10.00;
  }
  
  updateDisplay("Set", setVoltage);  // Update the display with set voltage
  delay(1000);
}

void handleSettingMode() {
  // Read the state of the "UP" and "DOWN" buttons
  int upButtonState = digitalRead(upButtonPin);
  int downButtonState = digitalRead(downButtonPin);

  // Check if the "UP" button is pressed and adjust set voltage
  if (upButtonState == LOW && downButtonState == HIGH) {
    setVoltage += 0.05;
    delay(100);  // Debounce delay
    lastButtonPressTime = millis();  // Update the time of the last button press
  }

  if (downButtonState == LOW && upButtonState == HIGH) {
    setVoltage -= 0.05;
    delay(100);  // Debounce delay
    lastButtonPressTime = millis();  // Update the time of the last button press
  }

  setVoltage = constrain(setVoltage, 10.00, 50.00);
  updateDisplay("Set", setVoltage);
}

void updateDisplay(String mode, float value) {
  display.clearDisplay();
  display.setTextSize(2); // Clear the display
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.print(mode + ":");
  display.print(value, 2); // Display value with two decimal places
  display.display();
}

void adjustAnalogOutput() {

float deltaV=(vIN - setVoltage+0.1)*1000;
Vtest = map(deltaV,0,300,0,255);
Vtest = constrain(Vtest,0,255);
analogWrite(analogOutPin, Vtest);
if(Vtest>0){
  digitalWrite(LED_BUILTIN, HIGH);
}
else {digitalWrite(LED_BUILTIN, LOW);}

if((vRaw -setVoltage) > 0.5){
  analogWrite(analogOutPin,255);
}
}
void saveSetVoltageToEEPROM() {
  int address = 0;
  EEPROM.put(address, setVoltage);
}

you need to check where you can "help" your floating point operations.
Float divisions are the worst performant. However often can be replaced with multiplication.
A blocking loop during the analogReads does also eat CPU cycles.

Look at this snippet

void loop()
{
  //  do you need 100?  what happens when going to 50, 20, 10 or even 1?
  for (int i = 0; i < 100; i++) {    
    Vdata = Vdata + analogRead(voltageSensePin);
    delayMicroseconds(20);  // <<<<<<<<<<<  sums up to 2 milliseconds per loop
  }
 Vdata = Vdata *  0.01;  // replace expensive division
 vRaw = Vdata * (5.0 / 1024.0 / (R2/(R1+R2)));
 //  As  (5.0 / 1024.0 ) * (R1+R2) / R1;  is a constant, calculate it compile time

The latter could be a global var that needs to be calculated once.

const float DATA2RAW = 5.0 /1024.0 / (R2/(R1+R2));

Ok thanks it's looks better. grate optimization.

Sorry for incompetence my Arduino skills are 1 week.. :sweat_smile:

Does it help with precision, if I measure VCC with 1.1V build in reference voltage. and then use this voltage to other measurements that use VCC as reference?
Or better get stable VCC 5.00v and forget.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.