Lichtsensor gibt falsche Werte aus

Hallo und guten Tag.
Ich denke ich dokumentiere hier ein allgemeines
Problem mit dem Auslesen der Lichtsensoren.

Aktuell werden im Nepo- und Makecode-Editor
bei meinen Calliope-Minis(V:1.3; 3 getestet) bei einer
nur Lese-Schleife des Lichtsensors und der
Ausgabe der Werte auf dem Seriellen-USB-Port
immer wieder(ca. alle 7 Werte) Falsch-Werte
von 0 oder zumindest >=50 Nach-unten-Sprüngen
gelesen.

Das führt zu den miserablen Programmen:Lichtschranke,
,Alarmanlage oder Fahrradlicht.
Bei denen wundert man sich warum diese
jetzt grad ausgehen oder ähnliches.

Die Fehlerwerte(große sprunghafte Abweichungen in Richtung 0)
treten nicht auf wenn ich identische Programme
mit der Abbozza(cpp) Umgebung auf die gleichen
Geräte gespielt habe.
Im Folgenden Aufzeichnungen mit dem Serial-Plotter
Serial-Plotterdie das fehlerhafte Schwanken der Werte dokumentieren.

Im Anhang die Bilder und die Codes:



Nepo-hex:
NEPOprog-Lichtsensor-Serial.hex (475,7 KB)
Makecode-hex:
MakeCode-Lichtsensor-SendSerial.hex (646,0 KB)
Abbozza-hex:
abbozza-combined.hex (509,3 KB)

Der Code ist bei allen drei in etwa mit folgendem Makecode-Javascript
ausgedrückt:

let li = 0
let tli = ""
basic.forever(function () {
    li = input.lightLevel()
    tli = convertToText(li)
    serial.writeLine(":" + tli + ";")
})

Das ganze geschieht auch bei 1000ms Warten!

Für mich der mit den Schülern mit Makecode
arbeitet ist das ein Problem!

Viele Grüße

Andreas Brusinsky

PS:
mit dem Microbit und folgendem Makecode:

basic.forever(function () {
    serial.writeLine("" + convertToText(input.lightLevel()) + ";")
})

gibt es keine Licht-Probleme.
PSS:
etwas was ich bei Abbozza sehe aber bei Makecode
nicht erkennen kann ist das setzen des MODE.

int Abbozza::readLightLevel() {
    int value, mode;
    
    mode = display.getDisplayMode();
    display.setDisplayMode(DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE);
    sleep(50);
    value = display.readLightLevel();
    display.setDisplayMode((DisplayMode) mode);
    
    return value;
}

Es scheint so als wenn etwas beim Lichtsensor-Wert
mal ein oder auch mal 2 Byte auf 0 setzt/schreibt/löscht.

Hallo @AndreasB

danke für deine tolle Analyse.
Bei unseren Tests konnten wir aber feststellen, dass das Problem ebenfalls beim microbit (V1) auftaucht. Allerdings mit leicht andern Werten – da vermuten wir, dass es an anderer Hardware und wie z.B. leicht veränderten Widerständen etc. liegen kann.
Vielleicht sollte aktuell die Messung bei einer Anwendung dann nicht permanent durchgeführt werden und evtl. das Ergebnis über eine Zeit kumuliert genommen werden?
Wir haben das Thema auf unsere Toto-Liste gesetzt und werden das softwareseitig genau überprüfen, falls du da aber schon vorher einsteigen möchtest, kannst du sehr gern den Treiber im Repository anschauen und ggfs. ein Pull Request erstellen, falls du da schneller eine Lösung hast. Das wäre natürlich super.

Grüße
Jörn

Der Messwert kommt aus der microbit-dal an dieser Stelle: microbit-dal/MicroBitLightSensor.cpp at ae1b5379d3bf9477ce95afa9b7e2ab9b96a2f559 · calliope-mini/microbit-dal · GitHub

Wenn ich das richtig sehe nutzt Abbozza ebenfalls die oben verlinkte microbit-dal. Den Sourcecode von Abbozza kann ich leider nicht einsehen (bzw. nur den von vor 4 Jahren & als veraltet markierten auf GitHub). Ob Abbozza da noch etwas macht um bessere Ergebnisse zu erhalten oder sogar eine eigene Funktion zum auslesen der Helligkeit verwendet bleibt mir deshalb unklar.

Der MicroBit misst bei mir insgesamt etwas niedrigere Werte als der Calliope, die auffällig niedrigen Messwerte zwischendrin habe ich dort aber ebenfalls. Wenn eine Verbesserung der Messung im Treiber möglich/nötig ist wäre die also für dessen Treiber ebenfalls nützlich.

Man sieht ja in dem readLightLevel-abbozza-Code oben das das
Abbozza anders macht.
Bei der DAL und dem Makecode wird ja irgendwie in der letzten
Zeile eines Display-Frames der Light-Level berechnet.
interleaving
Siehe auch in
renderWithLightSense

