Hast Du Töne?

In den Spybot ist auch eine Tonausgabe integriert. Eine Übersicht, mit welchen Befehlen sie angesprochen werden kann, gibt Kasten 5. Den Laser spricht man entweder mit On(OUT_C); oder SendVLL(n); (wobei n zwischen 0 und 127 liegt) an. Bleiben die Befehle, die sich mit internen Timern etc. beschäftigen, und die Event-Steuerung mit bis zu 16 verschiedenen, frei konfigurierbaren Ereignissen. Für meine Zwecke benötigte ich lediglich den Befehl Random(n);, der einen zufälligen Wert zwischen 0 und n zurückliefert. Die weiteren Ergebnisse meiner Recherchen habe ich aber auf die Heft-CD (Agenten-CD?) eingeschleust; alternativ finden sich die Infos unter [3].

Kasten 5: NQC-Töne

PlaySound(sound)          // sound kann sein
  // SOUND_CLICK, SOUND_DOUBLE_BEEP, SOUND_DOWN
  // SOUND_UP, SOUND_LOW_BEEP, SOUND_FAST_UP
PlayTone(frequenz, dauer) // PlayTone(440,50) spielte
  // eine halbe Sekunde den Kammerton a
MuteSound()
  // Stoppt alle Töne und schaltet stumm
UnmuteSound()
  // Reinitialisiert die Tonausgabe und lässt Töne wieder zu
ClearSound()
  // Löscht hinterherhängende Töne aus dem Speicher

Es wird ernst

Mit allem Notwendigen für die Programmierung des Spybots ausgestattet, legte ich mich vor dem besagten Gebäude auf die Lauer. Eine Möglichkeit, nachts unentdeckt ins Gebäude zu kommen, wollte mir einfach nicht einfallen, bis ich schließlich doch die rettende Idee hatte – die Lüftungsschächte. Deren Außenmauern waren nur mit leichten Gittern versehen und würden als Eingangstür für den kleinen Roboter dienen. Als falscher Pizzaverkäufer getarnt nahm ich den Aufbau des Gebäudes und insbesondere dort die Lüftung genauer unter die Lupe. Die Lüftungsschächte verliefen quer durch die Etagen. Große vergitterte Flächen sorgten für die nötige Luftzirkulation.

Damit stand mein Plan fest: Ich würde den Spybot nachts durch eine der leicht gesicherten Öffnungen ins Gebäude bringen, absetzen und dort losfahren lassen. Immer wenn der Spybot über ein Lochgitter führe, stiege die Helligkeit an. Wenn der Roboter das Loch passierte, würde es wieder dunkler – der Lichtsensor sollte dies erfassen können. Danach sollte der Roboter wieder ein Stück zurückzufahren bis aufs Gitter, einen Höllenlärm veranstalten und so die Alarmanlage auslösen, um anschließend schnell abzuhauen.

Im Übergang vom Gitterbereich in den verdeckten ist ein Helligkeitsrückgang von zehn Prozent, was durch periodisches Abfragen des Lichtsensors erkannt wird. Dieses erledigt der Task lichtkontrolle() im NQC-Programm helsinki.nqc (Listing 3, nur auf der Heft-CD). Weiterhin sollte der Spybot zufällig durch die Gänge brausen. An jeder T-Kreuzung oder in Sackgassen sollte er sich (Random()-gesteuert) für eine neue Richtung entscheiden – also eine Links- oder Rechtsdrehung vollführen. Dafür ist der Task hindernis() zuständig. Wichtig war an dieser Stelle, dass sich die beiden Aktionen lichtkontrolle() und hindernis() nicht gegenseitig behindern sollten. Es wäre fatal für den Auftrag, wenn der Spybot in einer Sackgasse ein ständiges Spektakel ausführte, nur weil vielleicht ein unvorhergesehener Lichteinfall aufträte. Um das zu verhindern, verwendete ich für die beiden Tasks die Semaphor-Technik: Ein Task sperrt vor einer Aktion alle anderen durch Setzen einer globalen Variablen sem. Nur wenn diese den Wert 0 hat, beginnt ein Task mit seiner speziellen Aktion. Solange diese ausgeführt wird, wird jede andere durch temporäres Setzen der Variable auf 1 gesperrt.

Abbildung 6: Gitterbereich

