Jump to content
ELFORUM - Forumul electronistilor

Mica automatizare


Mihai85

Recommended Posts

Buna seara.

Am incropit un mic montaj cu Arduino Pro Micro (Leonardo) pentru a testa niste motoare BLDC de putere.

Functii:

-citire 2 temperaturi cu termistori ntc de 100K

-citire rpm cu senzor hall si magnet

-citire tensiune baterie(auxiliara 12v)

-comanda pwm pentru variator motor(ESC) de tip RC(radio comanda) cu intervalul intre 1 si 2 ms 

-afisare procentaj acceleratie de la potentiometru.

 

      Aparent functioneaza totul mai putin partea de comanda ESC, in sensul ca atunci cand motorul ar trebui sa fie oprit la un interval aleator de secunde (cateodata si la o secunda) motorul porneste pentru o fractiune de secunda. 

       O a doua problema este ca raspunde cu un mic delay dupa ce am invartit potentiometrul.

  Problema apare pentru ca in bucla sunt si celelalte instructiuni : citire temperaturi, turatie si tensiune baterie. 

   Daca las in program doar partea de comanda ESC functioneaza corect fara acele impulsuri si intarzieri.

   Se poate rezolva cumva aceasta problema, sau trebuie o placa separata?

Multumesc!

 

Pun o filmare https://files.fm/u/x7czw9mrv

https://files.fm/u/rhka2egez#/view/c7zka44t5

 

#include <LiquidCrystal_I2C.h>
#include <Servo.h>

Servo ESC;     // create servo object to control the ESC

int Thermistor1Pin = 3;
int Thermistor2Pin = 2;

int Vo;
float R1 = 10000;
float logR2, R2, T, Tc, Tf;
float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07;

// variables for input pin for measure Ubat
  int analogInput = 1;
  float vout = 0.0;
  float vin = 0.0;
  float R3 = 33000.0;    // !! resistance of R3 !!
  float R4 = 10000.0;     // !! resistance of R4 !!

// variable to store the value 
  int value = 0;

  int Pin = 10; // Hall sensor at pin 10

  int potValue;  // value from the analog pin potentiometer
  int percentage;

  
unsigned long rpm = 0;
unsigned long duration;


LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup() {
  lcd.init();
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.backlight();      //  backlight on
  
  pinMode(Pin, INPUT); //Sets sensor as input

    // Attach the ESC on pin 9
  ESC.attach(9,1000,2000); // (pin, min pulse width, max pulse width in microseconds) 
}

void loop() {

  Vo = analogRead(Thermistor1Pin);
  R2 = R1 * (1023.0 / (float)Vo - 1.0);
  logR2 = log(R2);
  T = (1.0 / (c1 + c2 * logR2 + c3 * logR2 * logR2 * logR2));
  Tc = T - 273.15;
  Tf = (Tc * 9.0) / 5.0 + 32.0;

 
 lcd.setCursor(0, 0);
  lcd.print("Tm");
  if (Tc < -50)
  lcd.print("--");
  if (Tc > -50)  
  lcd.print((int)Tc);
  lcd.print("C ");
  delay(500);

  
  Vo = analogRead(Thermistor2Pin);
  R2 = R1 * (1023.0 / (float)Vo - 1.0);
  logR2 = log(R2);
  T = (1.0 / (c1 + c2 * logR2 + c3 * logR2 * logR2 * logR2));
  Tc = T - 273.15;
  Tf = (Tc * 9.0) / 5.0 + 32.0;

  lcd.setCursor(0, 1);
  lcd.print("Tc");
  if (Tc < -50)
     lcd.print("--");
   if (Tc > -50)  
   lcd.print((int)Tc);
   lcd.print("C ");
  delay(500);

  

{
  // read U Batt
  value = analogRead(analogInput);

  vout = (value * 5.0) / 1024.0;
  vin = vout / (R4/(R3+R4)); 
 if (vin<0.09) {
   vin=0.0;//statement to quash undesired reading !
}  
   
  
    lcd.setCursor(12, 1);
    lcd.print(vin);
    lcd.setCursor(12, 0);
    lcd.print("Ubat");
    
}

//Read hall sensor
{
  duration = pulseIn(Pin, FALLING, 500000); //times the amount of microseconds the motor is not timing IR, Times out after 100000 uS. Raise the timeout for slower RPM readings. .5 second
  rpm = 60000.0/duration*1000; 
 

  lcd.setCursor(6, 0);
  lcd.print("R");

   if(rpm < 1000)      
        lcd.print(" ");
if(rpm < 100)
        lcd.print(" ");
if(rpm < 10)
        lcd.print(" ");
lcd.print(rpm);
 
 }

 {
  potValue = analogRead(A0);   // reads the value of the potentiometer (value between 0 and 1023)
  potValue = map(potValue, 0, 1023, 0, 180);   // scale it to use it with the servo library (value between 0 and 180)
  ESC.write(potValue);    // Send the signal to the ESC

  lcd.setCursor(6, 1);
  lcd.print("A");
  percentage = map(potValue, 0, 180, 0, 100);
  lcd.print(percentage);
  lcd.print("% ");
}




}

 

