Hilfe bei Record and Pay ohne Seriellen Monitor

Ich benötige wieder einmal Hilfe.

Ich versuche zwei Servo Motoren mit jeweils einem Poti zu steuern und diesen Bewegungsablauf zu speichern.

Habe dafür einen Sketch gefunden zur Steuerung eines Roboterarmes.
Es funktioniert soweit.
Jetzt stehe ich vor dem Problem, daß ich das ganze ohne PC betreiben möchte.
So kam mir die Idee, die Anzeige des verbleibenden Speichers mit LED‘s auszugeben. Sowie Record und Play über zwei Button zu steuern.

Der erste Schritt war die LED Ausgabe. Der Sketch funktioniert mit der Ansteuerung über den Seriellen Monitor.

[code]
/*
   Robotic ARM with Record and Play option using Arduino
   Code by: B. Aswinth Raj
   Website: www.circuitdigest.com
   Dated: 05-08-2018
*/

#include <Servo.h> //Servo Bibliothek

Servo Servo_0;
Servo Servo_1;
//Servo Servo_2;
//Servo Servo_3;
//Servo Gripper;

const int buttonR = 8;
const int buttonP = 12;
int ledBlau = 7;
int ledGelb = 4;
int ledRot = 13;

int ledBlauStatus = LOW;          //der LED-Blau-Status
int ledRotStatus = LOW;           //der LED-Rot-Status
int ledGelbStatus = LOW;            //der LED-Gelb-Status
int buttonRStatus;              //zum zwischenspeichern des aktuellen Record-Schalter-Status
int buttonPStatus;              //zum zwischenspeichern des aktuellen Play-Button-Status
int letzterButtonRStatus = LOW; //zum zwischenspeichern des letzten Record-Schalter-Status
int letzterButtonPStatus = LOW; //zum zwischenspeichern des letzten Play-Schalter-Status
//long ist ein Datentyp für große Zahlen; unsigned bedeutet, dass nur positive Zahlenwerte angenommen werden können. 
unsigned long letzteAenderungR = 0;  //der letzte Zeitpunkt, an dem eine Änderung am Record-Schalter stattfand
unsigned long letzteAenderungP = 0;  //der letzte Zeitpunkt, an dem eine Änderung am Play-Schalter stattfand
unsigned long pause = 50;           //Pause, die nach Schalter-Aktion folgen soll

int S0_pos, S1_pos;        
int P_S0_pos, P_S1_pos;    
int C_S0_pos, C_S1_pos;    
int POT_0,POT_1;           
int saved_data[600]; //Array zu speichern der Record-Daten

int array_index=0;
char incoming = 0;

int action_pos;
int action_servo;

void setup() {
Serial.begin(9600); //Serial Monitor für Fehlersuche

  pinMode(buttonR, INPUT_PULLUP);  //Record-Taster mit internen PULLUP-Widerstand
  pinMode(buttonP, INPUT_PULLUP);  //Play-Taster mit internen PULLUP-Widerstand
  pinMode(ledBlau, OUTPUT);           
  pinMode(ledRot, OUTPUT);          
  pinMode(ledGelb, OUTPUT);
  digitalWrite(ledBlau, ledBlauStatus);    
  digitalWrite(ledRot, ledRotStatus);     
  digitalWrite(ledGelb, ledGelbStatus);    
  
//deklarieren der Servo-Pins 
Servo_0.attach(3);
Servo_1.attach(5);

//Fahren der Servomotoren in die Grundstellung 
Servo_0.write(70);
Servo_1.write(100);

Serial.println("Press 'R' to Record and 'P' to play"); //Instruktion für den Benutzer 
}

void Read_POT() //Funktion zum Lesen des Analogwertes vom POT und dessen Zuordnung zum Servowert
{
   POT_0 = analogRead(A0); 
   POT_1 = analogRead(A1); 
   S0_pos = map(POT_0,0,1024,10,170); //Map it for 1st Servo (Base motor)
   S1_pos = map(POT_1,0,1024,10,170); //Map it for 2nd Servo (Hip motor)
}