Das Programm helsinki.nqc enthält weiterhin eine Unterfunktion warten(), die den Spybot für die erste halbe Stunde an seinem Ort verharren lässt – genug Zeit, mich zu verdrücken. Nach etlichen Testfahrten in meinem Labor konnte ich die Wait()-Zeiten soweit anpassen, dass der Spybot zufriedenstellende 90-Grad-Drehungen fuhr.

Ich schickte Nachricht an den Pinguin, dass ich bereit war. In der verabredeten Nacht schraubte ich einen Spalt ins Außengitter der Belüftung, übergab den Spybot seinem Schicksal und sah zu, dass ich wegkam, denn schon eine gute halbe Stunde später schrillten im Gebäude die ersten Sirenen.

Agenten-

: <I>helsinki.nqc<I>

#include "spy.nqh"
// Semaphor zum gegenseitigen
// Sperren von Anstoßen und Laser
int sem=0;
void spektakel()
{
  until(sem==0)        // warten bis Semaphor frei
  {
    sem=1;             // Semaphor sperren
  }
  PlaySound(SOUND_DOWN);
  Toggle(OUT_A+OUT_B); // zurückfahren
  Wait(100);
  Float(OUT_A+OUT_B);  // auslaufen lassen
  // Drehen
  Rev(OUT_A); Fwd(OUT_B); On(OUT_A+OUT_B);
  repeat(8)
  {
    /*
    // Laser an, Krach schlagen
    */
    SendVLL(0);
    PlaySound(SOUND_FAST_UP);
    Wait(50);
  }
  Off(OUT_C);          // Laser aus
  // auf Schleichfahrt
  MuteSound(); ClearSound(); UnmuteSound();
  OnFwd(OUT_A+OUT_B);  //  abhauen
  sem=0;               // Semaphor freigeben
}
task lichtkontrolle()
{
  int alte_helligkeit;
  int aktuelle_helligkeit;
  int intervall_lichtmessung=50;
  alte_helligkeit=SENSOR_2;       // initialisieren
  while(true) // ständig die Helligkeit beobachten
  {
    aktuelle_helligkeit=SENSOR_2;
    /*
    // mehr als 10% dunkler geworden?
    */
    if(aktuelle_helligkeit+10<alte_helligkeit)
    {
      spektakel();                // Inline-Funktion aufrufen
      // Helligkeit sichern
      alte_helligkeit=aktuelle_helligkeit;
    }
    Wait(intervall_lichtmessung); // Warten auf nächsten Messung
  }
}
task hindernis()
{
  while(true)              // Warten auf Drucksensor
  {
    if(SENSOR_1==1)        // Drucksensor betätigt?
    {
      until(sem==0)        // warten bis Semaphor frei ist
      {
        sem=1;             // Semaphor sperren
      }
      Toggle(OUT_A+OUT_B); // Motoren in umgekehrte Richtung
      /*
      // eine Sekunde in andere Richtung fahren lassen
      */
      Wait(100);
      if(Random(1)==0)     // zufällige Drehrichtigung wählen
      {
        Toggle(OUT_A);
      }
      else
      {
        Toggle(OUT_B);
      }
      Wait(60);            // drehen lassen
      Fwd(OUT_A+OUT_B);    // Beide Motoren wieder vorwärts
      sem=0;               // Semaphor freigeben
    }
  }
}
sub warten()
{
  int zeit=0;
  PlaySound(SOUND_DOUBLE_BEEP);
  ClearTimer(0);
  /*
  // ca. eine halbe Stunde warten
  */
  until(zeit>=15000)
  {
    zeit=Timer(0);
  }
  PlaySound(SOUND_LOW_BEEP);
}
task main()
{
  int geschwindigkeit=7;   // maximale Geschwindigkeit
  // Initialisierung:
  // Drucksensor erwartet "an" oder "aus"
  // Lichtsensor auf 0 bis 100
  SetSensorMode(SENSOR_1,SENSOR_MODE_BOOL);
  SetSensorMode(SENSOR_2,SENSOR_MODE_PERCENT);
  SetPower(OUT_A+OUT_B,geschwindigkeit);
  /*
  // Besonderheit Gigamesh G60 berücksichtigen
  // wo alles umgekehrt definiert sein müsste
  */
  SetGlobalDirection(OUT_A+OUT_B,OUT_REV);
  warten();
  OnFwd(OUT_A+OUT_B);      // Los gehts
  start lichtkontrolle;    // Lichtkontrolle ein
  start hindernis;         // Hinderniskontrolle ein
}

