cambio motore dc con motore brushless - cambio controllo pwm

Salve a tutti ed auguri innanzitutto,

faccio una veloce premessa per poi fare la domanda relativa al problema che mi accingo ad affrontare.
Ho installato sulla mia moto 4 arduino nano che svolgono tutti una funzione specifica e sono connessi tutti tra di loro via bus e si scambiano dati.

Uno di essi gestisce il parabrezza elettrico. La moto era dotata di un sistema manuale, io ho installato un motore e lo gestisco con arduino (sotto allego lo sketch). Questo arduino nano gestisce due pulsanti, per salire e scendere il parabrezza, ed inoltre è collegato ad una scheda telecomando per aprire e chiudere il cancello di casa. Sul pin 2 legge un segnale proveniente da un sensore hall (mi avete gentilmente aiutato a risolvere un problema in merito) usa questo valore per vari motivi e lo invia via PWM ad un altro arduino nano.
Il motore è gestito in modo semplicissimo ovvero tramite dei relè che lo alimentano in modo da farlo salire o scendere. Ho constatato negli anni che il motore si rompe probabilmente perché non è brushless. Potrebbe rompersi anche per motivi meccanici dovuti alle sollecitazioni. Il motore attuale ha un riduttore a 625 e gira a 4.5 rpm con 100 Ncm di coppia. Ho quindi deciso di darci un taglio e passare ad un motore di classe superiore dal punto di vista meccanico e sopratutto brushless.

Il motore è questo

Il motore è a 24 V quindi dovrò innanzitutto installare un convertitore DC-DC step-up per alimentarlo. Non credo sia un problema. Ha l'elettronica già onboard (ma non so esattamente cosa significa).

Per il controllo pensavo a questo:

pin 3 del motore: posso utilizzare qualunque pin digitale di arduino per cambiare lo stato e cambiare la direzione di marcia.

pin 4 del motore: non mi serve leggere le pulsazioni e poi il pin 2 di arduino è già impegnato.

pin 5 del motore: se ho capito bene inviando un segnale PWM con frequenza compresa tra 15KHz e 24 KHz posso variare la velocità che al massimo è 7,5 rpm per il mio modello.

pin 6 del motore: posso utilizzare qualunque pin digitale di arduino per avviare e fermare il motore

Spero di avere spiegato il contesto. La domanda è relativa al fatto che la frequenza richiesta dal motore non è compatibile con quella di arduino e quindi non posso gestirla a meno di mettere un altro arduino con i pin modificati in fastPWM (ma non sono esperto). In realtà a me non interessa affatto modificare la velocità e ridurla ma mi va bene 7,5 rpm. Visto l'hardware del motore, posso utilizzare un pin digitale di arduino con uscita 5V per simulare un duty cycle del 100%. Se non sbaglio in questo modo non dovrei pormi il problema di modulare il duty cycle e non ho motivo di usare pin PWM di arduino.

Grazie per i consigli.

il codice non entrava perché eccedeva 9000 caratteri e l’ho diviso

prima parte, dichiarazioni + setup

/*  Istruzioni utilizzo EPROM:

    La posizione 63 è occupata dalla stato del windscreen

    La posizione 65 è occupata dallo stato di attivazione del telecomando: 0 disattivo, 1 attivo

    La posizione 66 è occupata dalle impostazioni del windshield:

             0: Il parabrezza si mette in posizione bassa quando si spegne il quadro strumenti. Quando si riaccende il parabrezza riprende la posizione prima dello spegnimento.
             1: Il parabrezza rimane nella posizione in cui si trova quando si spegne il quadro.

    La posizione 67 è occupata delle impostazioni del windshield:

             1: Imposta il limite di velocità a cui disattivare i comandi del windshield a 100;
             0: disattiva il limite di velocità;

    La posizione 68 è occupata dalle impostazioni del windshield:

             0: Motalità automatica disattivata
             1: Modalità automatica (City)     Vmin=15, Vmax=35;
             2: Modalità automatica (Touring)  Vmin=40, Vmax=70;
             3: Modalità automatica (Mainways) Vmin=60, Vmax=90;

   La posizione 76 è relativa al limite inferiore di temperatura per alzare il windshield
   La posizione 77 è relativa al limite superiore di temperatura per abbassare il windshield

   La posizione 78 è occupata dalo stato di attivazione dell'automatismo del parabrezza con la temperatura

             0: disattivato;
             1: attivato;

*/


