In reactive-banana versuche ich reactimate :: Event (IO ()) -> Moment ()
mit einigen Aktionen von Arduino
in hArduino-Paket , eine Instanz von MonadIO
. Es scheint keine Funktion von Arduino a -> IO a
im Paket vorhanden zu sein. Wie würden Sie Arduino
Aktionen in reactimate
ausführen?
Wie würden Sie Arduino-Aktionen in
reactimate
ausführen?
Ich würde veranlassen, dass sie indirekt ausgeführt werden, indem eine IO-Aktion ausgeführt wird, die eine beobachtbare Nebenwirkung hat. Dann, in withArduino
, würde ich diesen Nebeneffekt beobachten und den entsprechenden Arduino-Befehl ausführen.
Hier ist ein Beispielcode. Lassen Sie uns zuerst die Importe aus dem Weg schaffen.
%Vor%Da ich kein Arduino habe, muss ich ein paar Methoden von hArduino ausprobieren.
%Vor%Im Rest des Codes werde ich so tun, als wären die Arduino- und Pin-Typen undurchsichtig.
Wir brauchen ein Ereignisnetzwerk, um Eingangsereignisse, die vom Arduino empfangene Signale darstellen, in Ausgangsereignisse umzuwandeln, die beschreiben, was wir an das Arduino senden wollen. Um die Dinge extrem einfach zu halten, lassen Sie uns Daten von einem Pin empfangen und geben die gleichen Daten auf einem anderen Pin aus.
%Vor%Als nächstes verbinden wir unser Event-Netzwerk mit der Außenwelt. Wenn Ausgabeereignisse auftreten, schreibe ich einfach den Wert in eine IORef, die ich später beobachten kann.
%Vor% Beachten Sie, dass reactimate
und compile
nur einmal außerhalb der Hauptschleife aufgerufen werden. Diese Funktionen richten Ihr Ereignisnetzwerk ein, Sie möchten sie nicht bei jeder Schleife aufrufen.
Schließlich führen wir die Hauptschleife aus.
%Vor% Beachten Sie, dass wir liftIO
verwenden, um aus einer Arduino-Berechnung mit dem Ereignisnetzwerk zu interagieren. Wir rufen fireInputPin
auf, um ein Eingabe-Ereignis auszulösen, das Ereignis-Netzwerk bewirkt, dass ein Ausgabe-Ereignis ausgelöst wird, und writeIORef
, das wir reactimate
gegeben haben, bewirkt, dass der Wert des Ausgabe-Ereignisses in die IORef geschrieben wird. Wenn das Ereignisnetzwerk komplizierter ist und das Eingabeereignis kein Ausgabeereignis auslöst, bleibt der Inhalt der IORef unverändert. Unabhängig davon können wir diesen Inhalt beobachten und verwenden, um festzustellen, welche Arduino-Berechnung ausgeführt werden soll. In diesem Fall senden wir einfach den Ausgabewert an einen vorgegebenen Pin.
Ich habe keine Erfahrung mit Arduino oder hArduino, also nimm das Folgende mit einer Prise Salz.
Da es unangemessen ist, das Board für jedes reactimate
neu zu initialisieren, glaube ich nicht, dass es eine saubere Option [*] gibt. Das grundlegende Problem ist, dass die Implementierung von reactimate
in reactive-banana nichts über die Arduino
-Monade weiß, und daher müssen alle hinzugefügten zusätzlichen Effekte durch die Zeit gelöst worden sein, in der reactimate
die Aktion auslöst (also die IO
type). Der einzige Ausweg, den ich sehen kann, ist das Rollen Ihrer eigenen Version von withArduino
, die die Initialisierung überspringt. Aus einem kurzen Blick auf die Quelle , das sieht machbar aus, wenn es sehr unordentlich ist.
[*] Oder zumindest eine saubere Option, die keinen veränderlichen Zustand beinhaltet, wie in den richtigen Antworten.
Da Heinrich Apfelmus diese Antwort freundlicherweise um einen interessanten Ausweg erweitert hat, konnte ich nicht umhin, seinen Vorschlag umzusetzen. Der Dank geht auch an Gelisam, denn das Gerüst seiner Antwort hat mir ziemlich viel Zeit erspart. Über die Hinweise unter dem Codeblock hinaus, siehe Heinrichs Blog für zusätzliche Kommentare zum "Gabelstapler" ".
%Vor%Anmerkungen:
Der Gabelstapler (hier, ard
) führt eine Arduino
-Schleife in einem separaten Thread aus. Mit carry
können wir Arduino
-Befehle wie readInputPin
und copyPin
, die in diesem Thread ausgeführt werden sollen, über Chan (Arduino ())
senden.
Es ist nur ein Name, aber in jedem Fall spiegelt das Argument newForkLift
, das unlift
heißt, die obige Diskussion.
Die Kommunikation ist bidirektional. carry
crafts MVar
s, die uns Zugriff auf Werte geben, die von den Arduino
-Befehlen zurückgegeben werden. Dadurch können wir Ereignisse wie eReadInputPin
ganz natürlich verwenden.
Die Schichten sind sauber getrennt. Zum einen löst die Hauptschleife nur Benutzeroberflächenereignisse wie eLine
aus, die dann vom Ereignisnetzwerk verarbeitet werden. Auf der anderen Seite kommuniziert der Arduino
-Code nur über den Gabelstapler mit dem Ereignisnetzwerk und der Hauptschleife.
Warum habe ich einen Sempahore gestellt? da drin? Ich werde Sie raten lassen, was passiert, wenn Sie es ausziehen ...
Tags und Links haskell frp reactive-banana