Midi Noten senden, wenn sie in einem Bestimmten bereich des analog-Wert ist

Guten Tag

momentan sind wir an einem Kunst Projekt und bin mich dabei langsam in die Arduino Welt ein zu arbeiten, was mir sehr viel Spass bereitet. Aber ich bin immer noch Level Anfänger.

unsere Idee ist, mit einem Alkohol Messer ( MQ-3B; gas sensor von Grove) per MIDI einzelne Visuals an zu Steuern.
Das MIDI senden und empfangen Funktioniert mittlerweile gut (Arduino UNO, Hairless MIDI, loopMIDI, Resolume Avenue).
Nur habe ich momentan das Problem das in meinem zusammen geschnippeltem Sketch immer MIDI Signale gesendet werden und ich will nur bei einer Veränderung eines bestimmten Messbereich 1 MIDI befehl senden.

hier der modulierte Sketch, Vielleicht sieht man an dem was ich will und bestimmt noch eine einfachere Lösung für mein Problem.
Habe das Gefühl das ich mit irgendwelchen bereichen Arbeiten muss und einer bestimmten if Abfrage.

const int AOUTpin=0;//Der AOUT-Pin des Alkoholsensors geht in den analogen Pin A0 des Arduino über

int limit;
int value;
int noteOn = 144;





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

}

void loop()
{
value= analogRead(AOUTpin);//Liest den analaog-Wert vom AOUT-Pin des Alkoholsensors
  if(value<200) 
  {
      MIDImessage(noteOn, 60, 127);      
  }
  if (value>=200 && value<280)
  {
      MIDImessage(noteOn, 61, 127);      
  }
  if (value>=280 && value<350)
  {
      MIDImessage(noteOn, 62, 127);      
  }
  if (value>=350 && value <450)
  {
      MIDImessage(noteOn, 63, 127);      
  }
  if(value>450)
  {
      MIDImessage(noteOn, 64, 127);     
  } 

  {delay (2000);}
}

//send MIDI message
// MIDI-Nachricht senden
void MIDImessage (byte command, byte data1, byte data2) {
  Serial.write (command);
  Serial.write (data1);
  Serial.write (data2);
  
}

Vielen Dank für die Hilfe.
Andreas

merk dir in den ifs den zuletzt ausgegeben Ton (Bereich) und erweitere die If Bedingung so, dass nur bei einem abweichenden (anderen) Bereichen der Ton ausgegeben wird

ungeprüftes Muster:
int oldRange; // global definieren

  if(value<200 && oldRange != 1)     // zusätzliche Prüfung dass dieser Bereich nicht schon gegeben war
  {
      MIDImessage(noteOn, 60, 127); 
      oldRange = 1;  
  }

noiasca:

  if(value<200 && oldRange != 1)     // zusätzliche Prüfung dass dieser Bereich nicht schon gegeben war

{
      MIDImessage(noteOn, 60, 127);
      oldRange = 1; 
  }

Als Ergänzung: Dann muss oldRange aber auch wieder 0 gesetzt werden, und zwar wenn eine andere Note ausgegeben wurde. Sonst ertönt jeder ton nur genau ein mal nach jedem Programmstart.

nein das war nicht die Idee.
Der geneigte Leser möge obiges als Beispiel sehen und ähnliches IN JEDEM NOTWENDIGEN IF ergänzen.

Ich mach noch ein zweites als Beispiel

  if (value>=200 && value<280 && oldRange != 2)
  {
      MIDImessage(noteOn, 61, 127); 
      oldRange = 2;    
  }

es wäre aber schön wenn der TO sich meldet, ob er den Tipp versteht. Weil online wäre er jetzt ja ...