#include <EEPROM.h>
#include <Wire.h>

int VPin = A2;         // Pin dove si legge la tensione della batteria
int PinSpeed = 2;      // Pin dove si legge la velocità della ruota
int RelayUP = 3;       // Pin dell'attivazione relay up     ATTENZIONE MODIFICATO PER METTERE IL PIN PWM
int RelayDOWN = 4;     // Pin dell'attivazione relay down   ATTENZIONE MODIFICATO PER METTERE IL PIN PWM

int pinPWM = 5;        // Pin per il PWM della velocità

int ButtonUP = 6;      // ingresso bottone di salita
int ButtonDOWN = 7;    // ingresso bottone di discesa
int PinRF433 = 8;      // uscita che alimenta il telecomando

double R1 = 9.8;       // Resistenza (KOhm) del partitore verso Vin
double R2 = 4.7;       // Resistenza (KOhm) del partitore a Vout

double TimeIN = 0;
double TimeOUT = 0;
double TimeWindshield = 0;
double wheelTime, wheelSpeed, Time433;
double Windshield_speed_limit = 90.0;  // imposta il limite dell'azionamento del windshield
double Vmin = 300.0;                   // imposta il limite della velocità a cui scendere il parabrezza in automatico
double Vmax = 300.0;                   // imposta il limite della velocità a cui alzare il parabrezza in automatico
double Time;
double Tempo_windscreen = 3550;        // millisecondi per l'interruzione
double delay_up = 650;
double V1 = 0;
double V2 = 0;
double V3 = 0;

boolean OKScreen = false;
boolean ScreenPUSHUP = false;
boolean ScreenPUSHDOWN = false;
boolean ONEtimeOnly = true;
boolean IRF433Button = false;
boolean Telecomando = true;
boolean Windshield_position = true; // stabilisce come deve essere messo il windshield quando la moto si spegne
boolean Windshield_auto = false;    // stabilisce se il windshield si muove in automatico
boolean OkTOup = false;
boolean OkTOdown = false;           // boolean per alzare ed abbassare il windshield in automatico
boolean Exit_cycle = false;
boolean NotEnter = true;
boolean ReadOK = true;
boolean NotAUTOdown = false;
boolean NotAUTOup = false;
boolean Not_T_AUTOdown = false;
boolean Not_T_AUTOup = false;
boolean Operate = false;
boolean OKeeprom = true;


byte eeprom = EEPROM.read(63);

volatile int wheelCount;


void setup() {

  Wire.begin(8);
  Wire.onReceive(receiveEvent); // register event

  pinMode(RelayUP, OUTPUT);
  pinMode(RelayDOWN, OUTPUT);
  pinMode(ButtonUP, INPUT);
  pinMode(ButtonDOWN, INPUT);
  pinMode(PinRF433, OUTPUT);
  pinMode(PinSpeed, INPUT);

  attachInterrupt(digitalPinToInterrupt(PinSpeed), Speed, RISING);

  digitalWrite(RelayUP, HIGH);       // Mette i relay in chiusura (posizione NC)
  digitalWrite(RelayDOWN, HIGH);     // Mette i relay in chiusura (posizione NC)
  digitalWrite(ButtonUP, HIGH);       //  Attiva la resistenza interna di PULL-UP
  digitalWrite(ButtonDOWN, HIGH);     //  Attiva la resistenza interna di PULL-UP
  digitalWrite(PinSpeed, HIGH);       //  Attiva la resistenza interna di PULL-UP
  digitalWrite(PinRF433, LOW);
  Time = millis();
  // Serial.begin(9600);
  wheelSpeed = 0;
  wheelTime = 0;


  //EEPROM.write(63, 0);
  //EEPROM.write(65, 1);
  //EEPROM.write(66, 0);
  //EEPROM.write(67, 1);
  //EEPROM.write(68, 1);

  setup_telecomando();
  setup_windshield();
  delay(500);
  //eeprom = 0; eliminato perché non fa alzare il parabrezza dopo lo spegnimento
}

