Wie Lauflicht flüssiger machen auch wenn es langsam läuft ?

Hallo,

ich habe ein Lauflicht mit 4 LEDs. Ab der 2. bis 4. LED wird es dann immer dunkler. Man könnte Kometenschweif dazu sagen. Oder dünner werdende Schlange. Jetzt ist mein optisches Problem, wenn es langsam läuft, sodass man es schön verfolgen kann, dann ruckt das. Welchen Trick gibt es um selbst das flüssig zubekommen?

Vielleicht die LED die noch vor der ersten ist langsam heller werden lassen? Darf aber auch nicht gar zu weich sein, sonst ist der helle Punkt weg am Kopf. Nur wie die anderen "nachziehen" und das alles noch Geschwindigkeitsabhängig?

Wie schaut denn dein Setup bzw. dein Code aus?

Also ich würde versuchen jeweils die vorherige beim Wechsel nicht ganz aus schalten sondern vielleicht ca 1/4, evtl auch 2 LED nachglimmen lassen. Somit hast du die Kopf-LED immer voll da.

Bei dem Video sieht man das schön: 12 LED Knight Rider chase - YouTube

Hallo,

mein Lauflicht sieht eigentlich wie im Video aus. Nur das meins entweder immer rechts herum dreht oder links herums. Hat also keinen Anschlag zum Richtungswechsel. Wenn das im Video langsamer laufen würde, bin ich fest der Meinung das es auch optisch ruckt. Also von LED zu LED springen würde.

Mein Code sieht so aus. Für das Lauflicht sind die Funktionen void Kometenschweif_dreht_CW () und void Kometenschweif_dreht_CCW () verantwortlich. Die Geschwindigkeit wird durch das Array bestimmt. Das Array ersetzt zusammen mit millis() die blockierend wirkende delay Funktion. Zur Info das nichts verwechselt wird. Das Lauflicht dient als Showeffekt beim elektronischen LED würfeln.

// Arduino Mega 2560

// Würfelaugen LED Zusammenfassung (Methode von Erik Bartmann, o´reilly Verlag, Arduino entdecken
int GruppeA = 22;  // Port.A.22  LED Nr. 4 (mittelste)
int GruppeB = 23;  // Port.A.23  LED Nr. 1 + 7
int GruppeC = 24;  // Port.A.24  LED Nr. 3 + 5
int GruppeD = 25;  // Port.A.25  LED Nr. 2 + 6
int WuerfelAugen = 0;        // Wert zwischen 1 und 6

int TASTER = 2;              // Start-Taster zum würfeln, im Setup mit internen PullUp Widerstand aktiv
int TasterStatus = HIGH;            // Zustand vom Taster

// Geschwindigkeitssteigerung des Kometenschweifs bzw. abbremsen
int PAUSE [32] = {134,139,144,149,154,160,165,170,175,180,185,191,196,201,206,212,217,223,228,233,239,244,250,255,261,266,272,277,283,289,294,300};
int SPEED = 31;       

// Anfangsposition vom Kometenschweif
int LEDPOS_1 = 4;                      // auf sichere LED Position setzen für ersten Durchlauf
int LEDPOS_2 = 5;                      // auf sichere LED Position setzen für ersten Durchlauf
int LEDPOS_3 = 6;                      // auf sichere LED Position setzen für ersten Durchlauf
int LAST_LED = 3;                      // auf sichere LED Position setzen für ersten Durchlauf

int LED_1, LED_2, LED_3;               // zum zwischen speichern der LED Position zum umdrehen

unsigned long ZEIT_NEW = 0;            // Ersatzvariable für millis() um delay() zu ersetzen
unsigned long ZEIT_OLD = 0;            // Ersatzvariable für millis() um delay() zu ersetzen

int LED_H1 = 255;        // 255, Helligkeiten der LEDs     
int LED_H2 = 96;         //  96
int LED_H3 = 16;	 //  16											

boolean TASTER_Pressed = false;        // Taster Anfangsstatus definieren ( Wurde Taster gedrückt oder nicht? )

void setup()
{     
   Serial.begin(9600);

pinMode(TASTER, INPUT);           // Start-Taster zum würfeln und
digitalWrite(TASTER, HIGH);       // internen PullUp Widerstand aktiviert

// Pins 3 bis 6 für den Kometenschweif setzen
  for (int thisPin = 3; thisPin <= 6; thisPin++)  { 
    pinMode(thisPin, OUTPUT); 
   }

// Pins für die Würfelaugen setzen und kurz einschalten 
  DDRA = 15;       // Port.A, Bit 0 bis 3 Ausgang
  PORTA = 15;      // Port.A, Bit 0 bis 3 eingeschalten
  delay(500);
  PORTA = 0;       // Port.A alle Ausgänge Aus
  
//  Serial.println("\n[memCheck]"); 
//  Serial.println(freeRAM(), DEC);  

}

