Arduino - Programmierung

  • Seite 2 von 10
29.06.2023 11:01
#16
avatar

Der Code ist sehr interessant.

Mir fällt dein flush an diversen Stellen auf. Du rufst an verschiedenen Stellen ein flush auf, jedoch außerhalb der Funktion wo ein Midi Befehl gesendet wird. Beispiel noteOn erstellt ein Befehl und da wäre es logisch, wenn es sofort gesendet werden soll auch unmittelbar vor verlassen der Funktion ein flush zu machen, anstatt irgendwo anders.

Bei deiner Lösung zum entprellen musst du etwas aufpassen. millis läuft nach einer gewissen Zeit über und beginnt dann wieder bei 0. Soweit ich weiß sind es wohl etwa 50 Tage. Im Normalfall also bei einem Spieltisch nicht relevant. Aber wenn z.B der USB Anschluss weiter Strom liefert, dann hättest du diese Zeit irgendwann erreicht und wunderst dich, warum es nicht mehr funktioniert. Entweder nutze eine andere Möglichkeit, oder setze im Loop eine Kontrolle ein, ob es zu einem Überlauf gekommen ist. Wenn millis bei einer Abfrage plötzlich kleiner ist als vorher, dann hat wohl ein Überlauf stattgefunden und du solltest alles zurücksetzen. Wie gesagt, wird vermutlich nicht relevant sein, aber wenn es doch einmal passiert, dann stehst du erst einmal auf dem Schlauch :)

Zum entprellen kannst du auch fertige Bibliotheken wie Bounce2.h nutzen. Die von dir genannten Keypad Helfer haben das meist auch schon mit drinnen. Ich habe damit jedoch eher negative Erfahrungen gemacht, da diese Bibliotheken oft wenig flexibel sind und einige können auch nur eine einzige Matrix abfragen. Hast du mehrere oder geteilte, dann stößt man dort an die Grenzen.

Auf der anderen Seite wird der Code extrem schlank, hier ein Beispiel für die sichere Abfrage auf einem Pi Pico mit Python:

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
 
# Importe
# =======
import time
import board
import busio
import usb_midi
import keypad
 
import adafruit_midi
from adafruit_midi.note_off import NoteOff
from adafruit_midi.note_on import NoteOn
from adafruit_bus_device.i2c_device import I2CDevice
 
from digitalio import DigitalInOut, Direction, Pull
 
# Variablen
#==========
midiChannelOut = 1
midiChannelIn = 1
 
midi = adafruit_midi.MIDI(midi_out=usb_midi.ports[midiChannelIn], out_channel=midiChannelOut)
 
# Pins für die Tastenmatrix
km = keypad.KeyMatrix(
row_pins=(board.GP0, board.GP1),
column_pins=(board.GP2, board.GP3, board.GP4),
)
 
# Midi Keycode für die dazugehörige Taste
KEYCODE = (51, 52, 53, 54, 55, 56)
 
# sendNoteOn sendet ein NoteON mit den übergebenen
# Parameter
def sendNoteOn(keycode, velocity=127):
midi.send(NoteOn(keycode, velocity))
 
# sendNoteOn sendet ein NoteON mit den übergebenen
# Parameter
def sendNoteOff(keycode, velocity=0):
midi.send(NoteOff(keycode, velocity))

# Hauptschleife
while True:
event = km.events.get()
if event:
sendNoteOn(KEYCODE[event.key_number]) if event.pressed else sendNoteOff(KEYCODE[event.key_number])
 



Kompakter geht es wohl nicht mehr :)


 Antworten

 Beitrag melden
29.06.2023 11:46
#17
So

Zitat von Christian_Hofmann im Beitrag #122
Der Code ist sehr interessant.

Haha, klingt nicht wie ein Kompliment


Zitat von Christian_Hofmann im Beitrag #122

Mir fällt dein flush an diversen Stellen auf. Du rufst an verschiedenen Stellen ein flush auf, jedoch außerhalb der Funktion wo ein Midi Befehl gesendet wird. Beispiel noteOn erstellt ein Befehl und da wäre es logisch, wenn es sofort gesendet werden soll auch unmittelbar vor verlassen der Funktion ein flush zu machen, anstatt irgendwo anders.