seconda parte: ciclo loop

void loop() {

  double check;
  int first, Second;


  /*
      Questo IF intercetta la prima accensione ed ripristina le condizioni iniziali del windscreen prima
      dello spegnimento. VPin deve essere quello della tensione di un lampada o di un qualcosa sotto chiave.

  */

  check = V(VPin);
  check = (check + V1 + V2 + V3) / 4;
  V3 = V2;
  V2 = V1;
  V1 = check;

  if (check > 600 && ONEtimeOnly) {
    OKScreen = true;
    Operate = true;
    if ((eeprom == 1 && ONEtimeOnly) && Windshield_position) {
      Windshield(true, false);
      delay(Tempo_windscreen + delay_up);
      Windshield(true, true);
    }
    ONEtimeOnly = false;
  }

  /*
      Questo IF intercetta la tensione della luce posteriore ed identifica il quadro spento.
      Tuttavia c'è ancora tensione dallo power socket BMW e quindi si può mettere il windscreen
      in posizione di chiusura
  */

  if ((check < 200.00) && (OKScreen)) {
    OKScreen = false;
    ONEtimeOnly = true;
    Operate = false;
    if (eeprom == 1) {
      if (Windshield_position) {
        Windshield(false, false);
        delay(Tempo_windscreen);
        Windshield(false, true);
      }
      EEPROM.write(63, 1);
      eeprom = 1;
    }
    else EEPROM.write(63, eeprom);
  }


  if (!Windshield_auto)
    if (wheelSpeed < Windshield_speed_limit) ReadOK = true;
    else ReadOK = false;
  else
  {
    if (Operate) {
      if (wheelSpeed < Windshield_speed_limit) ReadOK = true;
      else ReadOK = false;

      switch (eeprom) {
        case 0:
          if (NotAUTOup) OkTOup = false;
          else OkTOup = true;
          OkTOdown = false;
          break;
        case 1:
          OkTOup = false;
          if (NotAUTOdown) OkTOdown = false;
          else OkTOdown = true;
          break;
      }

      if (((wheelSpeed > Vmax && OkTOup) && !Exit_cycle)) {
        Windshield(true, false);
        TimeWindshield = millis();
        Exit_cycle = true;
        NotEnter = false;
      }
      if (((wheelSpeed < Vmin && OkTOdown) && !Exit_cycle)) {
        Windshield(false, false);
        TimeWindshield = millis();
        Exit_cycle = true;
        NotEnter = false;
      }
      if (((millis() - TimeWindshield) > Tempo_windscreen) && !NotEnter) {
        if (OkTOup) {
          delay(delay_up);
          Windshield(true, true);
          OkTOup = false;
        }
        if (OkTOdown) {
          Windshield(false, true);
          OkTOdown = false;
        }
        Exit_cycle = false;
        NotEnter = true;
      }
    }
  }


  if (ReadOK) {
    if (OKScreen) {
      if (OKeeprom)
        if (!ScreenPUSHDOWN) {
          if (eeprom == 0) {
            first = digitalRead(ButtonUP);
            delay(10);
            Second = digitalRead(ButtonUP);
            if (((Second == first) && first == LOW) && !ScreenPUSHUP) {
              TimeIN = millis();
              Windshield(true, false);
              ScreenPUSHUP = true;
              ScreenPUSHDOWN = false;
              if (Windshield_auto && !NotAUTOup) NotAUTOdown = true;
            }
          }
          else {
            if (Telecomando) {
              first = digitalRead(ButtonUP);
              delay(10);
              Second = digitalRead(ButtonUP);
              if (((Second == first) && first == LOW)) {
                digitalWrite(PinRF433, HIGH);
                Time433 = millis();
                IRF433Button = true;
              }
            }
          }
        }

      // Scende il parabrezza

      if (!ScreenPUSHUP) {
        if (eeprom == 1) {
          first = digitalRead(ButtonDOWN);
          delay(10);
          Second = digitalRead(ButtonDOWN);
          if (((Second == first) && first == LOW) && !ScreenPUSHDOWN) {
            TimeIN = millis();
            Windshield(false, false);
            ScreenPUSHUP = false;
            ScreenPUSHDOWN = true;
            if (Windshield_auto && !NotAUTOdown) NotAUTOup = true;
          }
        }
        else {
          if (Telecomando) {
            first = digitalRead(ButtonDOWN);
            delay(10);
            Second = digitalRead(ButtonDOWN);
            if (((Second == first) && first == LOW)) {
              digitalWrite(PinRF433, HIGH);
              Time433 = millis();
              IRF433Button = true;
            }
          }
        }
      }
      if (ScreenPUSHDOWN || ScreenPUSHUP) {
        TimeOUT = millis();
      }
      if ((TimeOUT - TimeIN) > Tempo_windscreen) {
        if (ScreenPUSHUP) {
          delay(delay_up);
          Windshield(true, true);
          if (Windshield_auto) NotAUTOup = false;
        }
        if (ScreenPUSHDOWN) {
          Windshield(false, true);
          if (Windshield_auto) NotAUTOdown = false;
        }
        ScreenPUSHDOWN = false;
        ScreenPUSHUP = false;
        TimeOUT = TimeIN;
      }
    } // End if ciclo della gestione del windshield
  } // End ReadOK


  // if che spegne il telecomando

  if ((millis() - Time433) > 800 && IRF433Button) {
    digitalWrite(PinRF433, LOW);
    IRF433Button = false;
  }

  /*  Calcolo della velocità dal pin 2 attraverso l'interrrupts.
      Il valore di counts e del tempo potrebbero non essere
      congruenti con il sistema atutomatico del windshield
      in particolare con il valore di modalità CITY
  */

  if (wheelCount > 9 || millis() - wheelTime > 1000) {
    wheelSpeed = ((59.8 * 3.14159 * 10 / 5) * wheelCount / (millis() - wheelTime)) * 3.6 * 0.955;
    wheelTime = millis();
    wheelCount = 0;
  }


  /*
     Questa routine calcola il duty cycle per il PWM in funzione della velocità.
     a 255 corrispondono 90 km/h
  */
  if (wheelSpeed < 90) {
    double temp_w = wheelSpeed / 90 * 168;
    int temp_pwm = (int) temp_w;
    analogWrite(pinPWM, temp_pwm);
  }
  else analogWrite(pinPWM, 168); // tensione max di 3.3V


} // END del ciclo loop

