Drehscheibe Modellbahn mit RF24

B: ist ein Paket der Drehbühne
S: ist ein Paket für die Steuerung

Im übertragenen Paket stehen nur Bytes, ja.
In deinem Sketch benutzt du die sprechenden Namen.

#include "dieEnumsDefsUndSo.h"

int16_t aktuellesGleis = 42;

  ...
  paket.send(steheAn, aktuellesGleis);

Und niemand zwingt dich aufeinanderfolgende und bei 0 startende Zahlen zu benutzen.

Bei Bytes z.B. bietet es sich an druckbare Zeichen zu verwenden,
dann kannst du den konstanten Header (alles vor dem Wert) einfach ausdrucken.

from könnte für die Drehbühne ein 'D' sein, die Sterung bekommt ein 'S',
der count könnte sich über 0-9A-Za-z bewegen,
's' stehe,
'o' OK
'!' fahreZu
'r' rechts
'l' links
...

Irgendwie finde ich die Variante so wie ich mir das gedacht habe für mich verständlicher.

Indem ich eine Zahl senden lasse und die je nach Größe auswerte:

von Sender zu Bühne
eine 0 für anhlten
von 1 bis 48 = Anzahl Schritte rechtsrum
101 bis 148 = Anzahl Schritte linksrum, z.B. 126-100 = 26 Schritte linksrum
255 = referenzfahrt starten
254 = reverenzfahrt beendet

von Bühne zu Sender
0 = Ziel erreicht
1 - 47 = restliche Schritte

So hatte ich es mir gedacht.

Dann mach es so.

Ich wollte dich nicht verärgern. Vielleicht begreife ich es irgendwan. Ich (denke) ich verstehe worauf du/ ihr hinaus wollt. Es geht darum das man das übertragene in meiner Variante nicht einfach lesen kann, da man ja nur mit Zahlen arbeitet. Bei eurer Variante würde man alles im Klartext übertragen. Oder denke ich falsch?

Acki1985:
Es geht darum das man das übertragene in meiner Variante nicht einfach lesen kann, da man ja nur mit Zahlen arbeitet. Bei eurer Variante würde man alles im Klartext übertragen. Oder denke ich falsch?

Offensichtlich hast du #193 vom Today at 22:25:28 entweder nicht gelesen, oder nicht verstanden.
Man kann beides haben, sprechende Namen und (nahezu) druckbare Pakete,
mit fast minimaler konstanter Größe.

Und niemand zwingt dich irgendetwas wie vorgeschlagen zu machen.

Die eigentliche Kommunikation solltest du ja jetzt hinbekommen, was du hin und her schickst
ist ja völlig wurscht und muss nur dir passen.

Dass ich anscheinend nicht in der Lage bin zu vermitteln wie man simpel, bequem, robust und
nicht-blockierend Kommunikationen zwischen Netztwerkknoten implementieren kann, ist nur etwas irritierend.

Vielleicht hat ja der ein oder andere Mitleser etwas damit anfangen können.

Ich habe zwar keine Eisenbahn, aber ein paar NRF Knoten. :wink:

Hi

Mir fehlt Beides - wobei so NRF-Dinger hier zwei rumliegen müssten ...

@Whandall
Ich bin der Überzeugung, daß Deine Erklärungen schon noch zünden werden, zumindest ich fand Sie durchaus eingängig.

@Acki
Wenn Deine Kommunikation funktioniert, dann soll Das doch auch ok sein!
Mehr muß nicht - für spätere Wartung oder Erweiterbarkeit wären halt sprechende Namen oder übertragbare weitere Informationen einfacher - wobei, eigentlich unabdingbar.
Wenn es jetzt noch nicht so weit sein soll, dann eben noch nicht - Dir reißt hier Keiner den Kopf ab, wenn Deine Drehbühne nach Deinen Vorstellungen fährt und eben genau so mit Dir via Funk schwätzt.

MfG

Guten morgen alle zusammen,

ich habe mir das mit dem enum noch mal durch den Kopf gehen lassen und noch mal danach gesucht und bin auf volgende Seite gestoßen : proggen.org - Enumerations - Raum für Ideen