Das Flush habe ich mal aus einem Code, den ich als Vorlage benutzt habe, übernommen. Habe damit herumexperimentiert und absolut keine Änderung festgestellt. Als ich jetzt mit der Matrix getestet habe, hat die Herausnahme des Flush Befehls die Situation eher verschlechtert, meine Wahrnehmung nach. Aber kann auch Quatsch sein. Die Frage ist ja, ob der Puffer gesendet wird, wenn er voll ist oder auch in regelmäßigen Abständen. Wenn letzteres, dann fällt es sich gar nicht ins Gewicht. Aber sogar die ehrwürdige Sabine arbeitet mit Flush!

Die Frage ist ja, ob man den Befehl nach Aufruf einer Funktion setzt oder in der Funktion. An sich dürfte es ja keinen Unterschied machen, da man nach Ende der Funktion doch in den Loop an die Stelle zurückkehrt, von wo die Funktion aufgerufen wurde.


Zitat von Christian_Hofmann im Beitrag #122

Bei deiner Lösung zum entprellen musst du etwas aufpassen. millis läuft nach einer gewissen Zeit über und beginnt dann wieder bei 0. Soweit ich weiß sind es wohl etwa 50 Tage. Im Normalfall also bei einem Spieltisch nicht relevant. Aber wenn z.B der USB Anschluss weiter Strom liefert, dann hättest du diese Zeit irgendwann erreicht und wunderst dich, warum es nicht mehr funktioniert. Entweder nutze eine andere Möglichkeit, oder setze im Loop eine Kontrolle ein, ob es zu einem Überlauf gekommen ist. Wenn millis bei einer Abfrage plötzlich kleiner ist als vorher, dann hat wohl ein Überlauf stattgefunden und du solltest alles zurücksetzen. Wie gesagt, wird vermutlich nicht relevant sein, aber wenn es doch einmal passiert, dann stehst du erst einmal auf dem Schlauch :)


Millis läuft nach 50 Tagen (oder 70 wie arduino.cc schreibt) über. Da ich jeden Abend alles stromlos mache (also Kippschalter an Steckdosenleiste, fällt das gar nicht ins Gewicht. Das würde selbst mit micros() gehen, die nach 30 Stunden überlaufen ;-)


Zitat von Christian_Hofmann im Beitrag #122

Zum entprellen kannst du auch fertige Bibliotheken wie Bounce2.h nutzen. Die von dir genannten Keypad Helfer haben das meist auch schon mit drinnen. Ich habe damit jedoch eher negative Erfahrungen gemacht, da diese Bibliotheken oft wenig flexibel sind und einige können auch nur eine einzige Matrix abfragen. Hast du mehrere oder geteilte, dann stößt man dort an die Grenzen.


Ich habe mich aus ähnlichen Gründen auch zunächst gegen Keypad entschieden, zumal ich irgendwo gelesen hatte, dass diese Lib nur bis 8 gleichzeitig gedrückte Tasten unterstützt. Das ist mir zu wenig, wenn es doch mal drauf ankommt und Reger o.ä. es mal wieder völlig übertreiben. Aber zum testen und Fehler ausschließen (und etwas schlauer werden) wollte ich trotzdem mal einen solchen Code aufsetzen.

Die Bounce Bibliothek schaue ich mir mal an. Auch probiere ich nochmal mit den Delays an verschiedenen Stellen und dem Flush Befehl herum. Es muss doch zu schaffen sein, andere haben das schließlich auch gepackt :-)


 Antworten

 Beitrag melden
29.06.2023 12:08
#18
avatar

Zitat von Brassmann im Beitrag #123
Aber sogar die ehrwürdige Sabine arbeitet mit Flush!

Sie nutzt aber soweit ich weiß keine Due. Zu dem Flush Problem schaue mal als Einstiegspunkt hier, dieser führt dich weiter https://forum.arduino.cc/t/problems-send...uino-due/550466

Wenn dieses Problem mit dem USB Controller bei dir tatsächlich die Ursache wäre, dann könntest du auch mit analogen Midi die Signale senden, zumindest dann wenn du noch Pins dazu frei hast.

Nur Manuale und Pedal sollte eigentlich nicht so viele Daten erzeugen können, vielleicht dein Schweller? Der könnte ja innerhalb kurze Zeit sehr viele Informationen erzeugen. Du könntest das senden der Midi Daten beim Schweller einmal auskommentieren, nur um zu sehen ob dies irgendwas verändert. Schreibe vielleicht mal über die Serielle Konsole den Midi Befehl und vergleiche es dann mit einem Midi Monitor. Wenn in deiner Konsole die Informationen auftauchen, am Rechner aber nicht ankommen, dann bleibt ja nur noch die Übertragung als Ursache.

