Die Mindstorms NXT MultiClock

Die MultiClock ist ein Roboter, der die Uhrzeit auf dem Display digital oder analog und mit den Motoren anzeigen kann. Außerdem kann die Uhr jede Viertel-, Halbe- oder Stunde piepen. Stündlich kann sie die Uhrzeit piepen. Natürlich kann man beim Start die Uhrzeit und die verschiedenen Funktionen ein oder ausstellen. Das Programm besteht aus ungefähr 300 Zeilen Code.

MultiClock

MultiClock

Erklärung

init();

Als erstes muss der Button-Listener an den verschiedene Buttons registriert werden. Dadurch wird bei jedem Knopfdruck die Methode buttonPressed(Button arg0) und beim loslassen buttonReleased(Button arg0) aufgerufen. Danach wird der Timer auf 60000 milisekunden (= 60 sec = 1 min) eingestellt und beim Timer-Listener registrier. Er wird aber noch nicht gestartet. Sonst würde er, schon bevor alles eingestellt wäre, jede Minute timedOut() aufrufen.

public void init() throws InterruptedException{
Button.ENTER.addButtonListener(this);
Button.ESCAPE.addButtonListener(this);
Button.LEFT.addButtonListener(this);
Button.RIGHT.addButtonListener(this);
timer = new Timer(60000,this);

Sound.setVolume(100);
setHardClock();
}

set…();

Danach wird setHardClock aufgerufen. Die Methode belegt zuerst den Wert mit setM(int max, String quest, String[] ans) und ruft, wenn Enter gedrückt wurde die nächste oder bei Escape die vorherige Methode auf. Bei setHardClock() wird das Programm bei Escape beendet, weil es die erste set...()-Methode ist.

public void setHardClock() throws InterruptedException{
hard_clock = setM(1,"HardClock Enable",new String[]{"ein","aus"});
if(ENTER){
Thread.sleep(500);
setHardSound();
}else if(ESCAPE){
Thread.sleep(500);
System.exit(0);
}
}

setM(int max, String quest, String[] ans)

setM(...) gibt die Frage quest aus und lässt einen eine von den Antworten String[] ans auf dem LCD mit Enter auswählen oder man kann mit Escape abbrechen. Zwischen den Antworten wechselt man mittels Left oder Right. max ist die Anzahl der Antworten -1. Das Ergebnis ist die Antwort anfangend bei 0.

public int setM(int max, String quest, String[] ans) throws InterruptedException{
int posnow = 0;
while(!ENTER && !ESCAPE){
Thread.sleep(500);
LCD.clear();
if(RIGHT && posnow == max){
posnow = 0;
}else if(RIGHT && posnow != max){
posnow ++;
}else if(LEFT && posnow == 0){
posnow = max;
}else if(LEFT &&posnow != 0){
posnow --;
}
System.out.println(quest);
System.out.println(ans[posnow]);
}
return posnow;
}

setTime()

In setTime() wird wird der Timer gestartet. Vorher wurden alle Ausgaben auf dem LCD mittels System.out.println(...) vorgenommen. Nun wird der LCD „gelöscht“ und es wird auf Graphics() gezeichnet. Da Garphics automatisch auf den LCD übertragen wird, kann man einfach eine Linie darauf zeichnen und man kann sie auf dem LCD sehen.

Die digitale Uhrzeit wird mittels   g.drawString(hour+" : "+minute,(int)(LCD.SCREEN_WIDTH/2-(hour+" : "+minute).length()*LCD.FONT_WIDTH/2+0.5d) , 56); dargestellt. hour+" : "+minute ist die Uhrzeit. Die x-Position der Uhrzeit ist die LCD Weite durch 2 geteilt minus der Länge des Uhrzeits-String geteilt durch 2. Das ganze wird dann durch +0.5d und (int) gerundet und zu int gecastet. Die y-Position beträgt 56.