Edited by Mihai85
Link to comment
  • Replies 18
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Posted Images

In program ai doua intarzieri de 500ms, iar a treia intarziere(variabila in functie de turatia motorului) este cauzata de folosirea functiei pulseIn care blocheza executia programului atunci cand asteapta ca semnalaul sa treaca din starea HIGH in LOW.

Evita sa folosesti intarzieri, evita sa printezi de mai multe ori caractere care trebuie afisate permanent, foloseste intreruperi.

lcd.print("Tm");
lcd.print("C ");
lcd.print("Tc");
lcd.print("Ubat");

Instructiunile de mai sus trebuie folosite in zona de initializare.

Edited by Elison
Link to comment

Nu prea pricep rolul acoladelor aici (nu sunt rutine sau functii):

{
    // read U Batt
    value = analogRead(analogInput);

    vout = (value * 5.0) / 1024.0;
    vin = vout / (R4 / (R3 + R4));
    if (vin < 0.09) {
      vin = 0.0; //statement to quash undesired reading !
    }


    lcd.setCursor(12, 1);
    lcd.print(vin);
    lcd.setCursor(12, 0);
    lcd.print("Ubat");

  }

 si aici:

 {
    duration = pulseIn(Pin, FALLING, 500000); //times the amount of microseconds the motor is not timing IR, Times out after 100000 uS. Raise the timeout for slower RPM readings. .5 second
    rpm = 60000.0 / duration * 1000;


    lcd.setCursor(6, 0);
    lcd.print("R");

    if (rpm < 1000)
      lcd.print(" ");
    if (rpm < 100)
      lcd.print(" ");
    if (rpm < 10)
      lcd.print(" ");
    lcd.print(rpm);

  }

  {
    potValue = analogRead(A0);   // reads the value of the potentiometer (value between 0 and 1023)
    potValue = map(potValue, 0, 1023, 0, 180);   // scale it to use it with the servo library (value between 0 and 180)
    ESC.write(potValue);    // Send the signal to the ESC

    lcd.setCursor(6, 1);
    lcd.print("A");
    percentage = map(potValue, 0, 180, 0, 100);
    lcd.print(percentage);
    lcd.print("% ");
  }

 

Link to comment

Multumesc pentru raspuns.

Da, pot muta  caracterele afisate permanent. 

Am incercat si fara cele 2 delay-uri de 500ms dar problema persista.

Problema ramane cu intarzierea data de functia pulseIn.

Oare pot aplica o intrerupere pe pin-ul folosit de senzorul hall? Pinul la care este legat actual (10) vad ca nu suporta intreruperi. Deci ar trebui mutat pe pin 0 sau 1 (RX, TX) pt ca 2 si 3 (SDA, SCL) sunt ocupate pt display.

 

LE: @nico_2010 ,asa e, le-am curatat.   Daca aveti vreo solutie la problema sunt deschis sa incerc.

pro micro.jpg

Edited by Mihai85
Link to comment

Din cate vad, poti incerca sa folosesti INT.6 in locul celorlalte intreruperi.

Poti sa testezi varianta cu intrerupere (cu modificarile pe care trebuie sa le faci conform schitei initiale) astfel:

 

volatile int16_t pwm = 0; //pwm value
volatile int16_t trig = 0; //timer value
#define pin 7 //pin the interrupt is attached to

void intHandler() //function to call on interrupt
{
    if(digitalRead(pin)) //if the pin is HIGH, note the time
  {
    trig = micros();
  }
  else
  {
    pwm = micros()-trig; //if it is low, end the time
  }
}