Leider löst es keinen Fehler auf, wenn irgendwas dann nicht gesendet wird. So was macht die Fehlersuche so gut wie unmöglich...


 Antworten

 Beitrag melden
29.06.2023 12:23 (zuletzt bearbeitet: 29.06.2023 12:24)
#19
So

Pins sind massig frei, könnte es auch über klassische MIDI Schnittstelle senden. Sabine nutzt meines Wissens den Due, aber nicht mit dem USB-Versand. Schweller könnte ich mal auskommentieren, der dürfte aber nicht ins Gewicht gefallen sein, weil ich das Schwellpedal beim Manual testen nicht berührt habe. Somit gibt es keine Änderung und keinen Durchlauf der Schleifen.

@Montre
Jetzt haben wir Bernds Thema gekapert. Vielleicht lagerst du diesen Midi-Strang in ein neues Thema aus?


 Antworten

 Beitrag melden
29.06.2023 15:56 (zuletzt bearbeitet: 29.06.2023 15:57)
avatar  Montre
#20
avatar

Zitat von Christian_Hofmann im Beitrag #122
sendNoteOn(KEYCODE[event.key_number]) if event.pressed else sendNoteOff(KEYCODE[event.key_number])

Ich denke mal, das "if event.pressed" gehört VOR den SendNoteOn (wenn es sich um die Sprache C handelt) ;-)


 Antworten

 Beitrag melden
29.06.2023 16:26 (zuletzt bearbeitet: 29.06.2023 16:28)
#21
avatar

Bei Python tatsächlich nicht, was ich sogar logischer finde.

Führe sendNoteOn aus wenn event.pressed wahr ist, wenn es nicht wahr ist, dann führe sendNoteOff aus.

Tritt keine Veränderung ein, dann wird die Zeile übersprungen. Theoretisch könnte man das if event auch noch einbauen, aber ich schreibe nur ungern Code, welchen ich nach einigen Monaten selbst nicht mehr verstehe. Mit solchen "Erleichterungen" kann man durchaus Code schreiben, der nicht mehr nachvollziehbar ist. Daher ist es objektiv gesehen besser so etwas nicht zu machen und lieber mehrere IF Blöcke zu schreiben... Aber die Faulheit siegt :)

Ich bin kein Entwickler von Interpreten oder Compiler, spannend wäre aber die Frage ob sich beide Varianten in der Ausführungszeit unterscheiden...


 Antworten

 Beitrag melden
29.06.2023 17:32 (zuletzt bearbeitet: 29.06.2023 17:32)
avatar  Montre
#22
avatar

Finde ich total unlogisch, aber egal, ich konnte mich mit Python nie anfreunden.
Wenn man von C/C++ kommt, stolpert man ständig über eine andersartige Syntax. Da ist mir PHP hundert mal lieber.
Und witzigerweise ist Python in C geschrieben...


 Antworten

 Beitrag melden
29.06.2023 19:39 (zuletzt bearbeitet: 29.06.2023 19:55)
avatar  Montre
#23
avatar

Zitat von Brassmann im Beitrag #121
Hier der gesamte Code

Die Methode MidiButton hat nicht für jeden Fall einen definierten Rückgabewert.

MidiButton hat den Parameter "bool keyAlt", der wird mit einem int verglichen: "keyAlt == LOW"
Das ist kein guter Stil. Auf dem einen System funktioniert das, auf dem anderen nicht.

siehe Beispielcode
https://www.arduino.cc/reference/de/lang...io/digitalread/

Wenn ein Pin nicht fest angeschlossen ist, dann kann es zufällige Rückgaben von digitalRead geben,
"Wenn der Pin nicht mit irgendetwas verbunden ist, kann digitalRead() entweder HIGH oder LOW (das passiert völlig zufällig) zurückgeben." => vielleicht auch noch eine Fehlerquelle.


 Antworten

 Beitrag melden
29.06.2023 20:05
#24
So

Die Methode verwende ich daher nur mit stabilen PIN Zuständen, also Input pullup oder bei Tastendruck halt LOW oder anders herum, je nachdem ob NO oder NC.


 Antworten

 Beitrag melden
29.06.2023 21:20
#25
So

Zitat von Christian_Hofmann im Beitrag #12
Ich kenne deinen Code nicht, ich vermute, dass du in den Funktionen noteon und noteoff ein sendMIDI einfach ausführst oder? Versuche mal hinter den sendMIDI direkt ein delayMicroseconds(300); zu setzen und entferne zusätzlich einmal alles flush aus deinem Code (auskommentieren).


