ZHAW Lightbag Workshop

Der ZHAW Lightbag Workshop ist ein kreatives Projekt, das es ermöglicht, mit Licht und Programmierung zu experimentieren. Diese Dokumentation enthält die Lösungen für die Challenges. Die Challenge Cards sind unter dem Link Challenge Cards zu finden.

Dokumentation

Um diese Dokumentation anzupassen und lokal zu testen, befolge diese Schritte:

  1. Install rust
    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
    
  2. Install mdbook
    cargo install mdbook
    
  3. Install extensions
    cargo install mdbook-admonish
    
  4. Build and serve the book from the docs directory
    mdbook serve
    

Lösungen Grüne Challenges

Die Lösungen für die Challenges sind in den folgenden Seiten zu finden. Wichtig ist, dass es viele Wege gibt, um zum Ziel zu gelangen. Die gezeigten Lösungen sind nur Beispiele und können auf verschiedene Arten erreicht werden. Teilweise sind Zusatzaufgaben oder alternative Lösungen enthalten.

Die Lösung wird als Bild der Blöcke angezeigt. Oben rechts in der Block übersicht gibt es einen Copy-Paste-Button, um den Code zu kopieren. Der Code kann dann in die MakeCode-Umgebung im JavaScript-Editor eingefügt werden.

Challenge 1: Hallo Welt

basic.showString("Hallo Welt")

Zusatzaufgabe

basic.showIcon(IconNames.Heart)
basic.pause(1000)
basic.forever(function () {
    basic.showString("Hallo Welt")
    basic.showIcon(IconNames.Surprised)
    basic.pause(200)
    basic.showIcon(IconNames.Asleep)
    basic.pause(200)
    basic.showIcon(IconNames.Surprised)
    basic.pause(200)
})

Challenge 2: Hallo Welt

basic.forever(function () {
    basic.showString("Hallo Welt")
    basic.showIcon(IconNames.Happy)
    basic.pause(2000)
})

Challenge 3: Taster A+B

Mit den Tastern A und B kannst du den micro:bit steuern. Aber du musst den micro:bit zuerst so programmieren, dass er auf die Taster reagieren kann. Versuche, zum Beispiel, dass beim Drücken vom Taster A ein Smiley erscheint.

input.onButtonPressed(Button.A, function () {
    basic.showIcon(IconNames.Happy)
})
input.onButtonPressed(Button.B, function () {
    basic.showIcon(IconNames.Sad)
})
basic.showIcon(IconNames.Asleep)

Alternative

basic.forever(function () {
    if (input.buttonIsPressed(Button.A)) {
        basic.showIcon(IconNames.Happy)
    } else if (input.buttonIsPressed(Button.B)) {
        basic.showIcon(IconNames.Sad)
    } else {
        basic.showIcon(IconNames.Asleep)
    }
})

Zusatzaufgabe

  • Erweitere das Programm so, dass beim Drücken des Tasters B ein anderes Symbol angezeigt wird
  • Verwende zusätzlich den Touch-Sensor „Logo“ um ein eigenes Symbol anzuzeigen

Challenge 4: Schleifen

Befehle wiederholen sich beim Programmieren oft. Da Programmierer faul sind, möchten sie so wenig Blöcke wie möglich einsetzen. Dafür gibt es Schleifen. Eine Schleife wiederholt eine Reihe von Blöcken, bis eine Bedingung zum Abbrechen erfüllt ist. Mit der Variablen „Index“ weisst du, beim wievielten Durchgang die Schleife ist.

Dein neues Programm soll von 0 bis 9 zählen und die Zahlen auf dem LED-Display anzeigen

let zahl = 0
basic.forever(function () {
    zahl = 0
    for (let index = 0; index < 10; index++) {
        basic.showNumber(zahl)
        basic.pause(1000)
        zahl += 1
    }
})

Alternative

basic.forever(function () {
    for (let Index = 0; Index <= 9; Index++) {
        basic.showNumber(Index)
        basic.pause(1000)
    }
})

Zusatzaufgabe

  • Beim Drücken des Tasters A soll in 2er-Schritten gezählt werden.
  • Beim Drücken des Tasters B soll der Zähler auf 0 zurückgesetzt werden.