void loop()  {
  
  ZEIT_NEW = millis();                     // Millisekunden seit µC Start/Reset abfragen und merken
  
  TasterStatus = digitalRead(TASTER);      // Taster abfragen, wenn nicht gedrückt liegt HIGH Signal an

  if (TASTER_Pressed == true && TasterStatus == HIGH)  {
     Schweif_nach_links_umdrehen ();       // LEDs werden in der Reihenfolge umgedreht
     TASTER_Pressed = false;               // Hilfsvariable wird geändert  
    }

  if (TASTER_Pressed == false && TasterStatus == LOW)  {    
     Schweif_nach_rechts_umdrehen ();      // LEDs werden in der Reihenfolge umgedreht
     TASTER_Pressed = true;                // Hilfsvariable wird geändert
    }  

  if (TasterStatus == LOW)  {              // wenn Taster gedrückt wird liegt LOW Signal an
     Kometenschweif_dreht_CW ();           // Schweif dreht rechts herum und beschleunigt
     WuerfelAugen = random(1,7);           // solange Taster gedrückt ist, Zufallszahlen generieren
     //Serial.println(WuerfelAugen);         // zu Testzwecken
    }  
      
  if (TasterStatus == HIGH)  {             // wenn Taster nicht gedrückt wird liegt HIGH Signal an 
     Kometenschweif_dreht_CCW ();          // Schweif dreht links herum und bremst ab
    }

  if (TASTER_Pressed == true)  {
     Wuerfel_loeschen ();                  // Wuerfelaugen Anzeige löschen
    }  

  if (TASTER_Pressed == false)  {
     Wuerfelzahl_anzeigen (WuerfelAugen);          // Zahl der Würfelaugen mittels LEDs anzeigen
    }

 
}  // Loop Ende


/* ***  Funktionen  *** */

void Kometenschweif_dreht_CW ()  {                   // Kometenschweif dreht mit Uhrzeigersinn (rechts herum)
 
  if (ZEIT_NEW - ZEIT_OLD > PAUSE[SPEED])  {         // vorgegebene Zeit aus Array schon abgelaufen?
  
     if (LEDPOS_1 > 6) { LEDPOS_1 = 3; }             // wenn "letzte" LED erreicht, auf Anfangsposition setzen
     
     analogWrite(LEDPOS_1, LED_H1);                  // 5, Schweifspitze ganz hell                                    
     analogWrite(LEDPOS_2, LED_H2);                  // 4, LED dahinter etwas dunkler   
     analogWrite(LEDPOS_3, LED_H3);                  // 3, nächste LED noch dunkler                  
     analogWrite(LAST_LED, LOW);                     // letzte alte LED ausschalten
             
     LAST_LED = LEDPOS_3;                            // 3

     LEDPOS_3 = LEDPOS_2;                            // 4
     LEDPOS_2 = LEDPOS_1;                            // 5
     LEDPOS_1++;                                     // 6

     SPEED--;                                        // Kometenschweif beschleunigen
    if (SPEED < 1) { SPEED = 0; }                    // schnellsten Wert beibehalten
     
     ZEIT_OLD = ZEIT_NEW;                            // alte Zeit aktualisieren, Ersatz für delay()
   } 
                            
}


void Kometenschweif_dreht_CCW ()  {                  // Kometenschweif dreht entgegen Uhrzeigersinn (links herum)

  if (ZEIT_NEW - ZEIT_OLD > PAUSE[SPEED])  {         // vorgegebene Zeit aus Array schon abgelaufen?
     
     if (LEDPOS_1 < 3) { LEDPOS_1 = 6; }             // wenn "letzte" LED erreicht, auf Anfangsposition setzen

     analogWrite(LEDPOS_1, LED_H1);                  // Schweifspitze ganz hell                 
     analogWrite(LEDPOS_2, LED_H2);                  // LED dahinter etwas dunkler        
     analogWrite(LEDPOS_3, LED_H3);                  // nächste LED noch dunkler                      
     analogWrite(LAST_LED, LOW);                     // letzte alte LED ausschalten
             
     LAST_LED = LEDPOS_3;

     LEDPOS_3 = LEDPOS_2;
     LEDPOS_2 = LEDPOS_1;
     LEDPOS_1--;
          
     SPEED++;                                        // Kometenschweif abbremsen
     if (SPEED > 31) { SPEED = 31; }                 // langsamsten Wert beibehalten
     
     ZEIT_OLD = ZEIT_NEW;                            // alte Zeit aktualisieren, Ersatz für delay()
   }    
}
 