Danach wird der Minutenzeiger gezeichnet. 50,32 bestimmen den Mittelpunkt und
(int) (50 + 15 * Math.cos( (60+minute-15) * 2 * Math.PI / 60 )+0.5d),
(int) (32 + 15 * Math.sin( (60+minute-15) * 2 * Math.PI / 60 )+0.5d )
den äußeren Punkt. 2 * Math.PI / 60 ist der Winkel für jede Minute. Da dann aber die Stunde dann aber bei 15 nach anfängt subtrahiert man 15 von der Minutenzahl ab. Und damit man keine negativen Minuten erhält addiert man noch 60 zur Minutenzahl. Die x-Position des Mittlepunktes plus den Radius multipliziert mit dem Kosinus von (60+minute-15) * 2 * Math.PI / 60 ergibt die äußere x-Position des Zeigers. Das ganze muss man noch mit +0.5d runden und mit (int) zu int casten. Genauso funktioniert das bei der äußeren  y-Position. Nur das man dort Sinus verwenden muss.

Dann wird noch der Stundenzeiger nach dem selben Prinzip gezeichnet. Weil sich auch der Stundenzeiger jede Minute bewegen soll beträgt der Winkel aber 2 * Math.PI / (12*60) . Es muss (hour*60+minute) sein, weil er sich jede Stunde 60 Schritte weiter bewegt hat. Dann wird der zeiger noch eine Vierteldrehung mit 60*12+ und -60*12/4 zurückgesetzt.

Zum Schluss wird noch alle 30° eine Markierung gezeichnet und die Motoren in ihre Position gebracht. Der Minuten-Motor dreht sich jede Minute um 6°.  Wenn der Stunden-Motor sich 7° dreht, dreht sich der Zeiger 1° (Übertragung: 8/56 = 1/7). Also müsste sich Der Stunden-Motor jede Minute 3,5° drehen. Da er sich aber nur um 3° oder 4° drehen kann, dreht er sich jede volle Stunde zusätzlich um 30°. So ist der Zeiger am Stundenende 4.2° hinterher (d.h. 0,7 min). Beim Einstellen dreht sich der Stunden-Motor für jede Minute 3° und für jede Stunde 210°.

public void setTime(){
timer.setDelay(60000);
timer.start();

LCD.clear();
g = new Graphics();
g.clear();
if(soft_digi == 0){
g.drawString(hour+" : "+minute,(int)(LCD.SCREEN_WIDTH/2-(hour+" : "+minute).length()*LCD.FONT_WIDTH/2+0.5d) , 56);
}

if(soft_clock == 0){
g.drawLine(50, 32,
(int) (50 + 15 * Math.cos( (60+minute-15) * 2 * Math.PI / 60 )+0.5d),
(int) (32 + 15 * Math.sin( (60+minute-15) * 2 * Math.PI / 60 )+0.5d ));
g.drawLine(50, 32,
(int) (50 + 10 * Math.cos( (60*12+(hour*60+minute)-60*12/4) * 2 * Math.PI / (12*60) )+0.5d),
(int) (32 + 10 * Math.sin( (60*12+(hour*60+minute)-60*12/4) * 2 * Math.PI / (12*60) )+0.5d ));
for(int i = 0; i<12;i++){
g.drawLine((int) (50 + 17 * Math.cos( i * 2 * Math.PI / 12 )+0.5d),
(int) (32 + 17 * Math.sin(  i * 2 * Math.PI / 12 )+0.5d ),
(int) (50 + 20 * Math.cos(  i * 2 * Math.PI / 12 )+0.5d) ,
(int) (32 + 20 * Math.sin(  i * 2 * Math.PI / 12 )+0.5d ));
}
}

MotorHour.rotate(3*minute+hour*210, true);
MotorMinute.rotate(6*minute, true);
}

Der Code:

import javax.microedition.lcdui.Graphics;

import lejos.nxt.Button;
import lejos.nxt.ButtonListener;
import lejos.nxt.LCD;
import lejos.nxt.Motor;
import lejos.nxt.Sound;
import lejos.util.Timer;
import lejos.util.TimerListener;

