Benutzer-Werkzeuge

Webseiten-Werkzeuge


virtuelles_java-teleskop

virtelles Java-Teleskop

Übersicht

Die grundsätzliche Arbeitsweise zwischen Linux und dem Teleskop (Steuerung) kann man auch ohne Elektronik (& Teleskop) studieren. Die drei großen Clients (KStart, Skychart und Stellarium) können mit der Indi-Schnittstelle kommunizieren und virtuelle Teleskopmontierungen einbinden. Diese Teleskopsimulatoren sind technisch gesehen INDI-C-Treiber. Ich erzeuge hier z.B. mit Java eine virtuelle serielle Schnittstelle und benutze „täusche“ eine rudimentäre LX200 Montierung vor, die mit Stellarium verwendet werden kann.

Software

Um mit Java auf die serielle Schnittstelle zugreifen zu können, verwenden wir die jSSC (Java Simple Serial Connector) API. Sie besteht aus nur einer jar-Datei und wird auch von der Arduino-IDE selbst verwendet. In Eclipse wird sie über Eigenschaften (Java Build Path - Add External JAR's…) dem Projekt hinzugefügt. https://code.google.com/archive/p/java-simple-serial-connector/ oder serial.zip

Installation und Inbetriebnahme

  1. Eclipseprojekt erzeugen und die Datei (unten) SimulatorTeleskop einfügen
  2. jssc-2.0.0.jar als Externe Library dem Projekt hinzufügen
  3. Projekt mit Eclipse übersetzen (kann nicht fehlerfrei gestartet werden, da die Schnittstelle „/dev/ttyUSB60“ nicht vorhanden ist)
  4. Virtuelle serielle Schnittstelle erzeugen - Rechte setzen - Testen
Details

Die folgenden beiden befehle erfordern Rootrechte. Außerdem müssen auf diese Weise angelegte Schnittstellen muss häufig neu eingerichtet werden. Nicht vergessen, dieses Projekt soll zum eigenen Experimentieren anregen und lediglich die grundlegende Kommunikation aufzeigen.

Die virtuelle Schnittstelle wird mit dem folgenden Befehl gesetzt

socat -d -d PTY,link=/dev/ttyUSB60 PTY,link=/dev/ttyUSB61

Anschließend werden zum Testen alle Rechte vergeben

# chmod 777 /dev/ttyUSB6*

Überprüfen Sie (Konsole ls-Befehl) ob alles richtig gemacht wurde 8-)

Test 1: Konsole

Ein erste Test erfolgt mit einer User-Konsole, indem folgender Befehl an das Gerät gesendet wird, zuvor muss das Programm (z.B. über Eclipse gestartet werden).

echo ":GD#" > /dev/ttyUSB61

Auf der Konsole (Eclipse) sollten jetzt die Anzahl der gelesenen Bytes angezeigt werden. Damit funktioniert die Kommunikation über die virtuelle serielle Schnittstelle.

  1. Schnittstelle einrichten (socat,chmod)
  2. Java SimulatorTeleskop starten
  3. In einer Userkonsole echo „:GD#“ > /dev/ttyUSB61 eingeben
Test 2: Stellarium

Der zweite Test ist spannender, da wir mit Stellarium kommunizieren.

  1. LX200 Teleskop einrichten mit /dev/ttyUSB61 als Device (noch nicht verbinden!)
  2. Schnittstelle einrichten (socat, chmod)
  3. Java SimulatorTeleskop starten
  4. LX200 Teleskop in Stellarium verbinden

Quellcode Projekt A

Das Protokoll kann hier eingesehen werden LX200 Seriell-Protokoll