Challenge 5: Mikrofon

Findest du das Mikrofon auf dem micro:bit? Das Mikrofon ist einer von vielen Sensoren auf dem micro:bit. Programmiere mit dem micro:bit eine Lautstärkenwarnung. Zeige dazu auf dem Bildschirm ein Symbol an, wenn die Lautstärke höher als 100 ist.

Schreie den micro:bit an, bis du das Symbol siehst. Wenn du nicht mehr schreist, sollte kein Symbol mehr angezeigt werden.

basic.forever(function () {
    if (input.soundLevel() > 180) {
        basic.showIcon(IconNames.No)
    } else if (input.soundLevel() > 100) {
        basic.showLeds(`
            . . # . .
            . . # . .
            . . # . .
            . . . . .
            . . # . .
            `)
    } else {
        basic.showIcon(IconNames.Yes)
    }
})

Zusatzaufgabe

  • Wie laut kannst du Schreien? Spiele mit dem Vergleichswert der Lautstärke!
  • Versuche die aktuelle Lautstärke auf dem Bildschirm anzuzeigen. Nutze dazu den folgenden Block:
basic.forever(function () {
    led.plotBarGraph(
    input.soundLevel(),
    255
    )
})

Challenge 7: Helligkeit

Dein micro:bit kann die Helligkeit messen. Die Helligkeit wird mit einer Zahl von 0 bis 255 angegeben, wobei 0 der dunkelste und 255 der hellste Wert ist. Lasse deinen micro:bit einen Warnton abspielen, wenn der Helligkeitswert grösser als 150 wird.

basic.forever(function () {
    if (input.lightLevel() > 100) {
        music.play(music.tonePlayable(523, music.beat(BeatFraction.Whole)), music.PlaybackMode.UntilDone)
        basic.pause(1000)
    } else {
    	
    }
})

Zusatzaufgabe

  • Versuche die aktuelle Helligkeit auf dem Bildschirm anzuzeigen. Nutze dazu den folgenden Block:
basic.forever(function () {
    led.plotBarGraph(
    255 - input.lightLevel(),
    255
    )
    music.play(music.tonePlayable(input.lightLevel() * 4, music.beat(BeatFraction.Half)), music.PlaybackMode.UntilDone)
})

Challenge 10: Würfel

Du kannst den micro:bit auch als Würfel verwenden! Zeige auf dem Display nach dem Schütteln die gewürfelte Zufallszahl zwischen 1 und 6 an! Erweitere die Anzeige so, dass das Resultat wie bei einem normalen Würfel mit 7 Lichtpunkten angezeigt wird.

let wurfzahl = 0
input.onGesture(Gesture.Shake, function () {
    wurfzahl = randint(1, 6)
    if (wurfzahl == 1) {
        basic.showLeds(`
            . . . . .
            . . . . .
            . . # . .
            . . . . .
            . . . . .
            `)
    } else if (wurfzahl == 2) {
        basic.showLeds(`
            # . . . .
            . . . . .
            . . . . .
            . . . . .
            . . . . #
            `)
    } else if (wurfzahl == 3) {
        basic.showLeds(`
            # . . . .
            . . . . .
            . . # . .
            . . . . .
            . . . . #
            `)
    } else if (wurfzahl == 4) {
        basic.showLeds(`
            # . . . #
            . . . . .
            . . . . .
            . . . . .
            # . . . #
            `)
    } else if (wurfzahl == 5) {
        basic.showLeds(`
            # . . . #
            . . . . .
            . . # . .
            . . . . .
            # . . . #
            `)
    } else if (wurfzahl == 6) {
        basic.showLeds(`
            # . . . #
            . . . . .
            # . . . #
            . . . . .
            # . . . #
            `)
    } else {
    	
    }
})

Zusatzaufgabe

  • Zeige während dem Würfeln (Schütteln) ein anderes Symbol (Zum Beispiel ein Smiley oder auch abwechselnd Nummern)
  • Zinke den Würfel, sodass der Würfel immer eine 6 anzeigt. Damit der gezinkte Würfel nicht auffällt, soll er nur eine 6 würfeln, wenn du gleichzeitig zum Schütteln das Logo berührst.