void Record() //Funktion zur Aufzeichnung der Bewegungen
{
Read_POT(); //Lesen der POT-Werte zum 1. mal

//Speichern in einer Variablen, um sie später zu vergleichen
   P_S0_pos = S0_pos;
   P_S1_pos = S1_pos;
   
Read_POT(); //Lesen Sie den POT-Wert zum 2. mal
  
   if (P_S0_pos == S0_pos) //Wenn 1. und 2. Wert gleich sind
   {
    Servo_0.write(S0_pos); //Ansteuerung des Servos
    
    if (C_S0_pos != S0_pos) //Wenn der POT gedreht wurde
    {
      saved_data[array_index] = S0_pos + 0; //Speichern der neuen Position im Array.
      array_index++; //Erhöhen des Array-Index 
    }
    
    C_S0_pos = S0_pos; //Speichert den vorherigen Wert, um zu prüfen, ob der POT gedreht wurde 
   }

//In ähnlicher Weise für alle Servomotoren wiederholen
   if (P_S1_pos == S1_pos)
   {
    Servo_1.write(S1_pos);
    
    if (C_S1_pos != S1_pos)
    {
      saved_data[array_index] = S1_pos + 1000; //1000 wird für den 1. Servomotor als Unterscheidungsmerkmal addiert
      array_index++;
    }
    
    C_S1_pos = S1_pos;
   }

  if (array_index >= 20) {            // ab Speicherplatzbelegung 300 LED Blau an
    digitalWrite(ledBlau, HIGH);
  }
    if (array_index >= 300){          // ab Speicherplatzbelegung 300 LED Blau aus und LED Gelb an
      digitalWrite(ledBlau, LOW);
      digitalWrite(ledGelb, HIGH);
    }
    if (array_index >= 580){          // ab Speicherplatzbelegung 580 LED Gelb aus und LED Rot an
      digitalWrite(ledGelb, LOW);
      digitalWrite(ledRot,HIGH);
    }
  //Den Wert zur Fehlersuche ausgeben 
  Serial.print(S0_pos);  Serial.print("  "); 
  Serial.print(S1_pos); Serial.print("  ");
  Serial.print ("Index = "); Serial.println (array_index); 
  delay(100); 
}

void Play() //Funktion zum Abspielen der aufgezeichneten Bewegungen
{
  for (int Play_action=0; Play_action<array_index; Play_action++) //Navigieren durch jedes gespeicherte Element im Array 
  {
    action_servo = saved_data[Play_action] / 1000; //Das erste Zeichen des Array-Elements wird geteilt, um die Servonummer zu kennen
    action_pos = saved_data[Play_action] % 1000; //Die letzten drei Zeichen des Array-Elements werden aufgeteilt, um die Servoposition zu ermitteln 

    switch(action_servo){ //Prüfen welcher Servo-Motor angesteuert werden soll 
      case 0: //If zeroth motor
        Servo_0.write(action_pos);
      break;

      case 1://If 1st motor
        Servo_1.write(action_pos);
      break;

    }

    delay(50);
    
  }
}

void loop() {

if (Serial.available() > 1) //Wenn etwas vom seriellen Monitor empfangen wird
{
incoming = Serial.read();
if (incoming == 'R')
Serial.println("Aufnahme gestartet......");
if (incoming == 'P')
Serial.println("Wiedergabe der aufgezeichneten Sequenz");
}

if (incoming == 'R') //Wenn der Benutzer den Aufnahmemodus gewählt hat
Record();

if (incoming == 'P') //Wenn der Benutzer den Wiedergabemodus ausgewählt hat 
Play();

}
[/code]

Nun habe ich in der Loop Schleife die Steuerung über den Seriellen Monitor mit Button ersetzt.

void loop() {
  //aktuellen Schalter-Messwert lesen
  int gelesenR = digitalRead(buttonR);
  //...Wenn der Record-Schalter-Status sich geändert hat (durch drücken oder auch prellen)
  if (gelesenR != letzterButtonRStatus) {
    // setze den Timer zurück
    letzteAenderungR = millis();
  }
  if ((millis() - letzteAenderungR) > pause) {
    //Der aktuell-gelesene Wert kann nun als zuverlässig angesehen werden, da dieser länger als 50ms vorliegt.
    if (gelesenR != buttonRStatus) {  //falls sich der Status verändert hat...
      buttonRStatus = gelesenR;       //...setze diesen als buttonRStatus
      
      //...und starte Record, falls der Knopf gedrückt wurde
      if (buttonRStatus == HIGH) {
        Record();
      }
    }
  }

   letzterButtonRStatus = gelesenR;
  
  //aktuellen Schalter-Messwert lesen
  int gelesenP = digitalRead(buttonP);
  //...Wenn der Record-Schalter-Status sich geändert hat (durch drücken oder auch prellen)
  if (gelesenP != letzterButtonPStatus) {
    // setze den Timer zurück
    letzteAenderungP = millis();
  }
  if ((millis() - letzteAenderungP) > pause) {
    //Der aktuell-gelesene Wert kann nun als zuverlässig angesehen werden, da dieser länger als 50ms vorliegt.
    if (gelesenP != buttonPStatus) {  //falls sich der Status verändert hat...
      buttonPStatus = gelesenP;       //...setze diesen als buttonRStatus
      
      //...und starte Play , falls der Knopf gedrückt wurde
      if (buttonPStatus == HIGH) {
        Play();
      }
    }
  }
  
  letzterButtonPStatus = gelesenP;
}