Das Javaprogramm implementiert nur wenige Kommandos des Protokolls. Nachdem Stellarium sich mit dem „Teleskop“ (Javaprogramm) verbunden hat, sendet es permanent Anfragen um die Rektaszension (#:GR#) und die Deklination (#:GE#) des Telekops zu erhalten.

Wenn mit Stellarium geschwenkt werden soll, d.h. ein bestimmtes Objekt angefahren werden soll, werden drei Kommandos geschickt. Die ersten beiden Kommandos übermitteln die Zielkoordinaten, während das dritte Kommando (:MS#) eine Bestätigung erwartet um das Teleskop zu schwenken. Diese Befehle sind im LX200 Seriell-Protokoll aufgelistet. Damit wir bei Stellarium eine animierte Bewegung sehen, wurde die Methode simulateMove() hinzugefügt, die lediglich die RA-Achse in zehn Schritten von den aktuellen Koordinaten currentRA zu den Zielkoordinaten targetRA bewegt.

/** LX200 Protocol 
 * @author torsten.roehl@fsg-preetz.org
 * simple demo to communicate with a indi-client!
 */
 
import java.util.Timer;
import java.util.TimerTask;
 
import jssc.SerialPort;
import jssc.SerialPortException;
 
public class SimulatorTeleskop {
 
	static String currentRA = "02:31:50#";
	static String currentDE = "+89*15#";
 
	static String targetRA = currentRA;
	static String targetDE = currentDE;
 
	static String dev = "/dev/ttyUSB60";
 
	public enum Protocol // some serial lx200 commands
	{
		CMD_GR, CMD_GD, CMD_QS, CMD_SD, CMD_MS, CMD_UNKNOWN
	}
 
	public static void main(String[] args) throws InterruptedException {
 
		SerialPort serialPort = new SerialPort(dev);
		try {
			serialPort.openPort();
			serialPort.setParams(9600, 8, 1, 0);
			System.out.println("...	initializing the serial port");
			Thread.sleep(4000); // necessary, otherwise serial will fail!!!
 
		} catch (SerialPortException e1) {
			e1.printStackTrace();
		}
 
		try {
			while (true) {
 
				String msg = decode(serialPort);
				Protocol cmd = protocol(msg);
 
				switch (cmd) {
				case CMD_GR:
					writeMessage(serialPort, currentRA);
					break;
				case CMD_GD:
					writeMessage(serialPort, currentDE);
					break;
				case CMD_QS:
					targetRA = msg.substring(msg.indexOf(' ')).trim();
					writeMessage(serialPort, "1");
					break;
				case CMD_SD:
					currentDE = msg.substring(msg.indexOf(' ')).trim();
					targetDE = currentDE;
					writeMessage(serialPort, "1");
					break;
				case CMD_MS:
					writeMessage(serialPort, "0");
					simulateMove();
					break;
				case CMD_UNKNOWN:
					if (!msg.startsWith("zero"))
						System.out.println("...received unknown serial command: " + msg);
					break;
				}
 
				Thread.sleep(100);
 
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
 
		try {
			serialPort.closePort();
		} catch (SerialPortException e) {
			e.printStackTrace();
		}
 
	}
 
	private static Protocol protocol(String msg) {
 
		if (msg.startsWith("#:GR#"))
			return Protocol.CMD_GR;
		if (msg.startsWith("#:GD#"))
			return Protocol.CMD_GD;
		if (msg.startsWith("#:Q#:S"))
			return Protocol.CMD_QS;
		if (msg.startsWith(":Sd "))
			return Protocol.CMD_SD;
		if (msg.startsWith(":MS#"))
			return Protocol.CMD_MS;
 
		return Protocol.CMD_UNKNOWN;
	}
 
	static String decode(SerialPort serialPort) {
		try {
			// step 1: read bytes from port
			byte[] buffer = serialPort.readBytes();
			// step 2: verify
			if (buffer == null)
				return "zero buffer";
 
			int numRead = buffer.length;
			if (buffer.length <= 0)
				return "zero length";
 
			// step 3: convert buffer to string
			String res = "";
			for (int i = 0; i < numRead; i++) {
				byte b = buffer[i];
 
				// fixme: problem with Star *
				char c = (char) b;
				if (b == -33)
					c = '*';
				res += c;
 
			}
			return res;
 
		} catch (SerialPortException e) {
			e.printStackTrace();
		}
 
		return "should not happen";
	}
 
	static void writeMessage(SerialPort p, String msg) {
		try {
			byte[] buffer = msg.getBytes();
			p.writeBytes(buffer);
		} catch (SerialPortException e) {
			e.printStackTrace();
		}
	}
 
	/**
	 * helper method convert a ra-string to a number (for arithmetic use)
	 */
	static int string2int(String str) {
		String tmp = str.substring(0, str.length() - 1);
		String lsTmp[] = tmp.split(":");
		int res = 3600 * Integer.valueOf(lsTmp[0]) + 60 * Integer.valueOf(lsTmp[1]) + Integer.valueOf(lsTmp[2]);
		return res;
	}
 
	/**
	 * helper method to convert a number into ra-string
	 */
	static String number2string(double number) {
 
		int h = (int) (number - (number % 3600)) / 3600;
		int rest = (int) (number - h * 3600);
		int m = (int) (rest - (rest % 60)) / 60;
		rest = rest - m * 60;
		int s = rest;
 
		String strH = String.format("%02d", h);
		String strM = String.format("%02d", m);
		String strS = String.format("%02d", s);
		return strH + ":" + strM + ":" + strS + "#";
	}
 
	/**
	 * dummy method to simulate kind of telescope motion - using ten steps only
	 * in ra-axis
	 */
	static void simulateMove() {
		TimerTask repeatedTask = new TimerTask() {
 
			int run = 0;
			double stepwidth = 0;
			int iTo = 0;
			int iFrom = 0;
 
			public void run() {
				System.out.println(run + " ...move simulation ");
 
				// step 0: calculate stepwidth once
				if (run == 0) {
					iFrom = string2int(currentRA);
					iTo = string2int(targetRA);
					stepwidth = (iTo - iFrom) / 10.0;
				}
				// step 1: adjust currentRA with stepwidth
				if (run > 0) {
					currentRA = number2string(iFrom + run * stepwidth);
				}
 
				// step 2: finish motion
				run++;
				if (run > 10) {
					currentRA = targetRA;
					cancel();
				}
			}
		};
		Timer timer = new Timer("Timer");
		timer.scheduleAtFixedRate(repeatedTask, 0, 250);
	}
 
}

Das dieses einfache Programm (die nur wenige Kommandos des Protokolls implementiert) funktioniert, verdanken wir den saloppen Umgang von Stellarium (getestet mit 0.18.0) mit dem Protokoll. Eine verfünftige Initialisierung (Handschake) ist beispielsweise nicht erforderlich.

virtuelles_java-teleskop.txt · Zuletzt geändert: 2023/01/21 13:43 von torsten.roehl