Ich verwende das „alte(1.5.2 >peer 1.2.3)“ portable Abbozza
altes Abbozza portable.

Bei diesem Abbozza ist auch immer ein cpp-Fenster im „Hintergrund“ das man jeder
Zeit öffnen kann, den Code einsehen und natürlich auch verändern.

Bei mir produziert der ‚alte‘ microbit mit folgendem MakeCode.microbit.org:

basic.forever(function () {
    serial.writeLine("" + convertToText(input.lightLevel()) + ";")
})

keine Falsch-Werte:

Wie debuggt man die microbit-dal?

Wo ist diese fiber-Schleife mit den systemTicks und
den anderen Events besser beschrieben?

Irgendwie flackern bei der Messung bei meinen Calliopes
die LEDs der oberen Zeile.

Was läuft da im Hintergrund obwohl ich doch nur sende?

Ist das irgendwo beschrieben?

Im Makecode kann ich auch nur in ‚meinem‘ Code
debuggen und nicht in den ‚tieferen‘ Ebenen dieser
anderen ts und cpp Dateien aus dem Core Bereich.

Und selbst mit beleuchteten LEDs in der Nicht-Sensor-Zeile
misst der Calliope-Mini mit dem Abbozza-Code akkurat.
Beim Makecode kommen bei beleuchteten LEDs auch
noch viele zusätzliche Sprünge hinzu.
Die anscheinend nicht nötig wären.

/**
 *  Generated by abbozza!
 */
#define ABZPAUSE abbozza.sleep(0)
#define ABZ_RADIO
// Bibliotheken
#include "MicroBit.h"
#include "lib/abbozzaDevice.h"
#include <string.h>

// Globale Variablen
Abbozza abbozza;
// Globale Variablen
bool don;


// Deklarierte Operationen
void __geschuettelt__(MicroBitEvent __event__);
void __Knopf_A_gedrueckt__(MicroBitEvent __event__);
void __Knopf_B_gedrueckt__(MicroBitEvent __event__);


// Die Operationen
void __geschuettelt__(MicroBitEvent __event__) {
   int li;
   while (true) {
      for(li=0;li<=4;li=li+1) {
         abbozza.display.image.setPixelValue(li,1,8);
         abbozza.sleep(1000);
         abbozza.display.image.setPixelValue(li,1,0);
      }
      abbozza.sleep(1000);
      ABZPAUSE;
   }
}

void __Knopf_A_gedrueckt__(MicroBitEvent __event__) {
   abbozza.display.disable();
}

void __Knopf_B_gedrueckt__(MicroBitEvent __event__) {
   abbozza.display.enable();
}


// Das Hauptprogramm
int main() {
   abbozza.init();
   abbozza.radio.enable();
   abbozza.display.setDisplayMode(DISPLAY_MODE_GREYSCALE);
   abbozza.registerEventHandler(MICROBIT_ID_GESTURE,MICROBIT_ACCELEROMETER_EVT_SHAKE,__geschuettelt__);
   abbozza.registerEventHandler(MICROBIT_ID_BUTTON_A,MICROBIT_BUTTON_EVT_DOWN,__Knopf_A_gedrueckt__);
   abbozza.registerEventHandler(MICROBIT_ID_BUTTON_B,MICROBIT_BUTTON_EVT_DOWN,__Knopf_B_gedrueckt__);
   while (true) {
      abbozza.serialWriteLine(USBTX,USBRX,ManagedString((int) abbozza.display.readLightLevel())+ManagedString(";"));
      ABZPAUSE;
   }
   release_fiber();
}

@juri kannst du die richtigen Repositories angeben?
@AndreasB am besten dürfte es sein, wenn du das alles lokal zum laufen bekommst. Dann kannst du da am einfachsten mit arbeiten. Juri hat die beste Übersicht, an welcher Stelle du am besten loslegst, deshalb habe ich ihn hier auch angefragt.

Ganz viel kann ich zum debuggen gar nicht sagen, ich hab es zwar testweise probiert, aber noch nicht praktisch genutzt und daher nicht viel Erfahrung. Als Grundlage zum Debuggen kann man dieses Repository nehmen: GitHub - calliope-mini/microbit-samples

Ich habe yotta unter windows installiert ( yotta Documentation - yotta ), wie das mit ARM mbed online funktioniert weiß ich daher nicht. Yotta ist leider deprecated und daher auch die installation nicht ganz einfach - ich habe zumindest so meine schwirigkeiten gehabt es zum laufen zu bekommen. Wenn Yotta dann läuft klappt die Anleitung aus der Readme zu microbit-samples aber gut.

Beim builden lädt Yotta die DAL von GitHub in den ordner yotta_modules/microbit-dal.
Um das die DAL lokal zu verlinken das Repo microbit ( GitHub - calliope-mini/microbit at v2.2.0-rc6-calliope.rc3 ) herunterladen und in einem ordner eine ebene drüber ablegen und die module.json entsprechend anpassen.