let wurfzahl = 0
basic.forever(function () {
    while (input.isGesture(Gesture.Shake)) {
        wurfzahl = randint(1, 6)
        basic.showIcon(IconNames.SmallDiamond)
        basic.pause(50)
        basic.showIcon(IconNames.Diamond)
        basic.pause(50)
    }
    if (wurfzahl == 1) {
        basic.showLeds(`
            . . . . .
            . . . . .
            . . # . .
            . . . . .
            . . . . .
            `)
    } else if (wurfzahl == 2) {
        basic.showLeds(`
            # . . . .
            . . . . .
            . . . . .
            . . . . .
            . . . . #
            `)
    } else if (wurfzahl == 3) {
        basic.showLeds(`
            # . . . .
            . . . . .
            . . # . .
            . . . . .
            . . . . #
            `)
    } else if (wurfzahl == 4) {
        basic.showLeds(`
            # . . . #
            . . . . .
            . . . . .
            . . . . .
            # . . . #
            `)
    } else if (wurfzahl == 5) {
        basic.showLeds(`
            # . . . #
            . . . . .
            . . # . .
            . . . . .
            # . . . #
            `)
    } else if (wurfzahl == 6) {
        basic.showLeds(`
            # . . . #
            . . . . .
            # . . . #
            . . . . .
            # . . . #
            `)
    } else {
    	
    }
})

Lösungen Rote Challenges

Die Lösungen für die Challenges sind in den folgenden Seiten zu finden. Wichtig ist, dass es viele Wege gibt, um zum Ziel zu gelangen. Die gezeigten Lösungen sind nur Beispiele und können auf verschiedene Arten erreicht werden. Teilweise sind Zusatzaufgaben oder alternative Lösungen enthalten.

Die Lösung wird als Bild der Blöcke angezeigt. Oben rechts in der Block übersicht gibt es einen Copy-Paste-Button, um den Code zu kopieren. Der Code kann dann in die MakeCode-Umgebung im JavaScript-Editor eingefügt werden.

Challenge 2: LED Ring

Dein LED-Ring hat 12 LEDs. Bringe nun vier von diesen LEDs zum Leuchten. Arbeite mit der vorhin eingerichteten Neopixel Erweiterung und nutze das Element rot (255) grün (255) blau (255) aus der Neopixelerweiterung im Reiter mehr.

LED an der Stelle 0: Rot
LED an der Stelle 3: Orange
LED an der Stelle 6: Blau
LED an der Stelle 9: Grün

let strip = neopixel.create(DigitalPin.P0, 12, NeoPixelMode.RGB)
basic.forever(function () {
    strip.setPixelColor(0, neopixel.rgb(255, 0, 0))
    strip.setPixelColor(3, neopixel.rgb(255, 200, 0))
    strip.setPixelColor(6, neopixel.rgb(0, 0, 255))
    strip.setPixelColor(9, neopixel.rgb(0, 255, 0))
    strip.show()
})

Zusatzaufgabe

Definiere vier Bereiche (range) mit je 3 LEDs auf dem Ring und lasse diese in unterschiedlichen Farben leuchten. Kannst du auch unterschiedliche Helligkeiten einstellen?

let strip = neopixel.create(DigitalPin.P0, 12, NeoPixelMode.RGB)
let zone_1 = strip.range(0, 3)
let zone_2 = strip.range(3, 3)
let zone_3 = strip.range(6, 3)
let zone_4 = strip.range(9, 3)
basic.forever(function () {
    zone_1.showColor(neopixel.colors(NeoPixelColors.Green))
    zone_2.showColor(neopixel.colors(NeoPixelColors.Orange))
    zone_3.showColor(neopixel.colors(NeoPixelColors.Indigo))
    zone_4.showColor(neopixel.colors(NeoPixelColors.Blue))
    strip.show()
})

Challenge 3: Regenbogen

Lasse auf deinem LED-Ring ein Regenbogen leuchten. Programmiere deinen micro:bit so, dass du den Regenbogen mit dem Berühren des Logos aus- und wieder einschalten kannst.