terzo ed ultimo: funzioni

/*
   Questa Funzione calcola la Tensione del partitore a VPin.
   Il partitore è nel cavo di diversione del segnale del
   faro posteriore.
*/

double V(int a) {
  double Temp = 0;
  int n = 250;

  for (int kk = 1; kk <= n; kk++) Temp = Temp + analogRead(a);
  Temp = Temp / n * (R1 + R2) / R2 / 1023 * 500;
  return Temp;

}

/*  Questa funzione conta il numero di interrupts e quindi di
    giri che sono accaduti e dopo un tot, calcola la velocità
    nella routine principale
*/

void Speed() {
  wheelCount += 1;
}



void setup_telecomando () {
  if (EEPROM.read(65) == 0) {
    Telecomando = false;
  }
  if (EEPROM.read(65) == 1) {
    Telecomando = true;
  }
}

void setup_windshield() {

  /* Posizione del windshield all'avviamento ed allo spegnimento:
     true, si posiziona basso in automatico e si ripristina all'avviamento
     false, lo lascia come si trova
  */


  if (EEPROM.read(63) == 1) NotAUTOdown = true;

  if (EEPROM.read(66) == 0) {
    Windshield_position = true;
  }
  else {
    if (EEPROM.read(66) == 1) {
      Windshield_position = false;
    }
  }
  /* Imposta il limite di velocità */
  if (EEPROM.read(67) == 0) {
    Windshield_speed_limit = 90;
  }
  else {
    if (EEPROM.read(67) == 1) {
      Windshield_speed_limit = 300;
    }
  }
  /* Imposta la modalità automatica */
  if (EEPROM.read(68) == 0) {
    Windshield_auto = false;
    ReadOK = true;
  }
  else {
    Windshield_auto = true;
    ReadOK = false;
    switch (EEPROM.read(68)) {
      case 1:
        Vmin = 5;
        Vmax = 35;
        break;
      case 2:
        Vmin = 10;
        Vmax = 70;
        break;
      case 3:
        Vmin = 15;
        Vmax = 90;
        break;
    }
  }
}