Leider habe ich hier keinen Erfolg. Kann jemand meinen Anfängerfehler finden und mir helfen?

Setze Deinen Code bitte in Codetags [code] davor und [/code] (ohne *) dahinter oder gehe in der IDE auf Bearbeiten - Für Forum kopieren und füge es hier ein.
Das kannst Du auch noch nachträglich ändern.

Außerdem formatiere bitte den Code ordentlich (Strg+T in der IDE hilft Dir dabei).

Gruß Tommy

Das wird nichts.
Du merkst Dir den Status nicht.

//aktuellen Schalter-Messwert lesen
int gelesenR = digitalRead(buttonR);
//...Wenn der Record-Schalter-Status sich geändert hat (durch drücken oder auch prellen)
if (gelesenR != letzterButtonRStatus)
{
  // setze den Timer zurück
  letzterButtonRStatus=gelesenR;
  letzteAenderungR = millis();
}

Und, wenn die Taste prellt, biste ganz raus.

Aber dazu muss man den Code lesen können -> den kannst Du da oben löschen und das machen, was @Tommy56 Dir angeboten hat und dann da oben wieder einfügen.

PS: Und in der Überschrift fehlt ein l

Diese Anweisung ist erlaubt, macht aber nichts. Du meinst wohl
Play();
wie in der Vorversion. Dasselbe mit Record;

Der Fehler ist mir heute auch aufgefallen. Habe es im Sketch geändert. Es funktioniert trotzdem nicht.

Der Button Sketch funktioniert einwandfrei. Verwende ihn mit zwei Taster und zwei LED's. Warum soll es hier nicht klappen?

Das weiss ich noch nicht.
Der Code der jetzt oben drin steht, ist mir noch nicht ganz klar.
Wenn es nicht klappt, muss alles ausgeschlossen werden was stört.
m.E. geht irgendwas mit Deinen 50ms schief.

Was erwartest Du da?
Sind die 50ms sowas wie "debounce?
warum? Das braucht es doch nicht?
Du sendest doch auch keine 50ms lang ein 'P'

Erklär mir Deine Logik - dann wirds richtig einfach.

Die 50ms sind zum entprellen. Ich kann ja noch den Button-Sketch zeigen. Wird aber erst am Abend, bin gerade unterwegs.

Die brauchst doch nicht.

In Deinem Ursprungssketch liest Du von der Seriellen Schnittstelle ein Zeichen ein. Damit setzt Du eine Variable.
Diese Variable wird immer wieder ausgelesen und switcht dann zwischen play() und record() je nach Inhalt.

Das erste Auftreten setzt also den Inhalt.

Das macht das folgende genauso.


void loop()
{
  /*
    if (Serial.available() > 1) //Wenn etwas vom seriellen Monitor empfangen wird
    {
    incoming = Serial.read();
    if (incoming == 'R')
      Serial.println("Aufnahme gestartet......");
    if (incoming == 'P')
      Serial.println("Wiedergabe der aufgezeichneten Sequenz");
    }
  */
  if (!digitalRead(buttonR))
  {
    incoming = 'R';
  }
  if (digitalRead(buttonP))
  {
    incomming = 'P')
  }
  if (incoming == 'R') //Wenn der Benutzer den Aufnahmemodus gewählt hat
    Record();
  if (incoming == 'P') //Wenn der Benutzer den Wiedergabemodus ausgewählt hat
    Play();
}

Wenn ich das richtig verstehe muss ich zwei String mit R und P anlegen?

Ein Buchstabe ist etwas völlig anderes als ein String.

Auch wenn du die Version mit Serial nimmst: Serial.read() liefert keinen String, sondern einen Wert zwischen -1 und 255, der (im Fall von 0 .. 255) einem einzelnen Buchstaben entsprechen kann!

Ich bin jetzt dahinter gestiegen was du im loop machst. Habe dein
if (digitalRead(buttonP))
{
incomming = 'P')
}

in