let strip = neopixel.create(DigitalPin.P0, 12, NeoPixelMode.RGB)
let ring_zustand = 0
basic.forever(function () {
    if (input.logoIsPressed()) {
        if (ring_zustand == 0) {
            strip.showRainbow(1, 360)
            ring_zustand = 1
        } else if (ring_zustand == 1) {
            strip.showColor(neopixel.colors(NeoPixelColors.Black))
            ring_zustand = 0
        } else {
        	
        }
        strip.show()
        // Diese Schleife Blockiert, bis das Logo wieder losgelassen wird
        while (input.logoIsPressed()) {
        	
        }
    }
})

Zusatzaufgabe

  • Ändere die Helligkeit des Lichts. Klicke auf A und der Regenbogen wird heller. Klicke auf B und er wird dunkler.
  • Was passiert, wenn die Helligkeit >255 ist oder kleiner 0? Programmiere, dass die Helligkeit nicht < 0 oder > 255 werden kann.
input.onButtonPressed(Button.A, function () {
    ring_helligkeit += -16
    if (ring_helligkeit < 0) {
        ring_helligkeit = 0
    }
    strip.setBrightness(ring_helligkeit)
    strip.show()
})
input.onButtonPressed(Button.B, function () {
    ring_helligkeit += 16
    if (ring_helligkeit > 255) {
        ring_helligkeit = 255
    }
    strip.setBrightness(ring_helligkeit)
    strip.show()
})
let ring_helligkeit = 0
let strip: neopixel.Strip = null
strip = neopixel.create(DigitalPin.P0, 12, NeoPixelMode.RGB)
let ring_zustand = 0
ring_helligkeit = 128
basic.forever(function () {
    if (input.logoIsPressed()) {
        if (ring_zustand == 0) {
            strip.showRainbow(1, 360)
            ring_zustand = 1
        } else if (ring_zustand == 1) {
            strip.showColor(neopixel.colors(NeoPixelColors.Black))
            ring_zustand = 0
        } else {
        	
        }
        strip.setBrightness(ring_helligkeit)
        strip.show()
        // Diese Schleife Blockiert, bis das Logo wieder losgelassen wird
        while (input.logoIsPressed()) {
        	
        }
    }
})

Challenge 4: Lauflicht

Auf deinem LED-Ring soll immer nur eine LED leuchten. Immer nach einer Sekunde springt das Licht zur benachbarten LED und bewegt sich so endlos im Kreis.

let richtung = 0
let strip = neopixel.create(DigitalPin.P0, 12, NeoPixelMode.RGB)
richtung = 1
let led_index = 0
basic.forever(function () {
    led_index = led_index + richtung
    led_index = led_index % 12
    strip.showColor(neopixel.colors(NeoPixelColors.Black))
    strip.setPixelColor(led_index, neopixel.colors(NeoPixelColors.Orange))
    strip.show()
    basic.pause(1000)
})

Zusatzaufgabe

  • Ändere bei Logoklick die Richtung.
  • Programmiere das Lauflicht so, dass es nach jedem Schritt eine andere Farbe hat.
  • Programmiere das Licht so, dass es langsam ausschaltet und währenddessen das nächste Licht langsam einschaltet. Tipp: Du brauchst dazu Variablen und Logikbauteile.
  • Lasse immer zwei benachbarte LEDs gemeinsam im Kreis laufen. Wie löst du den Übergang von der LED 11 zur LED 0?
input.onLogoEvent(TouchButtonEvent.Pressed, function () {
    richtung = richtung * -1
})
let richtung = 0
let strip = neopixel.create(DigitalPin.P0, 12, NeoPixelMode.RGB)
richtung = 1
let led_index = 0
basic.forever(function () {
    led_index = led_index + richtung
    led_index = led_index % 12
    strip.showColor(neopixel.colors(NeoPixelColors.Black))
    strip.setPixelColor(led_index, neopixel.colors(NeoPixelColors.Orange))
    strip.show()
    basic.pause(1000)
})

Challenge 5: Lautstärke anzeigen

