Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Servo-control for generator start

Status
Not open for further replies.

Adri67

Junior Member level 2
Joined
Aug 11, 2014
Messages
24
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
267
20180120
I am designing a remote/auto start for 5kVA generator (gen) already fitted with 12V electric start. The gen is fitted with a choke lever which must be "played" progressively from fully closed while cranking, to fully open when full speed (3,000 RPM = 50Hz) is achieved. I have fitted a small RC-type servo (6Vdc / 50Hz / 180 degree = 1...2mS, etc). My sketch contains the "Knob"(Servo) part which works fine with a pot input.
I have added a frequency counter to translate the motor speed which also works well displaying frequency.
My problem is to USE the frequency output (Freq or FREQ) in order to control the servo satisfactority instead of the pot. I cannot get the frequency signal "out". D5 output with present sketch is 0 for 0Hz and 1 for any output above 0Hz.
What am I doing wrong to not achieve an output of 0... 1023 instead of 0...1?

Code:
   //   20180120 - no FREQ output D5

#include <LiquidCrystal595.h>
#include <Servo.h>

Servo myservo;  

int potpin = 0;  // analog pin A0 for pot
int val;         // variable to read the value from the analog pin
 
LiquidCrystal595 lcd (7, 8, 6);

const int ledPin = 13 ;
int ledState = LOW ;
long previousMillisA = 0 ;
long wait = 400 ;

float  FREQ = 0 ;
//  float  Freq = 0 ;

#define MainPeriod 400    // was 1000

long previousMillis = 0 ; 
volatile unsigned long duration = 0 ;
volatile unsigned int pulsecount = 0 ;
volatile unsigned long previousMicros = 0 ;


void setup()  {
  
  pinMode   (ledPin, OUTPUT) ;
  pinMode   (FREQ,   OUTPUT) ;
  myservo.attach  (10);                 // connects the servo to pin 10 
  
  lcd.begin  (20, 4);

  attachInterrupt  (0, myinthandler, RISING) ;  // input D3 
}

void loop() {
  
  val = analogRead (potpin);            // reads the value of the potentiometer (value between 0 and 1023)
  val = map  (val, 0, 1023, 0, 180);     // scale it to use it with the servo (value between 0 and 180)
  myservo.write (val);                  // sets the servo position according to the scaled value
  delay   (15);                           // waits for the servo to get there

   unsigned long currentMillisA = millis();
 
  if  (currentMillisA - previousMillisA > wait) {
    previousMillisA = currentMillisA;   

    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;
    digitalWrite (ledPin, ledState);
  } 
 
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= MainPeriod)
  {
    previousMillis = currentMillis;        
    unsigned long   Aduration = duration;
    unsigned long   Apulsecount = pulsecount;
    duration = 0; 
    pulsecount = 0;
    
    float Freq = 1e6 / float(Aduration);    

    Freq *= Apulsecount;                
    
   FREQ = Freq ;
   if  (isnan (FREQ))  FREQ = 0 ;   // to remove "nan" when near 0
   
   digitalWrite  (5,  FREQ) ;
    
    lcd.setCursor  (2, 0) ;
    lcd.print (Freq) ;             // for testing only - shows "nan"
    lcd.setCursor  (2, 1) ;
    lcd.print  (FREQ) ;             
      }
}
void myinthandler() 
{
  unsigned long currentMicros = micros();
  duration += currentMicros - previousMicros;
  previousMicros = currentMicros;
  pulsecount++;
}
 

Sorry, your diagram is not visible.
Click 'Go Advanced', then 'Manage Attachments'.
Edaboard provides each member with his own area for storing images and other files. You can upload images from your computer, then include them in a post as you compose it.
 

Is it correct to say you want to send pulses 1 mSec long to the servo when the engine is starting, so that it moves the choke closed?
Then the pulses shall be 2 mSec long when the engine reaches 3000 rpm (choke open)?
 

Yes, almost exactly right, Brad.
Of course the servo library takes care of modulating the 1...2mS pulse width on its own, according to the 'pot' 0...5V signal.
In my case I want the opposite, i.e. choke closed (2mS) at begin cranking, ending (at full speed) choke open (1mS). And I will add a bar graph to indicate the actual choke situation during the cycle.