void setup(){
  pinMode(pin, INPUT); //set the pin to input
  attachInterrupt(pin,intHandler,CHANGE); //attach the interrupt function "intHandler" to "pin" whenever the state changes
  Serial.begin(9600); //begin serial comms
}

void loop()
{

  Serial.print("PWM = ");   
  Serial.println(pwm);
}

 Si vezi daca este suficient de rapida pentru nevoile tale

Link to comment
Acum 3 minute, Mihai85 a spus:

Intreruperea imi sugerati sa o folosesc pentru citirea turatiei sau comanda ESC. Comanda ESC nu ar trebui sa fie intrerupta banuiesc. Am vazut scris ''pwm'' in codul de mai sus.

 

Nu stiu la ce folosesti senzorul Hall, presupun ca la citirea turatiei?

Variabila "pwm" din exemplul postat reprezinta durata impulsului, nu altceva!

Exemplul este dat pentru inlocuirea "PulseIn".

Link to comment

Da ,este pentru citirea turatiei. Incerc si revin . Multumesc.

 

LE: Am introdus in schita cod-ul de mai sus. Asa ar trebui sa arate? 

 

#include <LiquidCrystal_I2C.h>
#include <Servo.h>



byte servoPin = 9; // signal pin for the ESC.
byte potentiometerPin = A0; // analog input pin for the potentiometer.
Servo servo;

int Thermistor1Pin = 3;
int Thermistor2Pin = 2;

int Vo;
float R1 = 10000;
float logR2, R2, T, Tc, Tf;
float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07;

// variables for input pin for measure Ubat
  int analogInput = 1;
  float vout = 0.0;
  float vin = 0.0;
  float R3 = 33000.0;    // !! resistance of R1 !!
  float R4 = 10000.0;     // !! resistance of R2 !!

// variable to store the value 
  int value = 0;

  int percentage;

  //Pin = 10; // Hall sensor at pin 10

  volatile int16_t pwm = 0; //pwm value
  volatile int16_t trig = 0; //timer value
  #define pin 7 //pin the interrupt is attached to

void intHandler() //function to call on interrupt
{
    if(digitalRead(pin)) //if the pin is HIGH, note the time
  {
    trig = micros();
  }
  else
  {
    pwm = micros()-trig; //if it is low, end the time
  }
}


 

  
//unsigned long rpm = 0;
//unsigned long duration;


LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup() {
  lcd.init();
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.backlight();      // Make sure backlight is on
   
  servo.attach(servoPin);

  pinMode(pin, INPUT); //set the pin to input
  attachInterrupt(pin,intHandler,CHANGE); //attach the interrupt function "intHandler" to "pin" whenever the state changes
  Serial.begin(9600); //begin serial comms
}

void loop() {

  Vo = analogRead(Thermistor1Pin);
  R2 = R1 * (1023.0 / (float)Vo - 1.0);
  logR2 = log(R2);
  T = (1.0 / (c1 + c2 * logR2 + c3 * logR2 * logR2 * logR2));
  Tc = T - 273.15;
  Tf = (Tc * 9.0) / 5.0 + 32.0;

 
 lcd.setCursor(0, 0);
  lcd.print("Tm");
  if (Tc < -50)
  lcd.print("--");
  if (Tc > -50)  
  lcd.print((int)Tc);
  lcd.print("C ");
  //delay(500);
  

  
  Vo = analogRead(Thermistor2Pin);
  R2 = R1 * (1023.0 / (float)Vo - 1.0);
  logR2 = log(R2);
  T = (1.0 / (c1 + c2 * logR2 + c3 * logR2 * logR2 * logR2));
  Tc = T - 273.15;
  Tf = (Tc * 9.0) / 5.0 + 32.0;

  lcd.setCursor(0, 1);
  lcd.print("Tc");
  if (Tc < -50)
     lcd.print("--");
   if (Tc > -50)  
   lcd.print((int)Tc);
   lcd.print("C ");
  // delay(500);
  
  
  // read U Batt
  value = analogRead(analogInput);

  vout = (value * 5.0) / 1024.0;
  vin = vout / (R4/(R3+R4)); 
 if (vin<0.09) 
   vin=0.0;//statement to quash undesired reading !
 
   
    lcd.setCursor(12, 1);
    lcd.print(vin);
    lcd.setCursor(12, 0);
    lcd.print("Ubat");
  
    
  //Hall sensor

  //duration = pulseIn(Pin, FALLING, 500000); //times the amount of microseconds the motor is not timing IR, Times out after 100000 uS. Raise the timeout for slower RPM readings. .5 second
 // rpm = 60000.0/duration*1000; //See above
 

  lcd.setCursor(6, 0);
  lcd.print("R");

   if(pwm < 1000)      
        lcd.print(" ");
if(pwm < 100)
        lcd.print(" ");
if(pwm < 10)
        lcd.print(" ");
lcd.print(pwm);

  
 //ESC
  int potVal = analogRead(potentiometerPin); // read input from potentiometer.
  int pwmVal = map(potVal,0, 1023, 1000, 2000); // maps potentiometer values to PWM value.
  servo.writeMicroseconds(pwmVal); // Send signal to ESC.

  lcd.setCursor(6, 1);
  lcd.print("A");
  percentage = map(pwmVal, 1000, 2000, 0, 100);
  lcd.print(percentage);
  lcd.print("% ");


}

 

