PWM zu Step-Dir - Ich komme nicht weiter

Hallo zusammen,

ich versuche seit einiger Zeit ein RC – PWM Signal über einen Arduino Nano zu einem Step- / Dir – Signal für eine Schrittmotorendstufe zu wandeln.

Leider komme ich nicht weiter, mein Verständniss reicht hierfür leider nicht aus. Meine Ergebnisse erzeugen entweder langsam laufende oder zuckelnde Motoren.

Die Maximale Pulsfrequenz für die Schrittsignale soll bei 40kHz liegen (maximal RPM) und im besten falle von nahe 0 bis 40kHz in stufen über das RC-Signal geregelt werden können.

Falls ich hier unmögliches versuche, wäre ein Hinweis nett.

Ich habe jetzt hier schon ein Stück Code mit dem ich den PWM – Pin auslese und unplausible Werte aussortiere. Das funktioniert soweit ich das über die serielle Schnittstele nachverfolgen kann auch schon ganz zuverlässig.

Nun möchte ich die Schrittsignale zum Motor senden aber mein Motor dreht entweder nicht oder nur sehr langsam.

Mit einem sehr einfachen Programm habe ich mal getestet ob der Motor überhaupt funktioniert und dabei auch gut Drehzahl zusammen bekommen.

Mein Code sieht aktuell so aus:

/*
#1 Controlling a Stepper Motor with a Remote Control and Arduino von: Brandon Tsuge
https://theboredrobot.com/blogs/blog/controlling-a-stepper-motor-with-a-remote-control-and-arduino
----------------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------------------------
#2 Tutorial for reading PWM non-blocking von: "heinduplessis" 
https://forum.arduino.cc/t/tutorial-for-reading-pwm-non-blocking/479611
-----------------------------------------------------------------------------------------------------------------
 */
#define PWM_Pin 2
#define DIR 4
#define STEP 5

int lastPulseTime;
int pulseTime;
int channelValue;
int pulse_Lenght;

//Set up time variables for Stepper motor
unsigned long previousMotorTime = micros();
unsigned long MotorInterval = 0;
volatile long StartTime = 0;
volatile long CurrentTime = 0;


void setup() {
  Serial.begin(115200);
  attachInterrupt(digitalPinToInterrupt(PWM_Pin), Pulse, CHANGE);
}

void loop() {

  //Serial.print("channelValue");
  //Serial.println(channelValue);
  //Serial.print("MotorInterval:");
  //Serial.println(MotorInterval);

  digitalWrite(STEP, LOW);

  //Stepper motor speed, bigger MotorInterval is a slower speed.
  if (channelValue >= 1450 && channelValue <= 1550) {
    digitalWrite(STEP, LOW);  //Motor doesn't move if the joystick is near the midpoint

  } else if (channelValue < 1450) {
    digitalWrite(DIR, LOW);
    MotorInterval = map(channelValue, 1150, 1450, 0, 25);  //map the RC signal to the motor speed in reverse when the joystick is pulled down
    Serial.println(MotorInterval);
  } else if (channelValue > 1550) {
    digitalWrite(DIR, HIGH);
    MotorInterval = map(channelValue, 1550, 1850, 25, 0);  //map the RC signal to the motor speed when the joystick is pushed forward.
    Serial.println(MotorInterval);
  }

  //check if the MotorInterval time has elapsed and step the motor.
  unsigned long currentMotorTime = micros();
  if (currentMotorTime - previousMotorTime > MotorInterval) {
    digitalWrite(STEP, HIGH);
    previousMotorTime = currentMotorTime;
  }
}

void Pulse() {
  lastPulseTime = pulseTime;
  pulseTime = micros();
  pulse_Lenght = pulseTime - lastPulseTime;
  if ((pulse_Lenght > 1150) & (pulse_Lenght < 1850)) {
    channelValue = pulse_Lenght;
  }
}

Über einen Schubs in die richtige Richtung wäre ich Euch dankbar.

Schönes Wochennende zusammen!
Matt-Hias

Wenn ich deinen Code richtig verstehe, bedeuten die 25 die Maximalgeschwindigkeit ( 25µs / Step ). Wenn es langsamer gehen soll, muss das Intervall aber größer werden, und nicht noch kleiner ( Intervall 0 geht ja gar nicht ).

