Acties:
  • 0 Henk 'm!

  • Miepermans
  • Registratie: Oktober 2004
  • Niet online
Goedemorgen mede-tweakers.

Helaas loop ik de laatste tijd tegen een muur als het gaat om verbetering van mijn led verlichting in mijn gang.

Situatieschets;

* 7 meter WS2812 ledstrip ( 30 leds per meter )
* 1 Arduino UNO
* 1 Ethernet Shield

Wat er nu al wel werkt;

* de Arduino start op, en doet http get request naar server.
* de server returned ( A-Z of 1-0 ). ( ja hierdoor ben ik gelimiteerd tot 36 programma's )
* de Arduino parsed dit en start een programma, dit kan gewoon "rood","wit" of bijvoorbeeld brightness zijn. Ook heb ik diverse "Rainbow" programma's.
* Als het programma afgelopen is, blijft de Arduino om de seconde weer pollen of er een ander programma afgespeeld moet worden. Is er geen ander programma dan speelt hij het vorige dus weer netjes af.

Het "Probleem".

Ik wil graag data kunnen "pushen" naar de Arduino via Ethernet. bijvoorbeeld ook met een http get request met meerdere parameters. ik denk dan bijvoorbeeld aan "http://arduino/index.html?color=FF00FF&brightness=255" of "http://arduino/index.html?program=rainbow&speed=10"

Nu schuilt het probleem erin, dat als de Arduino een rainbow afspeelt dit een programma van bijvoorbeeld 30 seconden is.

Al die tijd kan ik geen requests verhelpen, dus als ik het programma zou willen wijzigen moet ik wachten totdat de rainbow afloopt en precies dan een request inschieten. Dit kreeg ik eerder niet werkend, vandaar nu het "pull" model waarbij ik het programma van de webserver afhaal.

Heeft iemand van jullie ooit al een soortgelijk iets gemaakt, en heeft iemand een hint hoe ik iets dergelijks kan bouwen? ik heb dit met een state-machine proberen op te lossen maar ben hierin rijkelijk gefaald omdat het rainbow programma een eigen "void" heeft waar hij niet uitbreekt.

Alvast bedankt voor jullie input! Ik ben hier al eens eerder geweest met een simpele vraag en ben toen echt super op weg geholpen.

P.s. ik zat al te denken om Artnet te gebruiken, echter is programma het dan niet eenvoudig met een commando vanaf een andere Arduino aan te passen. HTTP GET is veel meer gestandaardiseerd en daardoor ideaal.

Acties:
  • 0 Henk 'm!

  • Robbiedobbie
  • Registratie: Augustus 2009
  • Laatst online: 03-09 15:40
Ik weet niet hoe je "programma's" in elkaar steken. Ik neem voor nu aan dat het een beetje een sensible design is, en dat ieder programma gewoon een soort van update functie heeft, die in een loop gecalled wordt. die loop zou je dan moeten aanpassen om tussen iedere update in, te checken of er een request is binnen gekomen. Om die requests te ontvangen zul je een EthernetServer moeten draaien.

De loop zou er dan bijv zo uit gaan zien:
code:
1
2
3
4
5
6
7
while(programActive) {
    program.update();
    EthernetClient client = server.available();
    if (client) {
        //Get parameters from request and change program
    }
}

Acties:
  • 0 Henk 'm!

  • Springuin
  • Registratie: Juli 2002
  • Laatst online: 11-09 20:13
Je zult je programma om moeten schrijven zodat als hij moet wachten hij returned zodat je andere dingen kunt doen. Een statemachine is de juiste manier. Teken een flowdiagram voor jezelf om vast te stellen welke stappen er zijn. Geef al die stappen een naam en maak een switch/case constructie die op basis van de huidige staat bepaald of er wat moet gebeuren, wat er moet gebeuren en in welke staat je de volgende keer terecht wilt komen.

Als je moet wachten gebruik je geen delay maar schrijf je de tijd op (in een static of globale variable). De volgende keer kom je in een andere staat die checkt of er al voldoende tijd verstreken is. Zo niet: return, zo wel: doe je volgende ding.

Acties:
  • 0 Henk 'm!

  • Miepermans
  • Registratie: Oktober 2004
  • Niet online
Ik snap het nut van de state machine, en wil deze ook erg graag gebruiken. Echter een rainbow programma is een op zichzelf staande void welke het effect afspeelt en pas daarna weer returned.

Dit is de code voor het rainbow effect :

C:
1
2
3
4
5
6
7
8
9
10
11
void rainbow(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip.show();
    delay(wait);
  }
}


Die lijk ik niet te kunnen onderbreken, of zie ik dat verkeerd? Ik hoop dat zelfs met dit soort effecten wel mogelijk is om hiermee verder te gaan

Acties:
  • 0 Henk 'm!

  • joelluijmes
  • Registratie: Juli 2013
  • Laatst online: 28-12-2024
Miepermans schreef op zondag 21 juni 2015 @ 12:32:
C:
1
2
3
4
5
6
7
8
9
10
11
void rainbow(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip.show();
    delay(wait);
  }
}


Die lijk ik niet te kunnen onderbreken, of zie ik dat verkeerd? Ik hoop dat zelfs met dit soort effecten wel mogelijk is om hiermee verder te gaan
Als je meerdere dingen wilt uitvoeren zonder dat je wilt wachten op de huidige actie kun je heel simpel vergelijken of de verlopen tijd, sinds je bent gestart, langer duurder dan de huidige delay. Bijvoorbeeld een iets uitgebreider state machine:
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
static uint32_t start = 0;