Danke Viel mal`s für die schnelle Hilfe

Habe den Sketch so angepasst und bis jetzt funktioniert es. Er ändert die Werte erst wenn ich den Sensor mit Alkohol bedampfe:-).

dies mit dem oldRage auf 0 verstehe ich nicht ganz. muss da stehen int old Range =0; oder so ?

Jetzt habe ich gemerkt das ich noch ein Problem habe. Die einzelnen Clips laufen immer eine bestimmte zeit. Das Problem ist jetzt das wenn ständig eine Veränderung kommt können die einzelnen Clips nicht bis ans ende laufen. Sprich das zu früh ein wechsel kommt. Theoretisch müsste es zu einer Veränderung kommen und dann bei der spitze so lange halten bis der Clip zu ende ist.

const int AOUTpin=0;//Der AOUT-Pin des Alkoholsensors geht in den analogen Pin A0 des Arduino über

int limit;
int value;
int noteOn = 144;
int oldRange; 





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

}

void loop()
{
value= analogRead(AOUTpin);//Liest den analaog-Wert vom AOUT-Pin des Alkoholsensors
  if(value<200 && oldRange != 1) 
  {
      MIDImessage(noteOn, 60, 127);
      oldRange = 1;      
  }
  if (value>=200 && value<280 && oldRange != 2)
  {
      MIDImessage(noteOn, 61, 127 ); 
      oldRange = 2;     
  }
  if (value>=280 && value<350 && oldRange != 3)
  {
      MIDImessage(noteOn, 62, 127);
      oldRange = 3;      
  }
  if (value>=350 && value <450 && oldRange != 4)
  {
      MIDImessage(noteOn, 63, 127);
      oldRange = 4;     
  }
  if(value>450 && oldRange != 5)
  {
      MIDImessage(noteOn, 64, 127);
      oldRange = 5;     
  } 

  {delay (2000);}
}

//send MIDI message
// MIDI-Nachricht senden
void MIDImessage (byte command, byte data1, byte data2) {
  Serial.write (command);
  Serial.write (data1);
  Serial.write (data2);
  
}

ja, ich würde sie auch mit 0 initialisieren.

ResBaechli81:
Die einzelnen Clips laufen immer eine bestimmte zeit. Das Problem ist jetzt das wenn ständig eine Veränderung kommt können die einzelnen Clips nicht bis ans ende laufen. Sprich das zu früh ein wechsel kommt. Theoretisch müsste es zu einer Veränderung kommen und dann bei der spitze so lange halten bis der Clip zu ende ist.

bekommst du irgendwo eine Information, dass der Clip zu ende ist? Wenn nicht, weist du die Länge vorher? Dann könntest ja einfache delays ans Ende der einzelnen Ifs packen. (Nicht ganz draußen im Loop).

Ps. Habe Tipp verstanden, musste ihn aber noch ausprobieren und bin noch an einem anderen Projekt
Lg :slight_smile:

Hallo nochmals von unterwegs

bekommst du irgendwo eine Information, dass der Clip zu ende ist? Könnte ich theoretisch. Wenn nicht, weist du die Länge vorher? Die länge weiss ich. Dann könntest ja einfache delays ans Ende der einzelnen Ifs packen. Dies ging mir auch durch den kopf(Nicht ganz draußen im Loop).

Melde mich gleich nochmals im zug

ich glaube ich brauche noch einen Sensor oder taste mehr.

Eigentlich sollte die Steuerung in etwa so ablaufen.

Mensch kommt betrunken, drückt Taste oder bedient ein hebel oder ein Distanz Messer Misst. jetzt weiß der Sketch Achtung scharf, dann messen messen messn bis peack und dann denn entsprechende MIDI befehl an den jeweiligen Clip, dann Delay so lange wie der Clip läuft oder jemand kommt pustet erneut in den Alkohol Messer.

in so etwa sollte es glaube ich sein.

lg

noiasca:
ja, ich würde sie auch mit 0 initialisieren.

bekommst du irgendwo eine Information, dass der Clip zu ende ist? Wenn nicht, weist du die Länge vorher? Dann könntest ja einfache delays ans Ende der einzelnen Ifs packen. (Nicht ganz draußen im Loop).

Ich glaube das Problem an den delays ist, das er ja immer der reihe nach durcharbeitet, sprich wenn ich zum beispiel einen Alkohol Pegel zwischen value>=280 && value<350 habe, wehren ja vorweg alle anderen Clips bis dahin im delay abgespielt und ich will ja nur den höchsten wert. Oder mache ich da einen denk Fehler?

na dann sortier deine Ifs halt um.

if(value>450 && oldRange != 5)

ganz rauf. dann 4, 3, 2, 1

Aber ein Ansteigen des Messwertes würde ich ohnehin annehmen.

in so etwa sollte es glaube ich sein.

die Anforderung muss schon du kennen.
Schreibe deine Anforderung nieder.
Umso kürzer die Sätze desto leichter tust du dich später beim Umsetzen in Code.
Zeichne ein Programmablaufplan.

noiasca:
na dann sortier deine Ifs halt um.

if(value>450 && oldRange != 5)

ganz rauf. dann 4, 3, 2, 1

Aber ein Ansteigen des Messwertes würde ich ohnehin annehmen.

die Anforderung muss schon du kennen.
Schreibe deine Anforderung nieder.
Umso kürzer die Sätze desto leichter tust du dich später beim Umsetzen in Code.
Zeichne ein Programmablaufplan.

ja dies könnte ich auch probieren. Ich werde es so machen das es in Resolume Avenue automatisch am Schluss in ein Standby Clip geht.

ich habe mit den Anforderung nur laut gedacht.
danke für den Tip mit dem Programmablauf zeichnen, mach momentan alles im Kopf.

habe den sketch mal so geschrieben, werde ihn heute Abend bei ein zwei Bier ausprobieren:-).
danke vorerst für die rasche und tolle Hilfe. melde mich wieder bei gelingen oder nichtgelingen.

const int AOUTpin=0;//Der AOUT-Pin des Alkoholsensors geht in den analogen Pin A0 des Arduino über

int limit;
int value;
int noteOn = 144;
int oldRange; 





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

}

void loop()
{
value= analogRead(AOUTpin);//Liest den analaog-Wert vom AOUT-Pin des Alkoholsensors
  
 if(value>450 && oldRange != 5)
  {
      MIDImessage(noteOn, 64, 127);
      oldRange = 5;
      delay (67800);
          
  } 
 if (value>=350 && value <450 && oldRange != 4)
  {
      MIDImessage(noteOn, 63, 127);
      oldRange = 4; 
      delay (60000);    
  }
 if (value>=280 && value<350 && oldRange != 3)
  {
      MIDImessage(noteOn, 62, 127);
      oldRange = 3;
      delay (60000);      
  }
 if (value>=200 && value<280 && oldRange != 2)
  {
      MIDImessage(noteOn, 61, 127 ); 
      oldRange = 2; 
      delay (60000);   
  }
 if(value<200 && oldRange != 1) 
  {
      MIDImessage(noteOn, 60, 127);
      oldRange = 1;
           
  }
  
}

//send MIDI message
// MIDI-Nachricht senden
void MIDImessage (byte command, byte data1, byte data2) {
  Serial.write (command);
  Serial.write (data1);
  Serial.write (data2);
  
}

noiasca:
nein das war nicht die Idee.

Ich mach noch ein zweites als Beispiel

  if (value>=200 && value<280 && oldRange != 2)

{
      MIDImessage(noteOn, 61, 127);
      oldRange = 2;   
  }

Achso! Ich dachte daran, für jede Range einen Boolean "OldRange_i" zu erstellen. Deine Idee finde ich aber besser, jetzt wo ich sie verstanden habe.

Da wir jetzt aber einen anderen Ablauf erläutert bekommen haben als im ersten Post: Dazu musst du eigentlich erst ein Programm laufen lassen, welches den maximalen Wert innerhalb einer Zeit misst (Bsp: Piepston oder LED als "Go", dann 5 Sek pusten, in dieser Zeit wird gemessen). Danach kommt erst das zweite Teilprogramm dran, welches entscheidet, in welcher Range der ermittelte Maximalwert liegt und welcher Ton abgespielt wird.

Dein Sketch macht stattdessen folgendes: Er nimmt den ersten Wert und spielt dann direkt die entsprechende Melodie und blockiert so lange weitere Messungen.

Eigentlich muss er eine ganze Messreihe mit verschiedenen Probanten fahren.

Vorschlag: Er lädt die Forumsschreiber zum Messtrinken ein und protokolliert die Werte. Er selbst muss dabei natürlich nüchtern bleiben :wink:

Gruß Tommy

ResBaechli81:
habe den sketch mal so geschrieben, werde ihn heute Abend bei ein zwei Bier ausprobieren:-).

Nach dem fünften kannst Du mal meine gerkürzte Version probieren (ungetestet):

const int AOUTpin = 0; //Der AOUT-Pin des Alkoholsensors geht in den analogen Pin A0 des Arduino über
const byte noteOn = 144;
uint32_t jetzt;

void setup() {
  Serial.begin(9600);
  pinMode (LED_BUILTIN, OUTPUT);
}
const uint16_t grenzen[] = {0, 200, 280, 350, 450, 1024};
const uint32_t pausen[] = {67800, 60000, 60000, 60000, 60000};
const byte message[] = {60, 61, 62, 63, 64};
const byte elemete = sizeof(message);

void loop()
{
  jetzt = millis();
  testeBereich();
  herzschlag();
}

void testeBereich() {
  static uint32_t vorhin, pause;
  static byte bereich = 255;
  if (jetzt - vorhin >= pause)
  {
    vorhin = jetzt;
    uint16_t wert = analogRead(AOUTpin); //Liest den analaog-Wert vom AOUT-Pin des Alkoholsensors
    for (byte b = 0; b < elemete; b++)
    {
      if (wert >= grenzen[b] && wert < grenzen[b + 1])
      {
        if (b != bereich)
        {
          bereich = b;
          MIDImessage(noteOn, message[b], 127);
          pause = pausen[b];
        }
      }
    }
  }
}

void herzschlag()
{
  static uint32_t vorhin;
  if (jetzt - vorhin >= 500)
  {
    vorhin = jetzt;
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
  }
}
// MIDI-Nachricht senden
void MIDImessage (byte command, byte data1, byte data2) {
    Serial.write (command);
    Serial.write (data1);
    Serial.write (data2);
}

Damit Du merkst, da läuft noch was, habe ich einen Herzschlag eingebaut.

Tommy56:
Vorschlag: Er lädt die Forumsschreiber zum Messtrinken ein und protokolliert die Werte. Er selbst muss dabei natürlich nüchtern bleiben :wink:

Gute Idee, als Schüler habe ich mal sowas gemacht, da mußte leider ich nüchtern bleiben, blöd gelaufen :disappointed_relieved:

na komm, jetzt hätt' ich aber schon ein schönes struct array von dir erwartet :wink:

bei b=4 wird er doch bei grenzen[b + 1]) über das Array hinauslesen oder?

noiasca:
bei b=4 wird er doch bei grenzen[b + 1]) über das Array hinauslesen oder?

Nö, grenzen[] ist ein Element größer als die anderen :grin:

noiasca:
na komm, jetzt hätt' ich aber schon ein schönes struct array von dir erwartet :wink:

Tut mir leid, Dich enttäuschen zu müssen, aber ich weiß nicht, wie ich das realisieren soll. Es hakt an grenzen[b + 1], da greife ich ja auf die nächste Grenze zu. Mir fehlt die Idee, wie ich das in einer Methode machen könnte. Und da ich dieses Thema nicht kapern möchte, halte ich mich zurück.

Schurke

(fürs längere Array ...hab ich übersehen)

Edit:
Wennst die For-Schleife umdrehst und bei einem Treffer verlässt dann könnte es vieleicht so aussehen:

const int AOUTpin = 0; //Der AOUT-Pin des Alkoholsensors geht in den analogen Pin A0 des Arduino über
const byte noteOn = 144;
uint32_t jetzt;

const uint16_t grenzen[] = {0,    200,  280,  350,  450};
const uint32_t pausen[] = {1000, 1200, 1300, 1400, 1500};
const byte message[] = {60, 61, 62, 63, 64};
const byte elemente = sizeof(message);

void setup() {
  Serial.begin(115200);
  pinMode (LED_BUILTIN, OUTPUT);
}

void loop()
{
  jetzt = millis();
  testeBereich();
  herzschlag();
}

void testeBereich() {
  static uint32_t vorhin, pause;
  static byte bereich = 255;
  uint16_t wert = analogRead(AOUTpin); //Liest den analaog-Wert vom AOUT-Pin des Alkoholsensors
  if (jetzt - vorhin >= pause)
  {
    vorhin = jetzt;
    for (int8_t b = elemente - 1; b >= 0; b--)
    {
      Serial.print("\nwert=");
      Serial.print(wert);
      Serial.print(" b=");
      Serial.print(b);
      Serial.print(" grenzen[b]=");
      Serial.print(grenzen[b]);
      if (wert >= grenzen[b])
      {
        if (b != bereich)
        {
          bereich = b;
          MIDImessage(noteOn, message[b], 127);
          pause = pausen[b];
          Serial.print(" -->neuer Bereich="); Serial.print(b);
          break;           // wir könnten hier aus dem For ausbrechen
        }
      }
    }
  }
}

void herzschlag()
{
  static uint32_t vorhin;
  if (jetzt - vorhin >= 500)
  {
    vorhin = jetzt;
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
  }
}
// MIDI-Nachricht senden
void MIDImessage (byte command, byte data1, byte data2) {
  //Serial.write (command);
  //Serial.write (data1);
  //Serial.write (data2);
}

In #15 habe ich einen Fehler bereinigt: analogRead() ein paar Zeilen runter, denn man muß das nur tun, wenn die Zeit abgelaufen ist.

noiasca:
na komm, jetzt hätt' ich aber schon ein schönes struct array von dir erwartet :wink:

Na gut, das mit den doppelten Grenzen habe ich nicht gelöst bekommen, aber etwas struct geht schon:

const int AOUTpin = 0; //Der AOUT-Pin des Alkoholsensors geht in den analogen Pin A0 des Arduino über
const byte noteOn = 144;
uint32_t jetzt;

// MIDI-Nachricht senden
void MIDImessage (byte command, byte data1, byte data2) {
  Serial.write(command);
  Serial.write(data1);
  Serial.write(data2);
}

struct Grenzen
{
  const uint16_t Min, Max;
  const uint32_t pausen;
  const byte message;

  Grenzen(const uint16_t Min, const uint16_t Max, const uint32_t pausen, const byte message)
    : Min(Min), Max(Max), pausen(pausen), message(message) {}

  void ausgabe(uint16_t wert, byte &m, uint32_t &p)
  {
    if (wert >= Min && wert < Max)
    {
      if (m != message)
      {
        m = message;
        MIDImessage(noteOn, message, 127);
        p = pausen;
      }
    }
  }
};

Grenzen grenzen[]
{
  //min, max, pause, message
  {0, 200, 1800, 60},
  {200, 280, 1000, 61},
  {280, 350, 1000, 62},
  {450, 1024, 1000, 64},
  {350, 450, 1000, 63},
};

void setup() {
  Serial.begin(9600);
  pinMode (LED_BUILTIN, OUTPUT);
}

void loop()
{
  jetzt = millis();
  testeBereich();
  herzschlag();
}

void testeBereich() {
  static uint32_t vorhin = 0;
  static uint32_t pause;
  static byte me;
  if (jetzt - vorhin >= pause)
  {
    vorhin = jetzt;
    uint16_t wert = analogRead(AOUTpin); //Liest den analaog-Wert vom AOUT-Pin des Alkoholsensors
    for (Grenzen &g : grenzen) g.ausgabe(wert, me, pause);
  }
}

void herzschlag()
{
  static uint32_t vorhin;
  if (jetzt - vorhin >= 500)
  {
    vorhin = jetzt;
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
  }
}

Zufrieden?

EDIT: (Grenzen &g : grenzen) siehe #23