Das würde ich nicht so machen - achte auf den Operator!.
Und hier bricht es Dir dann das Genick restlos.

@MicroBahner : Stimmt, das habe ich nicht bedacht. Ich habe den Code nochmal etwas angepasst und ich komme langsam schon in eine brauchbare Richtung.

@my_xy_projekt : Ich verstehe nicht was ich da falsch mache beziehungsweise anders machen kann.
Habe ich die falsche Variablen - Type gewählt?

Anbei der aktuelle, schon etwas bessere Code:
Es hackt noch bei der PWM - Abfrage, die funktioniert scheinbar nicht zuverlässig. Kann Hier jeamnd erkennen was da los ist? Oder ist das was @my_xy_projekt gemeint hat?

/*
#1 Controlling a Stepper Motor with a Remote Control and Arduino von: Brandon Tsuge
https://github.com/TheBoredRobot/Arduino-Examples/blob/master/RC_and_Stepper.ino
----------------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------------------------
#2 Tutorial for reading PWM non-blocking von: "heinduplessis" 
https://forum.arduino.cc/t/tutorial-for-reading-pwm-non-blocking/479611
-----------------------------------------------------------------------------------------------------------------
 */
#define PWM_Pin 2
#define DIR 4
#define STEP 5

int lastPulseTime;
unsigned long pulseTime;
int channelValue;
int pulse_Lenght;
int Motor_STEP;

//Set up time variables for Stepper motor
unsigned long previousMotorTime = micros();
unsigned long MotorInterval;
volatile long StartTime = 0;
volatile long CurrentTime = 0;


void setup() {
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  Serial.begin(115200);
  attachInterrupt(digitalPinToInterrupt(PWM_Pin), Pulse, CHANGE);
}

void loop() {

  digitalWrite(STEP, LOW);

  //Stepper motor speed, bigger MotorInterval is a slower speed.
  if (channelValue >= 1450 && channelValue <= 1550) {
    digitalWrite(STEP, LOW);  //Motor doesn't move if the joystick is near the midpoint
    Motor_STEP = 0;

  } else if (channelValue < 1450) {
    digitalWrite(DIR, LOW);
    Motor_STEP = 1;
    MotorInterval = map(channelValue, 1150, 1450, 100, 1000);  //map the RC signal to the motor speed in reverse when the joystick is pulled down
    Serial.println(MotorInterval);
  } else if (channelValue > 1550) {
    digitalWrite(DIR, HIGH);
    Motor_STEP = 1;
    MotorInterval = map(channelValue, 1550, 1850, 1000, 100);  //map the RC signal to the motor speed when the joystick is pushed forward.
   // Serial.println(MotorInterval);
  }

  //check if the MotorInterval time has elapsed and step the motor.
  unsigned long currentMotorTime = micros();
  if(Motor_STEP== 1){
  if (currentMotorTime - previousMotorTime > MotorInterval) {
    digitalWrite(STEP, HIGH);
    previousMotorTime = currentMotorTime;}
  }
}

void Pulse() {
  lastPulseTime = pulseTime;
  pulseTime = micros();
  pulse_Lenght = pulseTime - lastPulseTime;
  if ((pulse_Lenght > 1150) & (pulse_Lenght < 1850)) {
    channelValue = pulse_Lenght;
  }
}

macht das nichts aus dass pulse_Lenght springt zwischen zwei Werten zweimal pro Period?

Da fehlt was :wink:

Lerne den Unterschied zwischen & und &&

Gruß Tommy

Also:
Du hast mit & versucht etwas zu verbinden, meinst aber &&.
Das eine (&) ist ein bitweises UND das andere (&&) ist ein logisches UND.
Das sind zwei vollkommen andere Dinge. Wir hatten hier auch schon den Fall, das ein bitweises & das gleiche Ergebnis brachte wie ein logisches UND. Es ist also nicht ausgeschlossen, das es hier genau so ist.

Dann der Genickbrecher:
pulseTime soll den Inhalt von micros() aufnehmen.
Das geht aber nicht, da der Datentyp int nur bis 32767 geht und dann überläuft. (und damit wieder von -32768 anfängt)