Und dort dann das selbe mit dem microbit-dal Repo ( GitHub - calliope-mini/microbit-dal at v2.2.0-rc6-calliope.rc3 )

Die Ordner microbit, microbit-dal und microbit-samples sollten dann alle in einem Ordner liegen. Dann kann man den Code verändern und mit yt clean und yt build jeweils eine neue Hex Datei erstellen. Die Haltepunkte für die DAL Dateien müssen in microbit-samples/yotta-modules/microbit-dal gesetzt werden. Wenn man yt clean weg lässt kann man ggf. auch ohne die DAL lokal ab zu legen dort den Code ändern - die Änderungen sind dann aber auch schnell dahin, wenn man doch mal yt clean ausführt.

Und es liegt wohl doch an MakeCode. Ich habe es gerade auf dem MicroBit noch mal getestet und diesmal habe ich auch keine Ausschläge - aber auch nicht mehr auf dem Calliope, wenn ich die .hex-Datei für den MicroBit verwende. Die Ausschläge waren auf beiden Geräte mit allen MakeCode versionen beim letzten Test da, eventuell hat mir da mein Arbeitslicht Flackernderweise einen Streich gespielt.

Die alte MakeCode Version (Microsoft MakeCode for Calliope mini) verursacht bei mir auch keine Ausschläge. Es hängt also mit dem Update zusammen. Ich werde noch mal die Änderungen durchgehen und schauen woran es liegen könnte - ad hoc fällt mir keine Änderung ein, die Einfluss auf die Helligkeitsmessung haben könnte.


Der Abbozza macht gar nicht viel anders, ich habe versucht ihn in MakeCode nachzubauen und das sähe etwa so aus (wegen dem Falschen Display Modus wird dann nur 255 ausgegeben):

basic.forever(function () {
    // ToDo: Aktuellen Display Mode auslesen
    led.setDisplayMode(DisplayMode.BlackAndWhite) // ToDo LIGTH_SENSE verwenden
    basic.pause(50)
    serial.writeLine("" + (input.lightLevel()))
// ToDo Display Mode auf vorherigen Wert zurücksetzen
})

In MakeCode lässt sich nur a) der Display Modus nicht auslesen und b) nicht auf BlackAndWhiteLightSense stellen. Dabei bin ich in MakeCode in der led.cpp auf diese stelle gestoßen: pxt-microbit/led.cpp at 06e2d806c4f5af01073bcb39594a80357097f92a · microsoft/pxt-microbit · GitHub
// TODO DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE
Allerdings ist die sowohl bei MicroBit als auch in unserer v3 Version schon so, hat vermutlich also keine Auswirkung auf das Problem.


Direkt in Yotta habe ich vorhin (nach der Anleitung aus meinem vorherigen Post) auch noch das folgende Programm getestet - allerdings hat dann der Sensor ausschließlich 0 ausgegeben.

#include "MicroBit.h"

MicroBit uBit;

int main()
{
    // Initialise the micro:bit runtime.
    uBit.init();

    int light, mode;
 
    while(1)
    {    
        mode = uBit.display.getDisplayMode();
        uBit.display.setDisplayMode(DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE);
        uBit.sleep(50);
        light = uBit.display.readLightLevel();
        uBit.display.setDisplayMode((DisplayMode) mode);
        uBit.serial.send(light);
        uBit.serial.send(";");
    }
}

Was ich eben nicht verstehen kann:

Wo wird in der DAL der DisplayMode wieder
auf den alten DisplayMode zurück gesetzt?

In beiden Implementierungen ist nur das
Setzen auf den SenseMode zu erkennen.
SenseGrayscale gibt es nicht und
es ist nicht zu erkennen wo der alte/vorher
gültige DisplayMode wieder rekonstruiert wird.

calliopeDAL

microbitDAL

Wenn mir das einer erklären könnte …?

Weil ich auch Lichtstärke messen möchte, habe ich das hier gelesen, und frage mich: Mit welchem Bauelement auf dem Calliope soll die Helligkeit überhaupt gemessen werden? Irgendwo steht geschrieben mit den roten Leuchtdioden. Ich habe noch nie gehört, wie das funktionieren soll.

Und wenn doch, dann wird die Matrix multiplex angesteuert. Mit einem Takt werden die 25 Leuchtdioden immer an und aus geschaltet, so schnell dass man es nicht sieht. Und wenn sie alle aus sind, dann schaltet der Takt sie eben mehrmals in der Sekunde aus.

Den Takt kann man abschalten mit
image
Wie sehen denn die Messwerte der Lichtstärke aus, nach diesem Befehl?

Wenn ich die Pins C4 bis C12 nutze, muss ich die Matrix immer deaktivieren, weil die Pins auch für die LEDs benutzt werden. Und zwar auch dann, wenn ich in der Matrix gar nichts anzeigen will. Der Takt läuft also immer im Hintergrund, wenn man ihn nicht explizit aus schaltet.

Für mich passt diese Hypothese zu den Messergebnissen.

Lutz