void Schweif_nach_links_umdrehen ()
{
     LED_1 = LAST_LED;             //5,  LED Positionen zwischen speichern
     LED_2 = LEDPOS_3;             //6
     LED_3 = LEDPOS_2;             //7

     LEDPOS_1 = LED_1;             //5,  LED Positionen umdrehen
     LEDPOS_2 = LED_2;             //6
     LEDPOS_3 = LED_3;             //7

     if (LEDPOS_3 >= 6) { LAST_LED = 3;}
       else { LAST_LED = LEDPOS_3 + 1; }  
}


void Schweif_nach_rechts_umdrehen ()
{
     LED_1 = LAST_LED;              //  LED Positionen zwischen speichern
     LED_2 = LEDPOS_3;             
     LED_3 = LEDPOS_2;        

     LEDPOS_1 = LED_1;              //  LED Positionen umdrehen
     LEDPOS_2 = LED_2;            
     LEDPOS_3 = LED_3;           

     if (LEDPOS_3 <= 3) { LAST_LED = 6;}
       else { LAST_LED = LEDPOS_3 - 1; }              
}


// Zahl der Würfelaugen mittels LEDs anzeigen
void Wuerfelzahl_anzeigen (int Augen)
{  
  if (Augen%2 != 0) {digitalWrite(GruppeA, HIGH);}     // ist der Augenwert ungerade ?  (Modulo, ist Restwert ungleich 0)
  if (Augen > 1)    {digitalWrite(GruppeB, HIGH);}     // ist der Augenwert größer 1 ?
  if (Augen > 3)    {digitalWrite(GruppeC, HIGH);}     // ist der Augenwert größer 3 ?
  if (Augen == 6)   {digitalWrite(GruppeD, HIGH);}     // ist der Augenwert gleich 6 ?
}


// Würfelaugen löschen
void Wuerfel_loeschen ()
{
   digitalWrite(GruppeA, LOW);             // Wuerfelaugen löschen
   digitalWrite(GruppeB, LOW);
   digitalWrite(GruppeC, LOW);
   digitalWrite(GruppeD, LOW);
}

     
int freeRAM()           //  Funktion im WWW gefunden, zeigt freien Speicher an
  { 
  extern int __heap_start, *__brkval;  
  int v;  
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
  }

Mensch Doc, das ist doch genau der Anwendungsfall für das Crossfading, welches wir hier vor 2 oder 3 Wochen ausgetüftelt haben: Du wechselst nicht hart zwischen den Schritten, sondern überblendest zwischen den beiden über n Schritte...

Gruß Helmuth

Hallo,

ach Helmuth, dass war mir schon wieder entfallen. Ich lese das nochmal durch. :wink:
Bin ja erstmal froh das der ganze Rest endlich so funktioniert wie gewünscht. Das Lauflicht ist die Kür.

Edit:
Hab nachgeschaut. Es ging bei uns (mir) damals um den PWM 0 auf 1 Effekt. Das Thema interessiert mich aktuell nicht. Jetzt geht es darum die Übergänge weicher zubekommen. Weil die 3 LEDs verschiedene Helliglkeiten haben, weiß ich nicht so recht wie ich die beim "laufen" faden soll.

Die erste LED ist immer volle Pulle PWM 255, die 2. LED ist PWM 96 und die 3. LED PWM 16 hell. Die 4. ist immer dunkel. Dieses Paket wandert immer im Kreis. Jetzt müßte ich die LED vor der 1. vielleicht in ganz kurzer Zeit mit 3 Zwischenstufen schnell heller werden lassen. In der gleichen Zeit die 1. dunkler auf den Wert der 2. und die 2. auf den Wert der 3. und die 3. ausklingen lassen.

Muß ich mir jetzt vielleicht gar 5 Zwischenwerte suchen und dann immer in 5 Durchgängen alle 3 LEDs ändern und dabei um eine Position vorschieben? Mir fehlt der Lösungsansatz wie man sowas generell richtig macht. Das soll ja Geschwindigkeitsunabhängig gut aussehen. Wenn meins jetzt schneller läuft sieht das auch gut aus. Wie im Video. Wenn es langsam läuft sieht es blöd aus.