uint16_t wifi_delay(uint8_t state)
{
    switch(state)
    {
    case WIFI_START:
    case WIFI_SEND:
        return 2; 
    case WIFI_GET:
        return 1; 
    case WIFI_CLOSE: 
        return 4; 
    case WIFI_RESET:
        return 2;
    }

    return 0;
}

void wifi_check(pin enable)
{
    static uint8_t state = WIFI_START;
    if (start == 0)
        start = timer_seconds();
    
    if (timer_seconds() - start < wifi_delay(state))
        return;

    start = timer_seconds();

    switch (state)
    {
    case WIFI_START:
        printf("AT+CIPSTART=\"TCP\",\"192.168.4.2\",80\n");
        state = WIFI_SEND;
        break;  
    case WIFI_SEND:
        printf("AT+CIPSEND=56\n");
        state = WIFI_GET; 
        break;
    case WIFI_GET:
        printf("GET /example/update.php?distance=%d&temperature=%d\n", reservoir, (int)(temperature*100.0)); 
        state = WIFI_CLOSE; 
        break;
    case WIFI_CLOSE:
        printf("AT+CIPCLOSE\n");
        state = WIFI_RESET; 
        break;
    case WIFI_RESET:
        state = WIFI_START;
        pin_low(enable); 
        _delay_ms(50); 
        pin_high(enable); 
        break;
    }
}


Is een stukje code uit een project wat ik onlangs heb geschreven, dit is overigens C (met avr-libc) zonder gebruik te maken van Arduino libraries.

Als de states sequentieel zijn (oplopend, dus in het bovenstaande voorbeeld; WIFI_START = 0x00; WIFI_SEND = 0x01... zou je geen gebruik te hoeven maken van een extra functie maar zou je deze dus kunnen uitmappen in een array.

Dit voorbeeld zou je in princiepe kunnen toepassen in jouwn eigen project, wat je nu dus in je program loop doet is elke keer de functie wifi_check(pin) aanroepen. De functie zelf handeld af met de benodigde delay en states.

Acties:
  • 0 Henk 'm!

  • jeroen3
  • Registratie: Mei 2010
  • Nu online
Je zult een superloop (eventloop) of anderzijds event driven moeten gaan werken.
Ipv elke functie blokkerend te maken, moet je zorgen dat ze niet meer blokkerend werken.
Vaak doe je dat met een state machine.

Het aanroepen van rainbow() doet één iteratie, ipv een for loop voor allemaal.
Dan gebruik je een timer (1 ms syteemtick) om te kijken of je rainbow alweer opnieuw moet uitvoeren.

voorbeeld:
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
ISR_SysteemTick(){
   systime++;
}

void main(){
   unsigned tijdstip1 = 10;
   unsigned tijdstip2 = 10;
   while(1){
      if( systime - tijdstip1 > 100 ){ // elke 100 ms 
         tijdstip1 = systime;
         rainbow();
      }
      if( systime - tijdstip2 > 100 ){ // elke 100 ms 
         tijdstip2 = systime;
         webserver();
      }
   }
}

Je snapt dat rainbow en webserver nu niet meer mogen "wachten" of lange lussen mogen uitvoeren.

Het andere alternatief is een preemptive (RT)OS, maar dat zal op een ATmega arduino wat lastiger zijn dan een ARM arduino. Dan kun je letterlijk twee grote while lussen maken die om-en-om processortijd krijgen.

Acties:
  • 0 Henk 'm!

  • Springuin
  • Registratie: Juli 2002
  • Laatst online: 11-09 20:13
Miepermans schreef op zondag 21 juni 2015 @ 12:32:
Die lijk ik niet te kunnen onderbreken, of zie ik dat verkeerd? Ik hoop dat zelfs met dit soort effecten wel mogelijk is om hiermee verder te gaan
Let maar eens op:

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
uint16_t rainbow_step = 0;
unsigned long lastupdate = 0;
// Returns true when rainbow is finished
bool rainbow(uint8_t wait) {
  uint16_t i;
  if (millis() - lastupdate >= wait) {
    // tijd is om
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+rainbow_step) & 255));
    }
    strip.show();
    // lastupdate bijwerken en volgende stap klaarzetten
    lastupdate = millis();
    rainbow_step++;
    if (rainbow_step >= 256) {
      // zodat we de volgende keer weer goed beginnen
      rainbow_step = 0;
      return true;
    }
  }
  return false;
}


Zo kun je je rainbow functie blijven aanroepen, totdat hij een keer true returned en dan weet je dat hij klaar is. Je kunt dan in je loop om en om je server en je leds afhandelen.

Acties:
  • 0 Henk 'm!

  • Miepermans
  • Registratie: Oktober 2004
  • Niet online
Wow Springuin ik wist niet dat dat kon. Gaaf!! Ik ga kijken of ik er zo nog aan toe kom. Dan hoef ik namelijk alleen nog maar te onderzoeken hoe ik die http get requests ga parsen, maar dat doe ik wel met switch/case.

Thanks!! Zo leer je elke dag wat bij

Acties:
  • 0 Henk 'm!

  • Steefph
  • Registratie: Juli 2002
  • Laatst online: 11-09 22:48
Je moet eens zoeken op led blinker zonder wait.

Hier staat precies beschreven hoe de Arduino hiermee om kan gaan ;)
(Zit ook bij de standaard voorbeelden "BlinkwithoutDelay" :P )

[ Voor 20% gewijzigd door Steefph op 21-06-2015 21:02 ]

Alles is terug te redeneren naar 4

Pagina: 1