But all this comes after I have found out HOW to convert the frequency to a usable variable.
In other words in line 38 to replace
val = analogRead (potpin) ;
with
val = analogRead (FREQ) ;

This is my problem. When I have sorted that out I will fine tune it (e.g. change the range from 0...50Hz to 15...50Hz for the choke, as necessary).

I have attached my sketch again without the unnecessary led.
Code:
[CODE]       
//   20180120 - no FREQ output D5
//   20180121 - remove led

#include <LiquidCrystal595.h>
#include <Servo.h>

Servo myservo;  

int potpin = 0;  // analog pin A0 for pot
int val;         

LiquidCrystal595 lcd (7, 8, 6);

long wait = 400 ;

float  FREQ = 0 ;

#define MainPeriod 400    // was 1000

long previousMillis = 0 ; 
volatile unsigned long duration = 0 ;
volatile unsigned int pulsecount = 0 ;
volatile unsigned long previousMicros = 0 ;


void setup()  {
  
  pinMode   (FREQ,   OUTPUT) ;
  myservo.attach  (10);                 // connects the servo to pin 10 
  
  lcd.begin  (20, 4);

  attachInterrupt  (0, myinthandler, RISING) ;  // input D3 
}

void loop() {
  
  val = analogRead (potpin);            // reads the value of the potentiometer (value between 0 and 1023)
  val = map  (val, 0, 1023, 0, 180);     // scale it to use it with the servo (value between 0 and 180)
  myservo.write (val);                  // sets the servo position according to the scaled value
  delay   (15);                           // waits for the servo to get there

  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= MainPeriod)
  {
    previousMillis = currentMillis;        
    unsigned long   Aduration = duration;
    unsigned long   Apulsecount = pulsecount;
    duration = 0; 
    pulsecount = 0;
    
    float Freq = 1e6 / float(Aduration);    

    Freq *= Apulsecount;                
    
   FREQ = Freq ;
   if  (isnan (FREQ))  FREQ = 0 ;   // to remove "nan" when near 0
   
   digitalWrite  (5,  FREQ) ;
    
    lcd.setCursor  (2, 0) ;
    lcd.print (Freq) ;             // for testing only - shows "nan"
    lcd.setCursor  (2, 1) ;
    lcd.print  (FREQ) ;             
      }
}
void myinthandler() 
{
  unsigned long currentMicros = micros();
  duration += currentMicros - previousMicros;
  previousMicros = currentMicros;
  pulsecount++;
}
[/CODE]
 

Hi,

If I understand correct then the main problem is the frequency measurement of the generator.