Mit dem Mikrofon auf dem micro:bit kannst du die Lautstärke von deiner Umgebung messen. Zeige auf dem LED-Ring an, wie laut es ist. Je lauter, desto mehr LEDs sollen leuchten. Wiederhole die Messung dauerhaft und aktualisiere deine LEDs.

let strip = neopixel.create(DigitalPin.P0, 12, NeoPixelMode.RGB)
basic.forever(function () {
    strip.showBarGraph(input.soundLevel(), 255)
    strip.show()
})

Zusatzaufgabe

  • Zeige den Lautstärkewert zusätzlich auf deinem micro:bit als Zahl an.
  • Spiele einen Warnton ab, wenn deine Umgebung zu laut wird.
let strip = neopixel.create(DigitalPin.P0, 12, NeoPixelMode.RGB)
basic.forever(function () {
    if (input.soundLevel() > 160) {
        music.play(music.tonePlayable(523, music.beat(BeatFraction.Whole)), music.PlaybackMode.UntilDone)
    } else {
    	
    }
    strip.showBarGraph(input.soundLevel(), 255)
    strip.show()
})
// Das Anzeigen der Zahl blockiert den Block. Ein zweiter Dauerhaft Block kann helfen
basic.forever(function () {
    basic.showNumber(input.soundLevel())
})

Challenge 6: Fang das Licht

In der Challenge 4 hast du ein Lauflicht programmiert. Programmiere nun ein kleines Spiel: Ein zweites Licht wird über die Knöpfe A und B gesteuert. Wenn du auf B klickst bewegt sich dein Licht im Uhrzeigersinn, mit A auf die andere Seite. Wenn dein Licht vom Lauflicht eingeholt wurde ist das Spiel verloren. Überlege dir, wie du schwierigere Levels von diesem Spiel programmieren kannst. Starte das Spiel beim Drücken von Taster A&B gleichzeitig.


Zusatzaufgabe

  • Mache, dass du bei Taster A+B immer wieder neu starten kannst.
  • Zähle, wie viele Schritte du zum Fangen des Lichtes benötigst und zeige es danach auf dem Display an.
  • Ändere die Geschwindigkeit des Pixels, dass du einfangen musst zufällig. Dazu kannst du zum Beispiel die Pause im Bereich von 200…1000 ms verändern.
  • Ändere die Richtung des Pixels, dass du fangen musst zufällig.
  • Beweg den Gegner automatisch weg von der Bewegung des Spielers.
  • Beweg den Gegner schneller, wenn der Spieler in der Nähe ist.
  • Passe das Spiel so an, dass du gegen einen Freund spielen kannst. Dazu könnt ihr die Position des Gegners über Funk übertragen.

Challenge 7: Kompass

Hast du dich auch schon gefragt, ob es einen digitalen Kompass gibt? Auf dem micro:bit ist ein Kompasssensor verbaut. Zeige mit dem LED-Ring die Kompasnadel an! Der Norden soll wie beim richtigen Kompass Rot und der Süden Weiss angezeigt werden.


Zusatzaufgabe

  • Was passiert, wenn einen Magneten um deinen micro:bit bewegst?
  • Zeige zusätzlich auf der LED-Matrix die aktuelle Ausrichtung deines LED-Rings an. Schreibe dazu die Buchstaben N, O, S oder W auf die LEDs

Challenge 8: Uhr

Programmiere eine Uhr, die mit einer Farbe die Stunde und mit einer anderen Farbe die Minute auf dem LED Ring anzeigt. Mit dem Knopf A soll die Stunde und mit dem Knopf B die Minute verändert werden können. Überlege dir Antworten zu folgenden Fragen bevor du programmierst: Nach wie vielen Minuten muss der Minutenzeiger eine LED weiterspringen? Wann muss der Stundenzeiger eine LED weiterspringen? Wie sollen deine LEDs leuchten, wenn beide Zeiger auf der gleichen LED sind?


Zusatzaufgabe

  • Erweitere deine Uhr um eine Timer Funktion. Nutze den Touch Sensor, um in den Timer Modus zu wechseln und den Timer zu starten.