/*
    Questa funzione alza ed abbassa il windshield.
    I relay in posizione HIGH sono disattivi mentre
    si attivano in poszione LOW.
    true/false attiva la salita
    false/false attiva la discesa
    true/true disattiva la salita
    false/true disattiva la discesa
*/


void Windshield(boolean UP, boolean Stop) {
  if (UP && !Stop) {
    digitalWrite(RelayDOWN, HIGH);
    delay(100);
    digitalWrite(RelayUP, LOW);
  }
  if (!UP && !Stop) {
    digitalWrite(RelayUP, HIGH);
    delay(100);
    digitalWrite(RelayDOWN, LOW);
  }
  if (UP && Stop) {
    digitalWrite(RelayUP, HIGH);
    eeprom = 1;

  }
  if (!UP && Stop) {
    digitalWrite(RelayDOWN, HIGH);
    eeprom = 0;
  }
}


/*
     Funzione che si attiva all'avviamento per la ricezione di comandi

*/

void receiveEvent(int howMany) {
  int x = Wire.read();
  if (x >= 0 && x < 12) {
    switch (x) {
      case 0:
        EEPROM.write(65, 0);
        break;
      case 1:
        EEPROM.write(65, 1);
        break;
      case 2:
        EEPROM.write(66, 0);
        break;
      case 3:
        EEPROM.write(66, 1);
        break;
      case 4:
        EEPROM.write(67, 0);
        break;
      case 5:
        EEPROM.write(67, 1);
        break;
      case 6:
        EEPROM.write(68, 1);
        break;
      case 7:
        EEPROM.write(68, 2);
        break;
      case 8:
        EEPROM.write(68, 3);
        break;
      case 9:
        EEPROM.write(68, 0);
        break;
      case 10:
        EEPROM.write(78, 0);
        break;
      case 11:
        EEPROM.write(78, 1);
        break;
    }
    delay(100);
    setup_telecomando();
    setup_windshield();
  }
}