Der Delay hat es gebracht. Vorläufige Tests waren positiv. Nun werde ich mal etwas länger üben und schauen, ob es wirklich weg ist. Ich verstehe nur ehrlich gesagt nicht, wieso dieser kurze Delay an genau der Stelle im Code geholfen hat. Aber gut, Hauptsache es funktioniert.

Und ja, in der Funktion wie es in meinem Code zu sehen war ist dann nur ein Sendmidi. Direkt danach habe ich nun den Delay eingebaut. Den Flush habe ich erstmal gelassen, um immer nur eine Sache pro Iteration zu ändern. Da es dann perfekt funktionierte, habe ich es so gelassen. Mein Ziel ist ein funktionierendes Manual, kein Optimieren des Codes bis meine Muttersprache C lautet .

Dass der Flush Befehl bei deinem Due Schwierigkeiten gemacht hat, kann vlt. auch an der Due-Generation liegen? Es kommen doch immer mal Revisionen, und dann gibt es noch den Due mit den grauen Buchsenleisten und den mit den schwarzen. Oder die Lib wurde weiterentwickelt. Ich hatte bislang eher schlechte Erfahrungen ohne den Flush gemacht.

Danke @Christian_Hofmann!


 Antworten

 Beitrag melden
29.06.2023 22:15
#26
avatar

Das es so funktioniert ist meines Erachtens nach ein Indiz, dass du das gleiche Problem hast wie ich. Du sendest etwas und kurze Zeit später wird wieder etwas geehrt, bevor der Controller wieder bereit ist. Dieses midiusb ist einfach Murks. Es läuft zwar auf dem Due, aber der Entwickler unterstützt diesen wohl nicht selbst. Auf anderen Modellen funktioniert das ohne Probleme.


 Antworten

 Beitrag melden
30.06.2023 01:14 (zuletzt bearbeitet: 30.06.2023 01:15)
avatar  Montre
#27
avatar

@Brassmann
Wenn Dir die Optimierung deines Codes zu schwierig ist, dann kann ich Tipps geben.
z.B. lässt sich die Zeile 150 bis 157 durch eine Schleife ersetzen:

1
2
 
  for(int i=0; i < 8; i++)
pinMode(row1+i*2, INPUT);
 



Die Konstanten row2 bis row8 und col2 bis vol8 kannst Du löschen, wenn alles durch kompakte Schleifen nach gezeigtem Muster ersetzt wurden. Dann hast Du auch ungefähr 200 Zeilen weniger Code.


 Antworten

 Beitrag melden
30.06.2023 01:46
#28
avatar

Mit den Optimierungen ist das immer so eine Sache. Man kann in dem Code wohl eine Menge verbessern, aber ob der Aufwand den Nutzen überwiegt?

Bei solchen eigenen Lösungen kommt es ja weniger auf perfekte Leistung an, sondern unterm Strich darauf, dass es funktioniert. Das fängt ja schon an bei solchen Geschichten wie die Notennummer. Im Code steht bei ihm, genau so wie bei mir Tastencode 49,50,51 und so weiter. Ganz spontan gefragt ohne nachzuschauen, was für eine Note verbirgt sich hinter dem Code 85?

Ich weiß es nicht, daher wäre es sinnvoll im Code Enums zu nutzen, statt Midi Notennummern. Also Beispiel:

1
2
3
4
5
 
num MidiNote {
C1 = 36,
Csharp1 = 37,
// ...
};
 



Nur ist es das Wert für ein Hobby Projekt an dem keiner außer man selbst arbeitet? Ich habe meinen Code damals geschrieben und seit dem er funktioniert, habe ich einige Jahre nichts mehr daran verändert :)


 Antworten

 Beitrag melden
30.06.2023 08:57
avatar  Bkoeln
#29
avatar

Ich lese hier interessiert mit wie ihr eure Midilösungen programmiert.
Mal eine andere Frage dazu. Wie führt ihr die Midisignale der einzelnen arduinos zusammen?
Gruß
Bernd


 Antworten

 Beitrag melden
30.06.2023 08:59
avatar  Montre
#30
avatar

Viele sind nicht so fit in der Programmierung. Da macht jede Optimierung Sinn, die die Übersicht verbessert und dadurch in Folge Fehler vermeidet.


 Antworten

 Beitrag melden
Bereits Mitglied?
Jetzt anmelden!
Mitglied werden?
Jetzt registrieren!