If so: (are you aware that we don't know nothing about the used microcontroller and the schematic)
Then please focus on it and don't care about the servo things.
Frequency measurement should be made with the capture feature of your microcontroller.
There are many threads about how to make a frequency measurement.

Counting pulses won't work satisfactory, because the resolution is low and the measurement time is high.

Klaus
 

It is very inaccurate to determine the frequency by counting pulses because you will get small numbers over reasonable times.

It is better to count the time between two pulses and calculate the frequency (when the frequency is low).
 

val = analogRead (FREQ) ; Doesn't look right.
Try val = FREQ ;

- - - Updated - - -

myservo.attach (10); // connects the servo to pin 10
digitalWrite (5, FREQ) ; How do you Write a float to 1 pin? What are you doing with pin5?

- - - Updated - - -

float FREQ = 0 ;
pinMode (FREQ, OUTPUT) ;
Doesn't this set pin 0 as output?
 

I couldn't make your sketch work so I started over.
It does what you asked for but I think it will open the choke too soon.
You can tweak it to suit your needs.


Code:
/*
Thank you Leifjoha for this simple frequency counter that he left in the comments here:
https://circuitdigest.com/microcontroller-projects/arduino-frequency-counter-circuit
You made one measuring of time and then display the floating number of frequency. 
You will get a more correct measuring as an average of several measuring's. 
I have placed a for .. until loop with counter to 1000 and add up Ttime in variabel 
Tsum and then calculate frequency from Tsum/1000. 
You can also convert this frequency to an integer if you like frekvens=long(frequency+0.5);

I have a better way don't use pulseIn() function because this is an indirect way and 
have many complicated process's , but count the number of transitions from HIGH to LOW 
(or LOW to HIGH) in a second that is frequency.

**Frequency counter - count the number of trasitions from HIGH to LOW in a second.

Modified to operate an RC servo from 0 degrees to 180 degrees on pin 9, 
corresponding to a frequency input of 0 to 4000 Hz on pin 8. 
DNA-Robotics.com

*/
#include <Wire.h>
#include <Servo.h>
Servo myservo;  // create servo object to control a servo

long frekvens;//storing frequency - danish for frequency
long number; // counter for transitions
long time1; // starttime for 1 second in micros()
long time; // measering time in micros()

void setup()
{
pinMode(8,INPUT); //impuls ind p� digital ben nr 8
myservo.attach(9);  // attaches the servo on pin 9 to the servo object
Serial.begin(9600);//initialize the serial
}

void loop()
{
  number=0;
  time1=micros();
  do
  /* loop for one second*/
  {
    if (digitalRead(8)==HIGH)
    {
      do
      {
      /* empty loop waiting for transition*/
      }
    while (digitalRead(8)==HIGH);
    /* now from HIGH to LOW */
    number++;
    }
  time=micros();
  }
while (time<(time1+1000000));
  Serial.print(number);
  Serial.println(" Hz");
  number = map(number, 0, 4000, 0, 180);     // scale it to use it with the servo (value between 0 and 180) 
  myservo.write(number);                  // sets the servo position according to the scaled value 
  delay(15);                           // waits for the servo to get there 

//delay(1000);
}
 

Attachments

  • GenChoke.ino.txt
    2.1 KB · Views: 56
Last edited:

20180126
I did not say I had a problem with measuring frequency. In fact the frequency counter I showed works incredibly well down to about 0.1Hz!
I said I had a problem "using it", i.e. making the servo respond correctly.
I have since fixed that and added the LED which will later disconnect the servo power when the gen reaches 50Hz, making the servo redundant.

// 20180120 - no FREQ output D5
// FREQ to servo tested perfect, even CHOKE inverted
// 20180125 - added LED : off when reaches 50Hz

#include <LiquidCrystal595.h>
#include <Servo.h>

Servo myservo;
const int ledPin = 13 ;
int potpin = 0; // analog pin A0 for pot, not used now
int val;

LiquidCrystal595 lcd (7, 8, 6);

long wait = 400 ;
float FREQ = 0 ;

#define MainPeriod 300 // was 1000

long previousMillis = 0 ;
volatile unsigned long duration = 0 ;
volatile unsigned int pulsecount = 0 ;
volatile unsigned long previousMicros = 0 ;

void setup() {
pinMode (ledPin, OUTPUT) ;
myservo.attach (10); // connects the servo to pin 10

lcd.begin (20, 4);

attachInterrupt (0, myinthandler, RISING) ; // input D3
}

void loop() {

val = map (FREQ, 2, 50, 180, 0); // scale it to use it with the servo (value between 0 and 180)
myservo.write (val); // sets the servo position according to the scaled value
delay (5); // waits for the servo to get there

unsigned long currentMillis = millis();

if (currentMillis - previousMillis >= MainPeriod)
{
previousMillis = currentMillis;
unsigned long Aduration = duration;
unsigned long Apulsecount = pulsecount;
duration = 0;
pulsecount = 0;

float Freq = 1e6 / float(Aduration);

Freq *= Apulsecount;

FREQ = Freq ;
if (isnan (FREQ))
FREQ = 0 ; // to remove "nan" when near 0

lcd.setCursor (2, 0) ;
lcd.print (Freq) ; // for testing only - shows "nan"
lcd.setCursor (2, 1) ;
lcd.print (FREQ) ;
lcd.setCursor (2, 2);

if (FREQ >= 50)
digitalWrite (ledPin, LOW);
else
digitalWrite (ledPin, HIGH);

}
}
void myinthandler()
{
unsigned long currentMicros = micros();
duration += currentMicros - previousMicros;
previousMicros = currentMicros;
pulsecount++;
}
I now have a problem with the bar-graph which I will post later.
Thanks for the help.
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top