fammi capire:
tu pensi che il motore attuale si danneggi perchè è un motore a spazzole
cosa te lo fa pensare?
verifichi usura anomala delle spazzole, rigatura del collettore, usura eccessiva del collettore, eccesso di polvere di carbone che provoca perdita di isolamento? eccesso di scintillio in commutazione, segni di surriscaldamento nel rotore e/o nello statore se è un motore in serie?
no, perchè se nessuna di queste cose avviene è probabile che il motore si danneggi per altre cause
ricordati che i motori a spazzole sono usati dal Black And Decker per i loro trapani (e non solo da loro), e io non ho mai avuto occasione di cambiare nemmeno le spazzole al mio trapano, non parliamo di rettificare il collettore
il mio consiglio sarebbe di esaminare bene la causa di guasto, che l'attuale analisi mi sembra affrettata,
hai controllato lo stato dei cuscinetti? e quello degli ingranggi del riduttore? il carico radiale e quello assiale? come hai collegato il riduttore? hai tenuto in considerazione non so, per fare un esempio, che una trasmissione a cnghia o a fune applica un tiro anche statico sull'asse, tiro che si trasforma in un carico radiale, anche consistente?
dopo cambia il motore con uno più adatto, se risulta necessario, ma non portarti in casa il fardello ulteriore di un convertitore cc-cc da 12 a 24, prendi un motore direttamente per applicazioni automobilistiche

Ciao Standardoil (nome vagamente associato al petrolchimico...)

Forse non ho ben chiarito che il motore si è rotto ben due volte ed in entrambi i casi ha iniziato a funzionare a singhiozzo: a volte parte e funziona per qualche giorno poi smette, poi riparte... ecc. infine l'ho sostituito con uno identico ed alla fine ha fatto un anno di vita e si è rotto allo stesso modo.

Nel suo funzionamento il motore fa solo circa 120° di giro quindi la meccanica gira poco ed è sollecita sempre negli stessi punti mentre il motore stesso avendo una riduzione a 630 gira ovviamente molto di più compiendo 210 giri per ciclo.

Non ho verificato la causa, ma non credo di essere in grado di farlo non avendolo mai fatto non ho termini di paragoni. In realtà se smonto il motore devo subito metterne un altro altrimenti rimango a piedi con la moto cosa per me molto più grave .....

Quindi ho deciso di cambiare il motore ed andare su uno con un riduttore epicicloidale con cuscinetti che ha una resistenza meccanica molto più alta sia sul carico assiale che radiale. Ovviamente ho pensato di prenderlo brushless così elimino un'altra potenziale causa. Tieni presente che questi motori non sono progettati per stare all'aperto come su una moto. Temperature basse, acqua e polvere sono standard e sebbene l'abbia protetto non sono sicuro che non sia una delle cause.

Rimettere lo stesso motore ed aprire l'attuale per studiarlo richiede del tempo che con due figli non ho...

Per questo la scelta di andare verso un motore più resistente sotto tutti i punti di vista.

Tu hai qualche link o marca di motori di derivazione automobilistica?

no, mi spiace, nessun link
hai provato a guardare tra i motori per alzacristalli o tergicristalli?
hanno standard di affidabilità altissimi, se ricordo bene li usa(va) anche ESAB Saldatura sui suoi trainafilo per saldature robotizzate, ergo usi continui in ambiente ostile, ma se la meccanica è oramai definita hai poco da scegliere
ti posso solo augurare che la causa della rottura sia effettivamente nella commutazione, altrimenti ti impegoli peggio

Pomeriggio mi sono ricordato di non aver buttato il primo motore. L’ho aperto ed ho scoperto che erano saltati dei denti nell’ultimo ingranaggio probabilmente per sollecitazioni meccaniche.

Il secondo motore è installato e non ho potuto provare. Mentre il primo veniva gestito da un rele (non da arduino) il secondo è sotto il controllo di arduino ed ho notato dei problemi con i fine corsa. In particolare la corsa del motore prima avveniva in 3550 millisecondi mentre adesso ho dovuto aumentare il tempo a 5400 millisecondi. Non so la ragione di questo incremento di tempo.

Quindi per il momento cambio tipo di motore e ne metto uno più resistente non brushless. Ad ogni modo… quale è la risposta alla mia domanda sul PWM? Giusto perché se in futuro il problema si ripresenta… in forma differente