Edited by Mihai85
Link to comment

Cand am avut de comandat ESC-uri sau servo-uri de radiomodelism, am generat mereu o intrerupere la fix 20ms (pentru 50Hz, dar merge orice frecventa intre 40 si 60Hz), la fiecare intrerupere citesti potentiometrul (valoarea ADC) si decizi lungimea pulsului intre 1 si 2ms. Daca nu ai alte intreruperi, merge brici.

 

PS: vorbim de PPM, nu de PWM, caci nu e deloc acelasi lucru. 

Link to comment
Acum 11 minute, Mihai85 a spus:

Am testat fizic montajul. Am mutat senzorul hall pe pin 7 (INT.6). Partea de variator functioneaza ok dar la turatie (pwm) nu afisaza nimic. Ramane zero.

Functia "attachInterrupt" nu vrea numarul pin-ului care se foloseste la pinMode si digitalWrite/Read ci numarul intreruperii, sunt lucruri diferite.

 

Inlocuieste 

attachInterrupt(pin,intHandler,CHANGE);

 

cu 

 

attachInterrupt(digitalPinToInterrupt(pin),intHandler,CHANGE); 

 

 

Link to comment
1 oră în urmă, Mircea a spus:

Cand am avut de comandat ESC-uri sau servo-uri de radiomodelism, am generat mereu o intrerupere la fix 20ms (pentru 50Hz, dar merge orice frecventa intre 40 si 60Hz), la fiecare intrerupere citesti potentiometrul (valoarea ADC) si decizi lungimea pulsului intre 1 si 2ms. Daca nu ai alte intreruperi, merge brici.

 

PS: vorbim de PPM, nu de PWM, caci nu e deloc acelasi lucru. 

Da, despre PPM este vorba. 1-2ms. Am expus la inceput ce am incercat eu. Doua temperaturi cu termistor ntc, o turatie cu senzor hall, si comanda de tip servo (PPM).

 

1 oră în urmă, Bandi Szasz a spus:

Functia "attachInterrupt" nu vrea numarul pin-ului care se foloseste la pinMode si digitalWrite/Read ci numarul intreruperii, sunt lucruri diferite.

 

Inlocuieste 

attachInterrupt(pin,intHandler,CHANGE);

 

cu 

 

attachInterrupt(digitalPinToInterrupt(pin),intHandler,CHANGE); 

 

 

Am facut modificarea sugerata si acum raspunde.

Indicatia este foarte rapida iar cand opresc motorul ramane o valoare intiparita, nu revine la zero, pe serial monitor. Pe lcd afiseaza aiurea niste cifre care se plimba.

Am facut un test. La 1180 rpm(masurata cu un voltcraft )  imi returneaza valori cuprinse intre 18200-18300, care trebuie transformate in rpm banuiesc .

Acum ca am taiat delay-urile la temperaturi si masurare tensiune  oscileaza un pic indicatia la ultima cifra.

Edited by Mihai85
Link to comment

Nu am o preferinta anume prin care sa citesc turatia , ma intereseaza ca semnalul servo/esc sa nu fie perturbat de celelalte , sa functioneze impreuna. Cred ca las temperaturile , turatia ,voltmetrul si pozitia potentiometrului pe placa asta si pun comanda pe alta placa sau un servotester.

Link to comment

Va salut. 