if (digitalRead(buttonP))
{
incomming = 'P')
}
geändert. Jetzt spielt erst mal der Compiler nicht mehr verrückt.
Den Sketch habe ich damit aber trotzdem nicht zum laufen bekommen.

incoming = 'P';

Ja.
Und geht? geht nicht?
Was erwartest Du?

Da mir das Zitat gerade wieder gestrichen wurde und die Forensoftware meint, meine Zitate zu löschen und meine Posts als editiert zu markieren: NEIN! Das war ich nicht!

incoming = 'P';

Ja, das ist richtig.

Geht nicht. Auf jeden Fall nicht so. Ich glaube, du hast mich auf die richtige Spur gebracht.
incoming 'R' und incoming 'P' an die entprellten Taster, die Pause auf 80 erhöht und es läuft. :upside_down_face:

Welche entprellten Taster?
Das ist doch Unsinn.
Die Variable incomming wird genau einmal(!) mit dem Eintreffen des spezifierten Ereignis gesetzt.
Die wird danach NIE gelöscht.

Im Ausgangssketch:

Genau das wird abgebildet durch:

  if (!digitalRead(buttonR))
  {
    incoming = 'R';
  }
  if (digitalRead(buttonP))
  {
    incomming = 'P';
  }

Nichts mehr und nichts weniger. Und nichts anders.

Da brauch ich keine millis(). Nicht 1, nicht 5 und schon gar nicht 80.

Wenn Du jetzt da was gebaut hast, dann wäre der Zeitpunkt richtig zu zeigen was Du hast und wie das funktioniert.

FALSCH!

Richtig:

    if (!digitalRead(buttonP))
  {
    incomming = 'P')
  }

Das dürfte das Problem mit Deinen 80ms ggfls. auflösen.

Was du geschrieben hast, läuft bei mi nicht. habe loop geändert

void loop() {
  //aktuellen Schalter-Messwert lesen
  int gelesenR = digitalRead(buttonR);
  //...Wenn der Record-Schalter-Status sich geändert hat (durch drücken oder auch prellen)
  if (gelesenR != letzterButtonRStatus) {
    // setze den Timer zurück
    letzteAenderungR = millis();
  }
  if ((millis() - letzteAenderungR) > pause) {
    //Der aktuell-gelesene Wert kann nun als zuverlässig angesehen werden, da dieser länger als 50ms vorliegt.
    if (gelesenR != buttonRStatus) {  //falls sich der Status verändert hat...
      buttonRStatus = gelesenR;       //...setze diesen als buttonRStatus
      
      //...und starte Record, falls der Knopf gedrückt wurde
      if (buttonRStatus == HIGH) {
        incoming = 'R';
      }
    }
  }

   letzterButtonRStatus = gelesenR;
  
  //aktuellen Schalter-Messwert lesen
  int gelesenP = digitalRead(buttonP);
  //...Wenn der Record-Schalter-Status sich geändert hat (durch drücken oder auch prellen)
  if (gelesenP != letzterButtonPStatus) {
    // setze den Timer zurück
    letzteAenderungP = millis();
  }
  if ((millis() - letzteAenderungP) > pause) {
    //Der aktuell-gelesene Wert kann nun als zuverlässig angesehen werden, da dieser länger als 50ms vorliegt.
    if (gelesenP != buttonPStatus) {  //falls sich der Status verändert hat...
      buttonPStatus = gelesenP;       //...setze diesen als buttonRStatus
      
      //...und starte Play , falls der Knopf gedrückt wurde
      if (buttonPStatus == HIGH) {
        incoming = 'P';
      }
    }
  }
  
  letzterButtonPStatus = gelesenP;

  if (incoming == 'R') //Wenn der Benutzer den Aufnahmemodus gewählt hat
Record();

if (incoming == 'P') //Wenn der Benutzer den Wiedergabemodus ausgewählt hat 
Play();

}

jetzt läuft der Sketch.

Wenn dem so ist, dann schick.
Es ist nicht sinnvoll, Statusvariablen oder Zustände in int speichern zu wollen und es ist auch nicht sinnvoll das auslösende einmalige ändern eines Zustand in einer, mit was auch immer millis()-irgendwas abzuhandeln.
Insbesondere nicht mit 80 (!) ms Pause.

Zumal der Codeschnipsel das auch nicht hergibt. Da fehlt alles drum rum. Du hast da was vermischt - das funktioniert vielleicht jetzt.

willst Du nicht.

Dein Code, Deine Entscheidung.

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