Hab mir diese Seite durchgelesen. Wenn ich das richtig verstanden habe, kann ich am Anfang den Bestandteilen der Aufzählung je einen Wert zuweisen: Z.B.

 enum zustaende
{
  rev_start = 255,
  rev_ende = 254,
  nothalt = 0,
  alte_pos = 1,
  neue_pos = 1,
  restl_schritte = 0,
  rechts = 0,
  links = 0
};

Habe ich das so richtig verstanden?

Dann kann ich in den Abfragen mit den bezeichnungen direkt arbeiten Z.B.
neue_pos = 10

Kann man dieses enum dann auch direkt versenden?

Hi

Nein

Das ist kein struct, sondern NUR eine Aufzählung verschiedener Zustände.
Eigentlich dürfte Das So auch nicht kompilieren?!?
Habe Es noch nicht probiert, aber müssen die Zahlen nicht unterschiedlich sein?

Aber ein struct nimmst Du eh, um die ganzen Informationen aufzunehmen, unter Anderem auch den Zustand (und davon KANN Es immer nur Einen geben - und Deine 0 wäre links, rechts, restl_schritte und nothalt - ich sehe dort eine Mehrdeutigkeit.

MfG

Hm dachte ich habe es verstanden... Nagut dann werde ich es mit der Zahlenmethode machen.

So habe mal wieder ein Bisschen was gemacht. Hab mal im Sender versucht das Programm für die Referenzfahrt zu programmieren. Aber leider empfängt die Bühne nichts...

Hier mal der Code vom Sender:

#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
#include <SPI.h>
#include "RF24.h"
RF24 radio (A4, A5);
byte address[] [6] = {"pipe1", "pipe2"};
const byte sensor_referenz = 2;                   // Pin für Sensor Referenz aussen an der Grube (Nullstellung)
int status_sensor_referenz;                       // Speichervariable für Status von Sensor für Referenzfahrt
byte befehl [8];

// Statusvariablen
bool nullStellung = false;                      // Speichervariable ob Referenzfahrt erfolgt ist
bool referenzFahrt_b = true;                      // Speichervariable ob Referenzfahrt gestartet oder beendet wurde
void setup() {
  pinMode(sensor_referenz, INPUT);
  /Serial.begin(9600);
  radio.begin();
  radio.openReadingPipe(1, address[0]);
  radio.openWritingPipe(address[1]);
  radio.setPALevel (RF24_PA_MAX);
  radio.setDataRate (RF24_250KBPS);
  radio.setChannel (110);
  radio.startListening();
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("Drehscheiben-");
  lcd.setCursor(0, 1);
  lcd.print("steuerrung");
  delay (2000);
 
}

void loop() {
//  daten_empfangen();
  referenzFahrt();
  //encoder_lesen();
  //schritte_berechnen();
  //wenden();
  //nothalt();
}

void referenzFahrt() {
  //Serial.println(nullStellung);
  //Serial.println(status_sensor_referenz);
  //Serial.println(referenzFahrt);
  
  status_sensor_referenz = digitalRead (sensor_referenz);
  if ((nullStellung == false) && (status_sensor_referenz == HIGH) && (referenzFahrt_b == true)) {
    referenzFahrt_b = false;
    befehl[0] = 255;
    radio.stopListening();
    radio.write(&befehl[0], sizeof(byte));
    radio.startListening();
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Referenzfahrt");
    lcd.setCursor(0, 1);
    lcd.print("gestartet");
    Serial.println(befehl[0]);
    }
  else if ((nullStellung == false) && (status_sensor_referenz == LOW)) {
    referenzFahrt_b = true;
    nullStellung = true;
    befehl[0] = 254;
    radio.stopListening();
    radio.write(&befehl[0], sizeof(byte));
    radio.startListening();
    lcd.setCursor(0, 1);
    lcd.print("beendet   ");
    Serial.println(befehl[0]);
  }
}

und der Code von der Bühne:

#include <SPI.h>
#include "RF24.h"

unsigned long warteZeit; 
int data[1];
boolean var = true;
//const byte addresses[][6] = {"00001", "00002"};
//const uint64_t pipe = 0xF0F0F0F0A1LL;
RF24 radio (8, 9);
byte address[] [6] = {"pipe1", "pipe2"}; // Adressen der beiden Pipes
byte rever_start = false;
const byte hal = 3;
byte schritte[1];                                 // Schritte die deer Motor (Hallsensor betätigt) zurücklegen muss
int sensor = LOW;
unsigned long startZeit;                          // Abfrage begin Sensor an Bühne
unsigned long interval = 2000;                    // Zeitabstand nachdem ein Zustand des Sensors erkannt wird
unsigned long vergangeneZeit = 0;                 // Speichervariable um die Vergangene Zeit zu speichern
/*int pin_motor_links = A1;                         // Richtungspin an H-Brücke für Links
int pin_motor_rechts = A2;                        // Richtungspin an H-Brücke für Rechts
*/
// Statusvariablen
bool nullStellung = false;                      // Speichervariable ob Referenzfahrt erfolgt ist
bool ergebnis = false;                          // Berechnung der Schritte und Richtung beendet/gestartet
bool start = false;                           // Schritte Zaehlen beendet/gestartet

void setup() {
  radio.begin();
  //radio.openReadingPipe(1, pipe);
  radio.openWritingPipe(address[1]); // 00001
  radio.openReadingPipe(1, address[0]); // 00002
  radio.setPALevel(RF24_PA_MAX); 
  radio.setDataRate (RF24_250KBPS);
  radio.setChannel(110);
  
  radio.startListening();
  pinMode(hal, INPUT);
  Serial.begin(9600);
  //delay (2000);
  }

void loop() {
 
  referenzFahrt();
  encoder_lesen();
  schritteZaehlen();
  }

void referenzFahrt() {
  if (radio.available())
{
Serial.println("Data there");
radio.read(data, 1);
Serial.println(data[0]);
}

      // Reverenzfahrt

      if ((data[0] == 255) && (rever_start == false) && (nullStellung == false)) { 
        rever_start = true;
        Serial.println("Reverenzfahrt gestartet");
    //    digitalWrite (pin_motor_rechts, HIGH);
      //  digitalWrite (pin_motor_links, LOW);
      }
      else if ((data[0] == 254) && (rever_start == true)) {
        nullStellung = true;
        rever_start = false;
        Serial.println("Reverenzfahrt beendet");
        Serial.println (" ");  
  //      digitalWrite (pin_motor_rechts, LOW);
//        digitalWrite (pin_motor_links, LOW); 
      }
    }
  
  void encoder_lesen () {
   if ((data[0] <= 48) && (data[0] > 0) && (nullStellung == true) && (ergebnis == false)) {
    //rechtsrum data[0] Schritte 
    schritte[0] = data[0];
    ergebnis = true;
    // Motor
    Serial.println (schritte[0]);
    Serial.print ("  Schritte nach Rechts"); 
    Serial.println (" ");   
   }
  else if ((data[0] >=100) && (data[0] <= 149) && (nullStellung == true) && (ergebnis == false)) {
    //linksrum data[0] - 100 Schritte
    schritte[0] = data[0] - 100;
    ergebnis = true;
    // Motor
    Serial.println (schritte[0]);
    Serial.print ("  Schritte nach links");
    Serial.println (" ");
   }
  }
 
void schritteZaehlen () {

  sensor = digitalRead (hal);
  startZeit = millis();
  if ((schritte[0] != 0) && (ergebnis == true)) {
    start = true;
    if ((startZeit - vergangeneZeit >= interval) && (sensor == LOW) && (start == true)) {
      vergangeneZeit = startZeit;
      schritte[0]--;
      Serial.println("Drehung start");
      Serial.println("Restl. Pos.");
      Serial.println(schritte[0]);
      radio.stopListening(); 
      radio.write (&schritte, sizeof (schritte));
      radio.startListening();
      }
  }
  else if ((schritte[0] == 0) && (start == true)) {
    start = false;
    ergebnis = false;
    data[0] = 0;
    Serial.println("Ziel");
    Serial.println("Drehung");
    Serial.println("beendet");
    Serial.print("daten");
    Serial.println(schritte[0]);
    radio.stopListening();
    radio.write (&schritte, sizeof (schritte));
    radio.startListening();
    //schritte[0]=0;
    
    Serial.println(ergebnis);
    }
}

Die Bühne empfängt nichts vom Sender. Kann mir jemand helfen woran es liegt?

Gruß Acki

Hi

Warum machst Du Dir Dein Leben so schwer?
Du hattest einen funktionierenden Code - ohne Funk.
Nun willst Du Funk dazu 'bauen' - aber warum packst Du Alles nur Denkbare in den funktionierenden Sketch?
Du willst, daß die Bühne auf Funk reagiert - dann baue EINE Funktion dafür.
Wenn von Der als Rückgabe 'Ja, habe was empfangen' kommt, kannst Du damit Dein schon bestehendes Programm triggern.
Auch sollte Dein Sketch so ausgesehen haben, daß loop() möglichst schnell durchlaufen wird.
Bei JEDEM Durchlauf rufst Du auch eine Funktion auf, Die den Status via Funk sendet.
In dieser Funktion entscheidest Du JEDES MAL NEU, ob jetzt wirklich gesendet werden soll/muss.

Du bekommst also zwei zusätzliche Funktions-Aufrufe in loop() - mehr nicht.
Wenn Deine vorherige Steuerung feste Pins abgefragt hat, ob eben ein neues Ziel angefahren werden soll, musst Du Das um die Möglichkeit erweitern, Das auch von Deiner Funk-Funktion auslosen zu können - mir schwebt dort ein 'funkstatus' vor.
Also eine Status-Variable, Die gerne auch mit enum-Begriffen beschickt werden darf.

MfG

Du meinst also ich soll den Sketch so lassen wie er ist und Parallel dazu die Funkfunktion (senden, empfangen) einbauen? Habe ich das so richtig verstanden? Also auf den Sender und die Bühne den gleichen Sketch und dann eben den Funk dazu?

Hi

Der Sender wird wohl keine Bühnen-Komponenten brauchen.
Die Bühne braucht aber neben der schon vorhandenen Funktionalität 'nur' die zusätzlichen Möglichkeiten.
Das Senden und Empfangen geht 'nebenher' - sofern der Bühnensketch nicht auf WHILE und delay() basiert :wink: .
Du musst 'nur' im Bühnen-Sketch diese zusätzlichen Eingaben mit verarbeiten.
Wenn Du vorher das neue Zielgleis via Terminal eingegeben hast, kommt jetzt das Ziel eben via Terminal ODER via Funk.
Nach Beiden ist dann, auf magische Art und Weise, die Zielgleis-Nummer eine Andere.
Der Bühnen-Sketch erkennt Das, berechnet die Drehrichtung, startet den Motor, ... also den ganzen Kram, Den Er vorher auch schon gemacht hat.

Zusätzlich wird halt bei jedem loop()-Durchlauf geprüft, ob man Status-Daten senden muss/kann.
Du wirst nicht 1000 Mal die Sekunde 'Bin auf Gleich 1, drehe rechts rum' senden müssen.
Das reicht 1x die Sekunde (millis() ist Dein Freund) oder, wenn sich was geändert hat.
Bei Stillstand z.B. muß die Bühne gar nicht schwätzen, wenn auch hier die Sende-Funktion 1000x die Sekunde aufgerufen wird.

Was löst bisher eine Drehung aus?
Genau DA solltest Du ansetzen, DAS sollte auch der Funk verändern.
Wie stoppst Du die Bühne aktuell? DA greift auch der Funk für den Nothalt mit zu.

MfG

Aber das hatte ich doch versucht. Wollte das wenn ich den Sender einschalte eine 255 Senden das die Bühne die Referenzfahrt startet. Wenn der Referenzpunkt erreicht ist wollte ich eine 254 Senden. Aber bei der Bühne kommt nix an. Der Bühnencode ist ja noch genau so wie wie ich es mit Test Sendesketch versucht habe. Mit dem hat es auch funktioniert. Nur mit dem jetzigen Sender Sketch funktioniert es nicht.
Nur warum?

Gruß Acki

Guten Abend,

ich möchte an der Steuerung weiter bauen.
Könnt ihr mir sagen warum der Arduino in der Bühne nur die meistens nur einmal die 255 empfängt obwohl ich sie dauerhaft sende?

#include <SPI.h>
#include "RF24.h"

unsigned long warteZeit; 
int data[1];
boolean var = true;
//const byte addresses[][6] = {"00001", "00002"};
//const uint64_t pipe = 0xF0F0F0F0A1LL;
RF24 radio (8, 9);
byte address[] [6] = {"pipe1", "pipe2"}; // Adressen der beiden Pipes
byte rever_start = false;
const byte hal = 3;
byte schritte[1];                                 // Schritte die deer Motor (Hallsensor betätigt) zurücklegen muss
int sensor = LOW;
unsigned long startZeit;                          // Abfrage begin Sensor an Bühne
unsigned long interval = 2000;                    // Zeitabstand nachdem ein Zustand des Sensors erkannt wird
unsigned long vergangeneZeit = 0;                 // Speichervariable um die Vergangene Zeit zu speichern
/*int pin_motor_links = A1;                         // Richtungspin an H-Brücke für Links
int pin_motor_rechts = A2;                        // Richtungspin an H-Brücke für Rechts
*/
// Statusvariablen
bool nullStellung = false;                      // Speichervariable ob Referenzfahrt erfolgt ist
bool ergebnis = false;                          // Berechnung der Schritte und Richtung beendet/gestartet
bool start = false;                           // Schritte Zaehlen beendet/gestartet

void setup() {
  radio.begin();
  
  radio.startListening();
  pinMode(hal, INPUT);
  //radio.openReadingPipe(1, pipe);
  radio.openWritingPipe(address[1]); // 00001
  radio.openReadingPipe(1, address[0]); // 00002
  radio.setPALevel(RF24_PA_MAX); 
  radio.setDataRate (RF24_250KBPS);
  radio.setChannel(110);
  Serial.begin(9600);
  //delay (2000);
  }

void loop() {
 
  referenzFahrt();
  encoder_lesen();
  schritteZaehlen();
  }

void referenzFahrt() {
  if (radio.available())
{
Serial.println("Data there");
radio.read(data, 1);
Serial.println(data[0]);
}

      // Reverenzfahrt

      if ((data[0] == 255) && (rever_start == false) && (nullStellung == false)) { 
        rever_start = true;
        Serial.println("Reverenzfahrt gestartet");
    //    digitalWrite (pin_motor_rechts, HIGH);
      //  digitalWrite (pin_motor_links, LOW);
      }
      else if ((data[0] == 254) && (rever_start == true)) {
        nullStellung = true;
        rever_start = false;
        Serial.println("Reverenzfahrt beendet");
        Serial.println (" ");
        //data [0] = 0;  
  //      digitalWrite (pin_motor_rechts, LOW);
//        digitalWrite (pin_motor_links, LOW); 
      }
    }
  
  void encoder_lesen () {
   if ((data[0] <= 48) && (data[0] > 0) && (nullStellung == true) && (ergebnis == false)) {
    //rechtsrum data[0] Schritte 
    schritte[0] = data[0];
    ergebnis = true;
    // Motor
    Serial.println (schritte[0]);
    Serial.print ("  Schritte nach Rechts"); 
    Serial.println (" ");   
   }
  else if ((data[0] >=100) && (data[0] <= 149) && (nullStellung == true) && (ergebnis == false)) {
    //linksrum data[0] - 100 Schritte
    schritte[0] = data[0] - 100;
    ergebnis = true;
    // Motor
    Serial.println (schritte[0]);
    Serial.print ("  Schritte nach links");
    Serial.println (" ");
   }
  }
 
void schritteZaehlen () {

  sensor = digitalRead (hal);
  startZeit = millis();
  if ((schritte[0] != 0) && (ergebnis == true)) {
    start = true;
    if ((startZeit - vergangeneZeit >= interval) && (sensor == LOW) && (start == true)) {
      vergangeneZeit = startZeit;
      schritte[0]--;
      Serial.println("Drehung start");
      Serial.println("Restl. Pos.");
      Serial.println(schritte[0]);
      radio.stopListening(); 
      radio.write (&schritte, sizeof (schritte));
      radio.startListening();
      }
  }
  else if ((schritte[0] == 0) && (start == true)) {
    start = false;
    ergebnis = false;
    data[0] = 0;
    Serial.println("Ziel");
    Serial.println("Drehung");
    Serial.println("beendet");
    Serial.print("daten");
    Serial.println(schritte[0]);
    radio.stopListening();
    radio.write (&schritte, sizeof (schritte));
    radio.startListening();
    //schritte[0]=0;
    
    Serial.println(ergebnis);
    }
}

Hier noch der Code vom Sender:

Sender.ino (9.19 KB)

Warum fügst Du den nicht hier ein? Wenn er zu lang ist, hänge ihn als Attachment ran.

Gruß Tommy

Hallo Tommy,

danke dir für den Tip. hab es geändert.