Challenge 10: Nachttischlampe

Das Projekt kann über den Link https://github.com/InES-HPMM/zhaw_lightbag in MakeCode importiert werden.

input.onLogoEvent(TouchButtonEvent.Pressed, function () {
    if (Eingeschaltet == true) {
        strip.setBrightness(0)
        strip.showColor(Farbe)
        strip.show()
    } else {
        strip.setBrightness(Helligkeit)
        strip.showColor(Farbe)
        strip.show()
    }
    Eingeschaltet = !(Eingeschaltet)
})
input.onButtonPressed(Button.A, function () {
    Helligkeit += 45
    if (Helligkeit > 255) {
        Helligkeit = 0
    }
    strip.setBrightness(Helligkeit)
    strip.showColor(Farbe)
    strip.show()
})
function wechsel_regenbogen () {
    while (true) {
        for (let Index = 0; Index <= 205; Index++) {
            if (input.buttonIsPressed(Button.B)) {
                return
            }
            strip.showRainbow(1, 360)
            strip.setBrightness(50 + Index)
            strip.show()
            basic.pause(10)
        }
        basic.pause(100)
        for (let Index2 = 0; Index2 <= 205; Index2++) {
            if (input.buttonIsPressed(Button.B)) {
                return
            }
            strip.showRainbow(1, 360)
            strip.setBrightness(255 - Index2)
            strip.show()
            basic.pause(10)
        }
    }
}
input.onButtonPressed(Button.B, function () {
    FarbZaehler += 1
    if (FarbZaehler < FarbListe.length) {
        Farbe = FarbListe[FarbZaehler]
        strip.setBrightness(Helligkeit)
        strip.showColor(Farbe)
        strip.show()
    } else if (FarbZaehler == FarbListe.length) {
        strip.showRainbow(1, 360)
    } else if (FarbZaehler == FarbListe.length + 1) {
        wechsel_regenbogen()
    } else {
        wechsel_farbig()
        FarbZaehler = -1
    }
})
function wechsel_farbig () {
    st_rot = 0
    st_gruen = 127
    st_blau = 255
    st_delta_rot = 2
    st_delta_gruen = 2
    st_delta_blau = 2
    while (true) {
        if (input.buttonIsPressed(Button.B)) {
            return
        }
        Farbe = neopixel.rgb(st_rot, st_gruen, st_blau)
        strip.showColor(Farbe)
        strip.setBrightness(Helligkeit)
        strip.show()
        basic.pause(50)
        st_rot += st_delta_rot
        st_gruen += st_delta_gruen
        st_blau += st_delta_blau
        if (st_rot > 255) {
            st_rot = 255
            st_delta_rot = st_delta_rot * -1
        }
        if (st_rot < 0) {
            st_rot = 0
            st_delta_rot = st_delta_rot * -1
        }
        if (st_gruen > 255) {
            st_gruen = 255
            st_delta_gruen = st_delta_gruen * -1
        }
        if (st_gruen < 0) {
            st_gruen = 0
            st_delta_gruen = st_delta_gruen * -1
        }
        if (st_blau > 255) {
            st_blau = 255
            st_delta_blau = st_delta_blau * -1
        }
        if (st_blau < 0) {
            st_blau = 0
            st_delta_blau = st_delta_blau * -1
        }
    }
}
let st_delta_blau = 0
let st_delta_gruen = 0
let st_delta_rot = 0
let st_blau = 0
let st_gruen = 0
let st_rot = 0
let FarbListe: number[] = []
let Eingeschaltet = false
let Helligkeit = 0
let Farbe = 0
let strip: neopixel.Strip = null
let FarbZaehler = 0
FarbZaehler = 0
strip = neopixel.create(DigitalPin.P0, 12, NeoPixelMode.RGB)
Farbe = neopixel.rgb(255, 200, 25)
strip.showColor(Farbe)
Helligkeit = 102
Eingeschaltet = true
strip.show()
FarbListe = [
neopixel.rgb(255, 0, 0),
neopixel.rgb(0, 255, 0),
neopixel.rgb(0, 0, 255),
neopixel.rgb(255, 200, 25)
]