Am rezolvat in felul urmator cu o mica exceptie: cand opresc motorul/rotatiile ramane afisata o valoare  pe ecran(apropiata de ultima valoare citita), nu se duce la zero. 

Ce as vrea sa mai rezolv ar fi sa mai indulcesc un pic afisarea temperaturilor. Ultima cifra mai oscileaza, pentru ca nu mai pot introduce delay().

 

 

#include <LiquidCrystal_I2C.h>
#include <Servo.h>


byte servoPin = 9; // signal pin for the ESC.
byte potentiometerPin = A0; // analog input pin for the potentiometer.
Servo servo;

int Thermistor1Pin = 3;
int Thermistor2Pin = 2;

int Vo;
float R1 = 10000;
float logR2, R2, T, Tc, Tf;
float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07;

// variables for input pin for measure Ubat
  int analogInput = 1;
  float vout = 0.0;
  float vin = 0.0;
  float R3 = 33000.0;    // !! resistance of R1 !!
  float R4 = 10000.0;     // !! resistance of R2 !!

// variable to store the value 
  int value = 0;

  int percentage;

  //Pentru rpm
 volatile long RPMcount=0;
 volatile long RPM=0;
 volatile boolean flag=0;
 long RPMperiod;
 #define pin 7 //pin the interrupt is attached to


 
LiquidCrystal_I2C lcd(0x27, 16, 2);



void setup() {
  lcd.init();
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.backlight();      // Make sure backlight is on
  
  
  
  servo.attach(servoPin);


   attachInterrupt(digitalPinToInterrupt(pin),magnet_detect,FALLING);//Initialize the intterrupt pin (Arduino digital pin 7)
}
void loop() {

  Vo = analogRead(Thermistor1Pin);
  R2 = R1 * (1023.0 / (float)Vo - 1.0);
  logR2 = log(R2);
  T = (1.0 / (c1 + c2 * logR2 + c3 * logR2 * logR2 * logR2));
  Tc = T - 273.15;
  Tf = (Tc * 9.0) / 5.0 + 32.0;

 
  lcd.setCursor(0, 0);
  lcd.print("Tm");
  if (Tc < -50)
  lcd.print("--");
  if (Tc > -50)  
  lcd.print((int)Tc);
  lcd.print("C ");
  

  
  Vo = analogRead(Thermistor2Pin);
  R2 = R1 * (1023.0 / (float)Vo - 1.0);
  logR2 = log(R2);
  T = (1.0 / (c1 + c2 * logR2 + c3 * logR2 * logR2 * logR2));
  Tc = T - 273.15;
  Tf = (Tc * 9.0) / 5.0 + 32.0;

  lcd.setCursor(0, 1);
  lcd.print("Tc");
  if (Tc < -50)
     lcd.print("--");
   if (Tc > -50)  
   lcd.print((int)Tc);
   lcd.print("C ");

  
  
  // read U Batt
  value = analogRead(analogInput);

  vout = (value * 5.0) / 1024.0;
  vin = vout / (R4/(R3+R4)); 
 if (vin<0.09) 
   vin=0.0;//statement to quash undesired reading !
 
   
    lcd.setCursor(12, 1);
    lcd.print(vin);
    lcd.setCursor(12, 0);
    lcd.print("Ubat");

    
  //RPM

  if(flag)
  {
    noInterrupts();
    RPM=(60000000UL/RPMperiod);   //One signals per rotation.
    interrupts();
   
    flag=0;
  }
          
  
 

  lcd.setCursor(6, 0);
  lcd.print("R");

   if(RPM < 1000)      
        lcd.print(" ");
if(RPM < 100)
        lcd.print(" ");
if(RPM < 10)
        lcd.print(" ");
lcd.print((int)RPM);

  
 //ESC
  int potVal = analogRead(potentiometerPin); // read input from potentiometer.
  int pwmVal = map(potVal,0, 1023, 1000, 2000); // maps potentiometer values to PWM value.
  servo.writeMicroseconds(pwmVal); // Send signal to ESC.

  lcd.setCursor(6, 1);
  lcd.print("A");
  percentage = map(pwmVal, 1000, 2000, 0, 100);
  lcd.print(percentage);
  lcd.print("% ");


}
 void magnet_detect() //Called whenever a magnet/interrupt is detected 
{
  RPMperiod=micros()-RPMcount;
  RPMcount=micros();
  flag=1;
}

 

 

Edited by Mihai85
Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now



×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.Terms of Use si Guidelines