public class Clock implements ButtonListener, TimerListener{

private Timer timer;
Graphics g;
Motor MotorHour = Motor.A;
Motor MotorMinute = Motor.B;

public int hard_clock = 0;
public int hard_sound = 0;
public int soft_clock = 0;
public int soft_digi = 0;
public int minute = 0;
public int hour = 0;

public boolean ENTER = false;
public boolean ESCAPE = false;
public boolean RIGHT = false;
public boolean LEFT = false;

public static void main(String[] args) throws InterruptedException{

Clock clock = new Clock();
clock.init();
while(true){
if(clock.ESCAPE){
System.exit(0);
}
}

}

public void init() throws InterruptedException{
Button.ENTER.addButtonListener(this);
Button.ESCAPE.addButtonListener(this);
Button.LEFT.addButtonListener(this);
Button.RIGHT.addButtonListener(this);
timer = new Timer(60000,this);

Sound.setVolume(100);
setHardClock();
}

public void setHardClock() throws InterruptedException{
hard_clock = setM(1,"HardClock Enable",new String[]{"ein","aus"});
if(ENTER){
Thread.sleep(500);
setHardSound();
}else if(ESCAPE){
Thread.sleep(500);
System.exit(0);
}
}
public void setHardSound() throws InterruptedException{
hard_sound = setM(3,"How often Sound",new String[]{"never","1 per Hour","2 per Hour","4 per Hour"});
if(ENTER){
Thread.sleep(500);
setSoftClock();
}else if(ESCAPE){
Thread.sleep(500);
setHardClock();
}
}
public void setSoftClock() throws InterruptedException{
soft_clock = setM(1,"SoftClock",new String[]{"ein","aus"});
if(ENTER){
Thread.sleep(500);
setSoftDigit();
}else if(ESCAPE){
Thread.sleep(500);
setHardSound();
}
}
public void setSoftDigit() throws InterruptedException{
soft_digi = setM(1,"DigitalClock",new String[]{"ein","aus"});
if(ENTER){
Thread.sleep(500);
setHour();
}else if(ESCAPE){
Thread.sleep(500);
setSoftClock();
}
}
public void setHour() throws InterruptedException{
hour =  setM(11,"Hour",new String[]{"0","1","2","3","4","5","6","7","8","9","10","11"});
if(ENTER){
Thread.sleep(500);
setMinute();
}else if(ESCAPE){
Thread.sleep(500);
setSoftDigit();
}
}
public void setMinute() throws InterruptedException{
minute = setM(59,"Minute",new String[]{"0","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","47","48","49","50","51","52","53","54","55","56","57","58","59"});
if(ENTER){
Thread.sleep(500);
setTime();
}else if(ESCAPE){
Thread.sleep(500);
setHour();
}
}

public int setM(int max, String quest, String[] ans) throws InterruptedException{
int posnow = 0;
while(!ENTER && !ESCAPE){
Thread.sleep(500);
LCD.clear();
if(RIGHT && posnow == max){
posnow = 0;
}else if(RIGHT && posnow != max){
posnow ++;
}else if(LEFT && posnow == 0){
posnow = max;
}else if(LEFT &&posnow != 0){
posnow --;
}
System.out.println(quest);
System.out.println(ans[posnow]);
}
return posnow;
}

/*
* 3*minute     :jede minute dreht sich der stundenmotor 3(3,5 = 360:(60*12)*7) grad;
* #+hour*30      :jede stunde dreht sich der stundenmotor 0,5*60 = 30 grad;
* +hour*210     :für jede bereits vergangene stunde muss sich der stundenmotor 30*7 (360:12*7) grad drehen;
*
* 6*minute        :jede minute dreht sich der minutenmotor 6 grad;
*/
public void setTime(){
timer.setDelay(60000);
timer.start();

LCD.clear();
g = new Graphics();
g.clear();
if(soft_digi == 0){
g.drawString(hour+" : "+minute,(int)(LCD.SCREEN_WIDTH/2-(hour+" : "+minute).length()*LCD.FONT_WIDTH/2+0.5d) , 56);
}

if(soft_clock == 0){
g.drawLine(50, 32,
(int) (50 + 15 * Math.cos( (60+minute-15) * 2 * Math.PI / 60 )+0.5d),
(int) (32 + 15 * Math.sin( (60+minute-15) * 2 * Math.PI / 60 )+0.5d ));
g.drawLine(50, 32,
(int) (50 + 10 * Math.cos( (60*12+(hour*60+minute)-60*12/4) * 2 * Math.PI / (12*60) )+0.5d),
(int) (32 + 10 * Math.sin( (60*12+(hour*60+minute)-60*12/4) * 2 * Math.PI / (12*60) )+0.5d ));
for(int i = 0; i<12;i++){
g.drawLine((int) (50 + 17 * Math.cos( i * 2 * Math.PI / 12 )+0.5d),
(int) (32 + 17 * Math.sin(  i * 2 * Math.PI / 12 )+0.5d ),
(int) (50 + 20 * Math.cos(  i * 2 * Math.PI / 12 )+0.5d) ,
(int) (32 + 20 * Math.sin(  i * 2 * Math.PI / 12 )+0.5d ));
}
}

MotorHour.rotate(3*minute+hour*210, true);
MotorMinute.rotate(6*minute, true);
}

public void nextMinute() throws InterruptedException{

minute++;
if(minute == 60){
minute = 0;
hour++;
if(hour == 12){
hour=0;
}
}

if(hard_clock == 0){
if(minute == 0){
MotorHour.rotate(3+30,true);
MotorMinute.rotate(6,true);
}else{
MotorHour.rotate(3,true);
MotorMinute.rotate(6,true);
}
}
if(hard_sound > 0){
if(minute == 0){
for(int i = 0; i< hour;i++){
Sound.buzz();
Thread.sleep(100);
}
if(hour == 0){
for(int i = 0; i< 12;i++){
Sound.buzz();
Thread.sleep(100);
}
}
}
if(minute == 30 && hard_sound < 1){
for(int i = 0; i<2; i++){
Sound.beep();
Thread.sleep(100);
}
}
if(minute == 15 && hard_sound < 2){
Sound.beep();
Thread.sleep(100);
}
if(minute == 45 && hard_sound < 2){
for(int i = 0; i<3; i++){
Sound.beep();
Thread.sleep(100);
}
}

}

g.clear();
if(soft_digi == 0){
g.drawString(hour+" : "+minute, (int)(LCD.SCREEN_WIDTH/2-(hour+" : "+minute).length()*LCD.FONT_WIDTH/2+0.5d), 56);
}

if(soft_clock == 0){

for(int i = 0; i<12;i++){
g.drawLine((int) (50 + 17 * Math.cos( i * 2 * Math.PI / 12 )+0.5d),
(int) (32 + 17 * Math.sin(  i * 2 * Math.PI / 12 )+0.5d ),
(int) (50 + 20 * Math.cos(  i * 2 * Math.PI / 12 )+0.5d) ,
(int) (32 + 20 * Math.sin(  i * 2 * Math.PI / 12 )+0.5d ));
}

//15 = länge minutenzeiger

g.drawLine(50, 32,
(int) (50 + 15 * Math.cos( (60+minute-15) * 2 * Math.PI / 60 )+0.5d),
(int) (32 + 15 * Math.sin( (60+minute-15) * 2 * Math.PI / 60 )+0.5d ));

//10 = länge stundenzeiger

g.drawLine(50, 32,
(int) (50 + 10 * Math.cos( (60*12+(hour*60+minute)-60*12/4) * 2 * Math.PI / (12*60) )+0.5d),
(int) (32 + 10 * Math.sin( (60*12+(hour*60+minute)-60*12/4) * 2 * Math.PI / (12*60) )+0.5d ));

}
}

@Override
public void buttonPressed(Button arg0) {
if(arg0 == Button.ENTER){
ENTER = true;
}else if(arg0 == Button.ESCAPE){
ESCAPE = true;
}else if(arg0 == Button.LEFT){
LEFT = true;
}else if(arg0 == Button.RIGHT){
RIGHT = true;
}
}

@Override
public void buttonReleased(Button arg0) {
if(arg0 == Button.ENTER){
ENTER = false;
}else if(arg0 == Button.ESCAPE){
ESCAPE = false;
}else if(arg0 == Button.LEFT){
LEFT = false;
}else if(arg0 == Button.RIGHT){
RIGHT = false;
}
}

@Override
public void timedOut() {
try {
nextMinute();
} catch (InterruptedException e) {
}
}
}

Viel Spaß beim ausprobieren😉

Schreibe einen Kommentar

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s