Glossar

wine

ist eigentlich kein echter Emulator, der Windows in Linux emuliert. Vielmehr nimmt wine die System- und Bibliotheksaufrufe an Windows auf und biegt diese in Linux-Aufrufe um. Der LinuxUser hat in seiner Ausgabe 10/2000 ausführlich über wine berichtet [1].

User.ini

Datei mit benutzerspezifischen Konfigurationen von Programmen, die auf unter Windows (oder eben unter wine) laufen.

call by value

Nur der Wert eines variablen Parameters wird übergeben. Ändert sich der Wert des Parameters innerhalb der Funktion, hat er nach Funktionsende den ursprünglichen Wert.

call by reference

Die Änderungen eines variablen Parameters innerhalb einer Funktion bleiben auch nach Ende der Funktion noch erhalten. Eine solche Übergabe wird in NQC mit dem Symbol & im Funktionskopf deklariert.

Infos

[1] Peter Ganten: "Windows-Programme unter Linux – Red, Red Wine", LinuxUser 10/2000, S. 15 http://www.linux-user.de/ausgabe/2000/10/015-wine/wine.html

[2] Die wine-Homepage: http://www.winehq.com

[3] NQC: http://www.baumfamily.org/nqc/

Der Autor

Volker Schmitt ist Mathematiker und arbeitet bei einer großen Versicherung. Multitasking-Programmierung kennt er aus seiner PL/1-Zeit am Großrechner; dank NQC kann er sich mit seinem Spybot von LEGO so richtig austoben.

LinuxCommunity kaufen

Einzelne Ausgabe
 
Abonnements
 

Related content

Kommentare

Infos zur Publikation

title_2014_08

Digitale Ausgabe: Preis € 5,95
(inkl. 19% MwSt.)

Mit der Zeitschrift LinuxUser sind Sie als Power-User, Shell-Guru oder Administrator im kleinen Unternehmen monatlich auf dem aktuelle Stand in Sachen Linux und Open Source.

Sie sind sich nicht sicher, ob die Themen Ihnen liegen? Im Probeabo erhalten Sie drei Ausgaben zum reduzierten Preis. Einzelhefte, Abonnements sowie digitale Ausgaben erwerben Sie ganz einfach in unserem Online-Shop.

NEU: DIGITALE AUSGABEN FÜR TABLET & SMARTPHONE

HINWEIS ZU PAYPAL: Die Zahlung ist auch ohne eigenes Paypal-Konto ganz einfach per Kreditkarte oder Lastschrift möglich!       

Tipp der Woche

Schnell Multi-Boot-Medien mit MultiCD erstellen
Schnell Multi-Boot-Medien mit MultiCD erstellen
Tim Schürmann, 24.06.2014 12:40, 0 Kommentare

Wer mehrere nützliche Live-Systeme auf eine DVD brennen möchte, kommt mit den Startmedienerstellern der Distributionen nicht besonders weit: Diese ...

Aktuelle Fragen

Server antwortet mit falschem Namen
oin notna, 21.07.2014 19:13, 0 Antworten
Hallo liebe Community, Ich habe mit Apache einen Server aufgesetzt. Soweit, so gut. Im Heimnet...
o2 surfstick software für ubuntu?
daniel soltek, 15.07.2014 18:27, 1 Antworten
hallo zusammen, habe mir einen o2 surfstick huawei bestellt und gerade festgestellt, das der nic...
Öhm - wozu Benutzername, wenn man dann hier mit Klarnamen angezeigt wird?
Thomas Kallay, 03.07.2014 20:30, 1 Antworten
Hallo Team von Linux-Community, kleine Zwischenfrage: warum muß man beim Registrieren einen Us...
openSUSE 13.1 - Login-Problem wg. Fehler im Intel-Grafiktreiber?
Thomas Kallay, 03.07.2014 20:26, 8 Antworten
Hallo Linux-Community, habe hier ein sogenanntes Hybrid-Notebook laufen, mit einer Intel-HD460...
Fernwartung für Linux?
Alfred Böllmann, 20.06.2014 15:30, 7 Antworten
Hi liebe Linux-Freunde, bin beim klassischen Probleme googeln auf www.expertiger.de gestoßen, ei...