micros() arbeitet mit einem Zahlentyp unsigned long.
Damit muss der aufnehmende Datentyp auch so eingerichtet werden.

Das wäre dann: uint32_t pulseTime

Im Übrigen habe ich bereits mehrerer solcher RC-Dinger begleitet.
Ich würde das mit den mehrfachen if-Vergleichen komplett weg lassen.
Ist mir jetzt aber zu früh - ich bau Dir mal was, von dem ich denke das es funktioniert.

@kolaha : Danke, habs jetzt verstanden, das war mir garnicht bewusst. - Hab das in meinem 2. Code also instinktiv richtig gemacht. :smile:

Danke auch an die Tippgeber @fony ; @Tommy56 ; @my_xy_projekt .

Danke @my_xy_projekt :smile:
Sorry, hab das mit den Variablentypen bis heute nicht richtig verstanden. - Ich bin einfach nicht vom Fach.

Entspricht dann eine Variable vom Typ unsigned long einer Variable vom Typ uint32_t?
Bzw. warum finde ich uint32_t nicht in der Referenz?

Blockquote
Ist mir jetzt aber zu früh - ich bau Dir mal was, von dem ich denke das es funktioniert.

Blockquote

Keine Eile :slight_smile: Danke für das freundliche Angebot.

Arduino hat als Unterbau C++.
Alles was C++ kann, kann Arduino auch.
Mit kleinen Einschränkungen.
Die hauptsächliste ist in der verwendeten Version zu finden. hier: C++ 11

Ansonsten Kurzliteratur: ArduinoForum.de - Das deutschsprachige Forum rund um den Arduino - Arduino Code-Referenz (deutsch) dort das pdf runter laden. Sehr schick geschrieben und liest sich an 3-4 Abenden weg. Da haste schon die halbe Miete.

Ein gutes hier gerne empfohlenes Buch: Der C++ Programmierer – Ulrich Breymann (2017) – terrashop.de auch wenn es "nur" bis Version 17 behandelt ist das vollkommen ausreichend.

Das Buch ist aktuell kaum noch zu bekommen.

Gruß Tommy

Ups. - Die gemeinen Forenleser aber auch... :wink:

Danke, ich versuchs mal mit der Code-Referenz. Hab mich an den 2kg Gewicht von dem Fachbuch erschreckt. :astonished:

Zeigst Du?

echt PWM oder RC PPM?

:grin:
Wenn Du das Buch hast, ist in dem ein Code. Mit dem kannst Du beim Verlag ein personalisiertes .pdf herunter laden, mit dem gleichen Inhalt.

Ich hab mal etwas länger über Deinen Code geschaut.
Da gibts ne Menge Baustellen.
Sicher alles nur Kleinigkeiten, aber eben Baustellen.
Eine ganz berüchtigte, die sich wiederholt:

A) Was passiert, wenn channelValue <1150 ist?
B) map wird nie channelValue mit dem Wert 1450 auswerten können

Las mir mal noch ne gute halbe Stunde, bis ich die Logik zerlegt habe.

Tut mir leid, hier habe ich einen Fehler gemacht. Kämpfe gerade damit es zu reproduzieren wie es dazu kam. Jedenfalls hatte das mal in einer anderen Version des Codes mit eingefügt – Ohne spürbare Ergebnisse.

Ich habe es jetzt nochmal richtig gestellt:

  if ((pulse_Lenght > 1150) && (pulse_Lenght < 1850)) {
    channelValue = pulse_Lenght;
  }

Ich hab mir das am Oszilloskop mal angesehen und bin mir nicht so recht sicher. Es sollte ein PWM - Signal sein, sieht aber irgendwie komisch aus.

Die Rückgabewerte von void Pulse() sind allerdings bis auf einige Ausreißer plausibel.
Das Signal kommt aus einem Cube Orange, den ich mit einer Herelink per Sbus ansteuere.

Die map-Funktion ist nicht auf den min/max Bereich der Eingangswerte begrenzt, sondern funktoniert auch darüber hinaus. Die 2 Wertepaare definieren sozusagen nur die Steigung der Umwandlungsgeraden.