diff --git a/mpu9250.py b/mpu9250.py new file mode 100755 index 0000000..2e9d3c4 --- /dev/null +++ b/mpu9250.py @@ -0,0 +1,205 @@ +#!/usr/bin/env python +from __future__ import print_function + +import sys +from time import sleep, time +from math import pi, sin, cos, asin, acos, atan2, sqrt +import numpy as np + +try: + import time + from mpu9250_jmdev.registers import * + from mpu9250_jmdev.mpu_9250 import MPU9250 + + mpu = MPU9250( + address_ak=AK8963_ADDRESS, + address_mpu_master=MPU9050_ADDRESS_68, # In 0x68 Address + address_mpu_slave=None, + bus=1, + gfs=GFS_1000, + afs=AFS_8G, + mfs=AK8963_BIT_16, + mode=AK8963_MODE_C100HZ) + + mpu.configure() +except ImportError: + sys.stderr.write("Ensure mpu9250_jmdev is present and importable\n") + sys.exit(1) + +#Local imports +from quaternions import _check_close +from quaternions import quaternion_to_rotation_matrix_rows, quaternion_from_rotation_matrix_rows +from quaternions import quaternion_from_axis_angle +from quaternions import quaternion_from_euler_angles, quaternion_to_euler_angles +from quaternions import quaternion_multiply, quaternion_normalise + +class GYMOD(object): + def __init__(self, bus=None): + self._last_gyro_time = 0 #needed for interpreting gyro + self.read_gyro_delta() #Discard first reading + q_start = self.current_orientation_quaternion_mag_acc_only() + self._q_start = q_start + self._current_hybrid_orientation_q = q_start + self._current_gyro_only_q = q_start + + def update(self): + """Read the current sensor values & store them for smoothing. No return value.""" + t = time.time() + delta_t = t - self._last_gyro_time + if delta_t < 0.020: + #Want at least 20ms of data + return + v_gyro = np.array(self.read_gyro(), np.float) + v_acc = np.array(self.read_accel(), np.float) + v_mag = np.array(self.read_compass(), np.float) + self._last_gyro_time = t + + #Gyro only quaternion calculation (expected to drift) + rot_mag = sqrt(sum(v_gyro**2)) + v_rotation = v_gyro / rot_mag + q_rotation = quaternion_from_axis_angle(v_rotation, rot_mag * delta_t) + self._current_gyro_only_q = quaternion_multiply(self._current_gyro_only_q, q_rotation) + self._current_hybrid_orientation_q = quaternion_multiply(self._current_hybrid_orientation_q, q_rotation) + + if abs(sqrt(sum(v_acc**2)) - 1) < 0.3: + #Approx 1g, should be stationary, and can use this for down axis... + v_down = v_acc * -1.0 + v_east = np.cross(v_down, v_mag) + v_north = np.cross(v_east, v_down) + v_down /= sqrt((v_down**2).sum()) + v_east /= sqrt((v_east**2).sum()) + v_north /= sqrt((v_north**2).sum()) + #Complementary Filter + #Combine (noisy) orientation from acc/mag, 2% + #with (drifting) orientation from gyro, 98% + q_mag_acc = quaternion_from_rotation_matrix_rows(v_north, v_east, v_down) + self._current_hybrid_orientation_q = tuple(0.02*a + 0.98*b for a, b in + zip(q_mag_acc, self._current_hybrid_orientation_q)) + + + #1st order approximation of quaternion for this rotation (v_rotation, delta_t) + #using small angle approximation, cos(theta) = 1, sin(theta) = theta + #w, x, y, z = (1, v_rotation[0] * delta_t/2, v_rotation[1] *delta_t/2, v_rotation[2] * delta_t/2) + #q_rotation = (1, v_rotation[0] * delta_t/2, v_rotation[1] *delta_t/2, v_rotation[2] * delta_t/2) + return + + def current_orientation_quaternion_hybrid(self): + """Current orientation using North, East, Down (NED) frame of reference.""" + self.update() + return self._current_hybrid_orientation_q + + def current_orientation_quaternion_mag_acc_only(self): + """Current orientation using North, East, Down (NED) frame of reference.""" + #Can't use v_mag directly as North since it will usually not be + #quite horizontal (requiring tilt compensation), establish this + #using the up/down axis from the accelerometer. + #Note assumes starting at rest so only acceleration is gravity. + v_acc = np.array(self.read_accel(), np.float) + v_mag = np.array(self.read_compass(), np.float) + return self._quaternion_from_acc_mag(v_acc, v_mag) + + def _quaternion_from_acc_mag(self, v_acc, v_mag): + v_down = v_acc * -1.0 #(sign change depends on sensor design?) + v_east = np.cross(v_down, v_mag) + v_north = np.cross(v_east, v_down) + #Normalise the vectors... + v_down /= sqrt((v_down ** 2).sum()) + v_east /= sqrt((v_east ** 2).sum()) + v_north /= sqrt((v_north ** 2).sum()) + return quaternion_from_rotation_matrix_rows(v_north, v_east, v_down) + + def current_orientation_euler_angles_hybrid(self): + """Current orientation using yaw, pitch, roll (radians) using sensor's frame.""" + return quaternion_to_euler_angles(*self.current_orientation_quaternion_hybrid()) + + def current_orientation_euler_angles_mag_acc_only(self): + """Current orientation using yaw, pitch, roll (radians) using sensor's frame.""" + return quaternion_to_euler_angles(*self.current_orientation_quaternion_mag_acc_only()) + + def read_accel(self, scaled=True): + """Returns an X, Y, Z tuple; if scaled in units of gravity.""" + accel = mpu.readAccelerometerMaster() + if scaled: + return accel[0], accel[1], accel[2] + else: + return accel[0], accel[1], accel[2] + + def read_gyro(self, scaled=True): + """Returns an X, Y, Z tuple; If scaled uses radians/second. + + WARNING: Calling this method directly will interfere with the higher-level + methods like ``read_gyro_delta`` which integrate the gyroscope readings to + track orientation (it will miss out on the rotation reported in this call). + """ + gyro = mpu.readGyroscopeMaster() + if scaled: + return gyro[0], gyro[1], gyro[2] + else: + return gyro[0], gyro[1], gyro[2] + + def read_gyro_delta(self): + """Returns an X, Y, Z tuple - radians since last call.""" + t = time.time() + gyro = mpu.readGyroscopeMaster() + d = np.array([gyro[0], gyro[1], gyro[2]], np.float) / (t - self._last_gyro_time) + self._last_gyro_time = t + return d + + def read_compass(self, scaled=True): + """Returns an X, Y, Z tuple.""" + compass = mpu.readMagnetometerMaster() + if scaled: + return compass[0], compass[1], compass[2] + else: + return compass[0], compass[1], compass[2] + + +if __name__ == "__main__": + print("Starting...") + imu = GYMOD() + + #Sanity test: + x, y, z = imu.read_accel() + g = sqrt(x*x + y*y + z*z) + print("Magnitude of acceleration %0.2fg (%0.2f %0.2f %0.2f)" % (g, x, y, z)) + if abs(g - 1) > 0.3: + sys.stderr.write("Not starting from rest, acceleration %0.2f\n" % g) + sys.exit(1) + print("Starting q by acc/mag (%0.2f, %0.2f, %0.2f, %0.2f)" % imu._q_start) + + try: + while True: + print() + imu.update() + #w, x, y, z = imu.current_orientation_quaternion_hybrid() + w, x, y, z = imu._current_hybrid_orientation_q + #print("Gyroscope/Accl/Comp q (%0.2f, %0.2f, %0.2f, %0.2f)" % (w, x, y, z)) + yaw, pitch, roll = quaternion_to_euler_angles(w, x, y, z) + print("Gyroscope/Accl/Comp q (%0.2f, %0.2f, %0.2f, %0.2f), " + "yaw %0.1f, pitch %0.2f, roll %0.1f (degrees)" % (w, x, y, z, + yaw * 180.0 / pi, + pitch * 180.0 / pi, + roll * 180.0 / pi)) + + w, x, y, z = imu._current_gyro_only_q + #print("Gyro-only quaternion (%0.2f, %0.2f, %0.2f, %0.2f)" % (w, x, y, z)) + yaw, pitch, roll = quaternion_to_euler_angles(w, x, y, z) + print("Gyro-only quaternion (%0.2f, %0.2f, %0.2f, %0.2f), " + "yaw %0.1f, pitch %0.2f, roll %0.1f (degrees)" % (w, x, y, z, + yaw * 180.0 / pi, + pitch * 180.0 / pi, + roll * 180.0 / pi)) + + w, x, y, z = imu.current_orientation_quaternion_mag_acc_only() + #print("Accel/Comp quaternion (%0.2f, %0.2f, %0.2f, %0.2f)" % (w, x, y, z)) + yaw, pitch, roll = quaternion_to_euler_angles(w, x, y, z) + print("Accel/Comp quaternion (%0.2f, %0.2f, %0.2f, %0.2f), " + "yaw %0.1f, pitch %0.2f, roll %0.1f (degrees)" % (w, x, y, z, + yaw * 180.0 / pi, + pitch * 180.0 / pi, + roll * 180.0 / pi)) + sleep(0.25) + except KeyboardInterrupt: + print() + pass + print("Done") diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..3749a8d --- /dev/null +++ b/readme.md @@ -0,0 +1,56 @@ +# Original Project + +In 2014 or there abouts [Peter Cook](https://github.com/peterjc) put together an amzing little project. + +[Blog Posts](http://astrobeano.blogspot.com/2014/01/instrumented-telescope-with-raspberry.html) + +The idea was to use a Raspberry Pi and Gyro sensors to create a "Push To" style mount for his telescope. + +>Instrumented Telescope with Raspberry Pi and orientation sensor +>A "Push To" telescope mount is like a fully automated "Go To" telescope mount, but without the motors. You must manually move the telescope, but because the >telescope knows where it is pointed, you get live tracking telling you where it needs to go. + +Fast forward to 2022, +- the GY-80 module originally used is out of date. +- astropysics - a Python module used is no longer maintained +- SkySafari has a whole lot of new versions + +This project is now an attempt to perseve the original hard work and begin to refactor the code. The needs I have are limited to the "Push To", image capturing and camera connection are not something I am focused on. + +# Current Progress + +- [Corrections to Date](results/corrections.md) +- [Open Items](results/todo.md) + +# Sky Safari Plus + +Testing in the original project was done in Sky Safari Plus 4.0, current testing is in Sky Safari Plus 7.0 + +Telescope usually setup as: + +``` +Scope Type: Meade LX-200 GPS +Mount Type: Equatorial Push-To (or any push to setting) +Auto-Detect SkyFi: Off +IP Address: That of the computer running this script (default 10.0.0.1) +Port Number: 4030 (default) +Set Time & Location: On (default is off) +Readout Rate: 4 per second (default) +Save Log File: Off (default) +``` + +# Protocol + +[LX-200](https://www.meade.com/support/LX200CommandSet.pdf) + +# Tools + +In order to try and understand Latitude and Longitude, and how to convert that to degrees and then to radians + +- [Decimal Degrees Units to Degrees, Minutes and Seconds Converter](https://www.engineeringtoolbox.com/latitude-longitude-d_1371.html) +- [Converting degrees to radians and vice versa](https://planetcalc.com/71/) + +Example Greenwich +- 51.4934° N, 0.0098° E +- > Latitude : 51 deg 29 min 36.24 sec + > Longitude: 0 deg 0 min 35.28 sec +- Radians 0.898729 0.000171 diff --git a/results/RPReplay_Final1643059606.MOV b/results/RPReplay_Final1643059606.MOV new file mode 100644 index 0000000..3748935 Binary files /dev/null and b/results/RPReplay_Final1643059606.MOV differ diff --git a/results/corrections.md b/results/corrections.md new file mode 100644 index 0000000..4171127 --- /dev/null +++ b/results/corrections.md @@ -0,0 +1,146 @@ +# Corrections + +These are the basic script changes currently being attempted. + +``` +#TODO - Try astropy if I can get it to compile on Mac OS X... +from astropysics import coords +from astropysics import obstools +``` + +*astropysics* is no longer maintained and the work has been invested into *astropy* + +``` +from astropy.coordinates import SkyCoord, EarthLocation, AltAz, Longitude, Angle +from astropy import coordinates as coord +from astropy.time import Time +from astropy import units as u +import numpy as np +``` + +The following has been added + +``` +from datetime import datetime as dt +``` + +For the Hardware module as the GY80 is no longer easily found. The reference is now simply GYMOD and changed throughout where GY80 was before and an alternative local import has been made. + +``` +#Local import +from mpu9250 import GYMOD +``` + +The first major portion of code that required changing was lines *111 - 118* + +``` +#Default to Greenwich, GMT - Latitude 51deg 28' 38'' N, Longitude zero +local_site = obstools.Site(coords.AngularCoordinate(config.get("site", "latitude")), + coords.AngularCoordinate(config.get("site", "longitude")), + tz=0) +#Rather than messing with the system clock, will store any difference +#between the local computer's date/time and any date/time set by the +#client (which should match any location set by the client). +local_time_offset = 0 +``` + +I believe the following is the correct way using *astropy* + +``` +obs = obs_time() +location = EarthLocation.of_address(site_address) +``` + +The next major code portion was with lines *191-197* + +``` +def greenwich_sidereal_time_in_radians(): + """Calculate using GMT (according to client's time settings).""" + #Function astropysics.obstools.epoch_to_jd wants a decimal year as input + #Function astropysics.obstools.calendar_to_jd can take a datetime object + gmt_jd = obstools.calendar_to_jd(site_time_gmt_as_datetime()) + #Convert from hours to radians... 24hr = 2*pi + return coords.greenwich_sidereal_time(gmt_jd) * pi / 12 +``` + +I believe the following is the correct way using *astropy* + +``` +def greenwich_sidereal_time_in_radians(): + return t.sidereal_time('apparent', 'greenwich').radian[0] +``` + +The next items were in the *def alt_az_to_equatorial* and *def equatorial_to_alt_az(ra, dec, gst=None):* and are related to getting the latitude and longitude of the local_site object. + +If correct then this should be the solution + +``` +def alt_az_to_equatorial(alt, az, gst=None): + global site_longitude, site_latitude, location #and time offset used too + if gst is None: + gst = greenwich_sidereal_time_in_radians() + + lat = Angle(location.geodetic.lat, u.radian) + #Calculate these once only for speed + sin_lat = sin(lat.radian) + cos_lat = cos(lat.radian) + sin_alt = sin(alt) + cos_alt = cos(alt) + sin_az = sin(az) + cos_az = cos(az) + # DEC based on latitude in radians + dec = asin(sin_alt*sin_lat + cos_alt*cos_lat*cos_az) + hours_in_rad = acos((sin_alt - sin_lat*sin(dec)) / (cos_lat*cos(dec))) + if sin_az > 0.0: + hours_in_rad = 2*pi - hours_in_rad + # Now figure out RA based on Longitude in Radians + lon = Angle(site_longitude, u.radian) + ra = gst - lon.radian - hours_in_rad + return ra % (pi*2), dec + +def equatorial_to_alt_az(gst=None): + > PENDING +``` + +With Python 3 socket connection handling changed slightly. + +Slight modification to line *751* and *791* + +``` + data_received = connection.recv(16) + data = data_received.decode() +``` + +``` +connection.sendall(resp.encode()) +``` + +Configuration section has been altered and changed, extended variables + +``` +print("Checking Configuration") +config_file = "telescope_server.ini" +if not os.path.isfile(config_file): + print("Using default settings") + h = open("telescope_server.ini", "w") + h.write("[server]\nname=127.0.0.1\nport=4030\n") + #Default to Greenwich as the site, 1 as tz + h.write("[site]\naddress=Greenwich\n") + h.write("[site]\ntz=1\n") + h.write("[site]\nlatitude=51.4934\n") + h.write("[site]\nlongitude=0.0098\n") + #Default to no correction of the angles + h.write("[offsets]\nazimuth=0\naltitude=0\n") + h.close() +``` +To help with debugging, and I added a lot of debugging statements + +``` +def debug_info(str): + if debug: + sys.stdout.write("%s\n" % str) +``` + +Usage is + +> debug_info("FUNCTION update_alt_az - local_alt %r - local_aaz %r" % (local_alt, local_az) ) diff --git a/results/log_slew_test_24Jan2230.txt b/results/log_slew_test_24Jan2230.txt new file mode 100644 index 0000000..0f22e03 --- /dev/null +++ b/results/log_slew_test_24Jan2230.txt @@ -0,0 +1,1107 @@ +{\rtf1\ansi\ansicpg1252\cocoartf2636 +\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 Menlo-Regular;} +{\colortbl;\red255\green255\blue255;\red0\green0\blue0;} +{\*\expandedcolortbl;;\csgray\c0;} +\paperw11900\paperh16840\margl1440\margr1440\vieww11520\viewh8400\viewkind0 +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0 + +\f0\fs22 \cf2 \CocoaLigature0 Checking Configuration\ +Connecting to sensors...\ +Connected to MPU9250 sensor\ +Opening network port...\ +\ +Starting up on 192.168.86.42 port 4030\ +Processing ':St+51*40#'\ +Command ':St', argument '+51*40'\ +Error with :St+51d40# latitude: Cannot parse first argument data "" for attribute ra\ +Command ':St', sending '0'\ +Processing ':Sg351*40#'\ +Command ':Sg', argument '351*40'\ +Error with :Sg351d40# longitude: Cannot parse first argument data "" for attribute dec\ +Command ':Sg', sending '0'\ +Processing ':SG-01.0#'\ +Command ':SG', argument '-01.0'\ +Local site timezone now -1.0\ +Command ':SG', sending '1'\ +Processing ':SG-01.0#'\ +Command ':SG', argument '-01.0'\ +Local site timezone now -1.0\ +Command ':SG', sending '1'\ +Processing ':SL22:26:04#'\ +Command ':SL', argument '22:26:04'\ +Requested site time 22:26:04 (TZ -1.0), new offset -1s, total offset -1s\ +Effective site date/time is 2022-01-24 23:26:04.142641 (local time), 2022-01-24 22:26:04.142864 (GMT/UTC)\ +Command ':SL', sending '1'\ +Processing ':SC01/24/22#'\ +Command ':SC', argument '01/24/22'\ +Requested site date 01/24/22 (MM/DD/YY) gives offset of 0 days\ +Effective site date/time is 2022-01-24 23:26:04.189068 (local time), 2022-01-24 22:26:04.189285 (GMT/UTC)\ +Command ':SC', sending '1Updating Planetary Data# #'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 0.10292361038863089\ +az 0.42004365151408446\ +Command ':GR', sending '23:59:32#'\ +Processing ':RS#'\ +Command ':RS', no response\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.440997552407953\ +az 1.2140914244190644\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 46.008625497311016\ +fraction: 0.003731634555151686\ +degress: 2636.0\ +return: -2636*06:00#\ +RA 00:20:53# (0.09112 radians), dec -46*06:00# (-46.00863 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 46.008625497311016\ +fraction: 0.003731634555151686\ +degress: 2636.0\ +return: -2636*06:00#\ +Command ':GD', sending '-46*06:00#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.808362700194987\ +az 3.07963767357625\ +Command ':GR', sending '00:22:21#'\ +Processing ':RS#'\ +Command ':RS', no response\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 0.641698367546771\ +az 3.725347645374688\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 43.49736927635536\ +fraction: 0.9407674306730769\ +degress: 2492.0\ +return: -2492*12:56#\ +RA 00:01:41# (0.00736 radians), dec -43*12:56# (-43.49737 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 43.49736927635536\ +fraction: 0.9407674306730769\ +degress: 2492.0\ +return: -2492*12:56#\ +Command ':GD', sending '-43*12:56#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 1.0745937086517492\ +az 5.590678768612702\ +Command ':GR', sending '00:03:25#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.736179916095925\ +az 0.436966905661191\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 46.7857500160689\ +fraction: 0.5610364922704321\ +degress: 2680.0\ +return: -2680*37:34#\ +RA 00:22:04# (0.09627 radians), dec -46*37:34# (-46.78575 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 46.7857500160689\ +fraction: 0.5610364922704321\ +degress: 2680.0\ +return: -2680*37:34#\ +Command ':GD', sending '-46*37:34#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.4819789839372\ +az 2.475752634821676\ +Command ':GR', sending '00:21:03#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 0.07481910364127334\ +az 3.3351532019959023\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 43.887563719734146\ +fraction: 0.3304551343226194\ +degress: 2514.0\ +return: -2514*34:20#\ +RA 23:59:25# (6.28065 radians), dec -43*34:20# (-43.88756 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 43.887563719734146\ +fraction: 0.3304551343226194\ +degress: 2514.0\ +return: -2514*34:20#\ +Command ':GD', sending '-43*34:20#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 0.7154476635528066\ +az 4.218109437521921\ +Command ':GR', sending '00:01:59#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 0.42828276008929456\ +az 5.781169522001875\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 41.441547399728165\ +fraction: 0.5457497464976768\ +degress: 2374.0\ +return: -2374*25:33#\ +RA 00:00:50# (0.00363 radians), dec -41*25:33# (-41.44155 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 41.441547399728165\ +fraction: 0.5457497464976768\ +degress: 2374.0\ +return: -2374*25:33#\ +Command ':GD', sending '-41*25:33#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.93768760061464\ +az 0.6672046677353796\ +Command ':GR', sending '00:22:52#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.478300163592391\ +az 2.325091590385063\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 44.89762533134501\ +fraction: 0.666498743388729\ +degress: 2572.0\ +return: -2572*26:40#\ +RA 00:21:02# (0.09177 radians), dec -44*26:40# (-44.89763 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 44.89762533134501\ +fraction: 0.666498743388729\ +degress: 2572.0\ +return: -2572*26:40#\ +Command ':GD', sending '-44*26:40#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 6.224637980392942\ +az 3.5724636207846743\ +Command ':GR', sending '00:24:01#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 0.6578588365330386\ +az 5.355471133129083\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 41.867245788601\ +fraction: 0.9890114224272111\ +degress: 2398.0\ +return: -2398*48:59#\ +RA 00:01:45# (0.00764 radians), dec -41*48:59# (-41.86725 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 41.867245788601\ +fraction: 0.9890114224272111\ +degress: 2398.0\ +return: -2398*48:59#\ +Command ':GD', sending '-41*48:59#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 1.349080267211595\ +az 0.36289943907578975\ +Command ':GR', sending '00:04:31#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 0.023625168345344713\ +az 0.693030514807611\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 46.52968640692245\ +fraction: 0.27919103353997343\ +degress: 2665.0\ +return: -2665*57:17#\ +RA 23:59:13# (6.27976 radians), dec -46*57:17# (-46.52969 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 46.52968640692245\ +fraction: 0.27919103353997343\ +degress: 2665.0\ +return: -2665*57:17#\ +Command ':GD', sending '-46*57:17#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.411312845389534\ +az 1.465406399218167\ +Command ':GR', sending '00:20:46#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.86866336304813\ +az 3.703120556705994\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 43.519596365024086\ +fraction: 0.3518697255240113\ +degress: 2493.0\ +return: -2493*29:21#\ +RA 00:22:36# (0.09859 radians), dec -43*29:21# (-43.51960 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 43.519596365024086\ +fraction: 0.3518697255240113\ +degress: 2493.0\ +return: -2493*29:21#\ +Command ':GD', sending '-43*29:21#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 0.5246134406822941\ +az 4.589946392470273\ +Command ':GR', sending '00:01:13#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 0.632922797428431\ +az 0.5690116980223668\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 46.653705223707675\ +fraction: 0.6244779535172711\ +degress: 2673.0\ +return: -2673*03:37#\ +RA 00:01:39# (0.00720 radians), dec -46*03:37# (-46.65371 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 46.653705223707675\ +fraction: 0.6244779535172711\ +degress: 2673.0\ +return: -2673*03:37#\ +Command ':GD', sending '-46*03:37#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.872463373800959\ +az 1.1378963243269284\ +Command ':GR', sending '00:22:37#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.431225010026832\ +az 3.234026720709049\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 43.98869020102103\ +fraction: 0.977689619143348\ +degress: 2520.0\ +return: -2520*21:59#\ +RA 00:20:51# (0.09095 radians), dec -43*21:59# (-43.98869 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 43.98869020102103\ +fraction: 0.977689619143348\ +degress: 2520.0\ +return: -2520*21:59#\ +Command ':GD', sending '-43*21:59#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 0.0507979480003294\ +az 4.070945407525698\ +Command ':GR', sending '23:59:19#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 1.2138875169162897\ +az 5.051777988957984\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 42.17093893277206\ +fraction: 0.009137106018897612\ +degress: 2416.0\ +return: -2416*13:01#\ +RA 00:03:59# (0.01734 radians), dec -42*13:01# (-42.17094 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 42.17093893277206\ +fraction: 0.009137106018897612\ +degress: 2416.0\ +return: -2416*13:01#\ +Command ':GD', sending '-42*13:01#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 0.6335329794670528\ +az 1.0007352576457271\ +Command ':GR', sending '00:01:39#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.320850817108474\ +az 1.8070653161638857\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 45.41565160556621\ +fraction: 0.5096501290772721\ +degress: 2602.0\ +return: -2602*07:31#\ +RA 00:20:24# (0.08902 radians), dec -45*07:31# (-45.41565 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 45.41565160556621\ +fraction: 0.5096501290772721\ +degress: 2602.0\ +return: -2602*07:31#\ +Command ':GD', sending '-45*07:31#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.097609980308893\ +az 3.593192710167199\ +Command ':GR', sending '00:19:31#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.242717162419878\ +az 5.342842535028297\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 41.87987438670177\ +fraction: 0.402933762914472\ +degress: 2399.0\ +return: -2399*32:24#\ +RA 00:20:05# (0.08766 radians), dec -41*32:24# (-41.87987 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 41.87987438670177\ +fraction: 0.402933762914472\ +degress: 2399.0\ +return: -2399*32:24#\ +Command ':GD', sending '-41*32:24#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.998203369645527\ +az 3.1741280498558258\ +Command ':GR', sending '00:23:07#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.922385687831215\ +az 2.162771966041259\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 45.05994495568882\ +fraction: 0.6802631663740613\ +degress: 2581.0\ +return: -2581*44:41#\ +RA 00:22:49# (0.09952 radians), dec -45*44:41# (-45.05994 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 45.05994495568882\ +fraction: 0.6802631663740613\ +degress: 2581.0\ +return: -2581*44:41#\ +Command ':GD', sending '-45*44:41#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.827103169583589\ +az 2.094420366913947\ +Command ':GR', sending '00:22:26#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 0.8953332877142155\ +az 4.9158964068388595\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 42.30682051489123\ +fraction: 0.13560724533817847\ +degress: 2424.0\ +return: -2424*00:08#\ +RA 00:02:42# (0.01178 radians), dec -42*00:08# (-42.30682 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 42.30682051489123\ +fraction: 0.13560724533817847\ +degress: 2424.0\ +return: -2424*00:08#\ +Command ':GD', sending '-42*00:08#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 1.2014040868078646\ +az 3.2620290345697676\ +Command ':GR', sending '00:03:56#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.572422400502384\ +az 1.3923796052459496\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 45.83033731648413\ +fraction: 0.09411372782960825\ +degress: 2625.0\ +return: -2625*53:06#\ +RA 00:21:25# (0.09342 radians), dec -45*53:06# (-45.83034 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 45.83033731648413\ +fraction: 0.09411372782960825\ +degress: 2625.0\ +return: -2625*53:06#\ +Command ':GD', sending '-45*53:06#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.5919977281630455\ +az 3.4578364323576696\ +Command ':GR', sending '00:21:29#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 1.1316649959160991\ +az 3.0732845498701074\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 44.14943237185997\ +fraction: 0.5685683496867568\ +degress: 2529.0\ +return: -2529*34:34#\ +RA 00:03:39# (0.01591 radians), dec -44*34:34# (-44.14943 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 44.14943237185997\ +fraction: 0.5685683496867568\ +degress: 2529.0\ +return: -2529*34:34#\ +Command ':GD', sending '-44*34:34#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.1478253307431565\ +az 5.581696514881982\ +Command ':GR', sending '00:19:43#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 6.213920453402858\ +az 1.9772057759726798\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 45.245511145757405\ +fraction: 0.6098338415067701\ +degress: 2592.0\ +return: -2592*22:37#\ +RA 00:23:59# (0.10461 radians), dec -45*22:37# (-45.24551 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 45.245511145757405\ +fraction: 0.6098338415067701\ +degress: 2592.0\ +return: -2592*22:37#\ +Command ':GD', sending '-45*22:37#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 0.6876066949098472\ +az 0.0003243043934229276\ +Command ':GR', sending '00:01:52#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.969825453460809\ +az 4.8951089799748475\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 42.32760794175522\ +fraction: 0.5975168199474865\ +degress: 2425.0\ +return: -2425*11:36#\ +RA 00:22:60# (0.10035 radians), dec -42*11:36# (-42.32761 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 42.32760794175522\ +fraction: 0.5975168199474865\ +degress: 2425.0\ +return: -2425*11:36#\ +Command ':GD', sending '-42*11:36#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.8852556579609665\ +az 4.6740989484576385\ +Command ':GR', sending '00:22:40#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 1.280859312768398\ +az 2.6719341961821206\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 44.55078272554795\ +fraction: 0.30945069391782454\ +degress: 2552.0\ +return: -2552*34:19#\ +RA 00:04:15# (0.01851 radians), dec -44*34:19# (-44.55078 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 44.55078272554795\ +fraction: 0.30945069391782454\ +degress: 2552.0\ +return: -2552*34:19#\ +Command ':GD', sending '-44*34:19#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 0.2637156133139604\ +az 4.949820859968343\ +Command ':GR', sending '00:00:10#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.223662267018147\ +az 2.071367854141759\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 45.151349067588285\ +fraction: 0.9044536852270539\ +degress: 2586.0\ +return: -2586*58:54#\ +RA 00:20:01# (0.08733 radians), dec -45*58:54# (-45.15135 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 45.151349067588285\ +fraction: 0.9044536852270539\ +degress: 2586.0\ +return: -2586*58:54#\ +Command ':GD', sending '-45*58:54#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.629451938681811\ +az 2.748183589107074\ +Command ':GR', sending '00:21:38#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 6.209880696541542\ +az 1.062760252974755\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 46.159956668755285\ +fraction: 0.24197758621448884\ +degress: 2644.0\ +return: -2644*46:15#\ +RA 00:23:58# (0.10454 radians), dec -46*46:15# (-46.15996 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 46.159956668755285\ +fraction: 0.24197758621448884\ +degress: 2644.0\ +return: -2644*46:15#\ +Command ':GD', sending '-46*46:15#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 0.576112588263892\ +az 5.811227357659393\ +Command ':GR', sending '00:01:25#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 0.767416203458844\ +az 0.9310294328401438\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 46.29168748888992\ +fraction: 0.09917911688353342\ +degress: 2652.0\ +return: -2652*19:06#\ +RA 00:02:11# (0.00955 radians), dec -46*19:06# (-46.29169 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 46.29168748888992\ +fraction: 0.09917911688353342\ +degress: 2652.0\ +return: -2652*19:06#\ +Command ':GD', sending '-46*19:06#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 0.7225551910473071\ +az 1.8511093418256268\ +Command ':GR', sending '00:02:01#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 1.3496953185539176\ +az 2.465929221035783\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 44.756787700694304\ +fraction: 0.5023887689258117\ +degress: 2564.0\ +return: -2564*22:30#\ +RA 00:04:31# (0.01971 radians), dec -44*22:30# (-44.75679 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 44.756787700694304\ +fraction: 0.5023887689258117\ +degress: 2564.0\ +return: -2564*22:30#\ +Command ':GD', sending '-44*22:30#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.624592790150345\ +az 4.080139861128027\ +Command ':GR', sending '00:21:37#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 0.4682031898343207\ +az 1.5414124786265773\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 45.6813044431035\ +fraction: 0.7568345227809914\ +degress: 2617.0\ +return: -2617*20:45#\ +RA 00:00:60# (0.00433 radians), dec -45*20:45# (-45.68130 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 45.6813044431035\ +fraction: 0.7568345227809914\ +degress: 2617.0\ +return: -2617*20:45#\ +Command ':GD', sending '-45*20:45#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 6.2101393977731565\ +az 5.854480679006412\ +Command ':GR', sending '00:23:58#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.167082858162292\ +az 3.7572129970748627\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 43.465503924655195\ +fraction: 0.395757523494467\ +degress: 2490.0\ +return: -2490*23:24#\ +RA 00:19:47# (0.08634 radians), dec -43*23:24# (-43.46550 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 43.465503924655195\ +fraction: 0.395757523494467\ +degress: 2490.0\ +return: -2490*23:24#\ +Command ':GD', sending '-43*23:24#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 6.219392466480384\ +az 3.6279045323432406\ +Command ':GR', sending '00:23:60#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.795553924485926\ +az 5.318347746424015\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 41.904369175306044\ +fraction: 0.609814188313976\ +degress: 2400.0\ +return: -2400*56:37#\ +RA 00:22:18# (0.09731 radians), dec -41*56:37# (-41.90437 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 41.904369175306044\ +fraction: 0.609814188313976\ +degress: 2400.0\ +return: -2400*56:37#\ +Command ':GD', sending '-41*56:37#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 1.0568737275045785\ +az 0.2896514721449101\ +Command ':GR', sending '00:03:21#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.312757328211764\ +az 2.680942224243321\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 44.541774697486744\ +fraction: 0.34213131538490416\ +degress: 2552.0\ +return: -2552*03:21#\ +RA 00:20:22# (0.08888 radians), dec -44*03:21# (-44.54177 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 44.541774697486744\ +fraction: 0.34213131538490416\ +degress: 2552.0\ +return: -2552*03:21#\ +Command ':GD', sending '-44*03:21#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 0.3163195075487179\ +az 2.805812179605746\ +Command ':GR', sending '00:00:23#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 0.9720237053552772\ +az 5.797418557330213\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 41.42529836439985\ +fraction: 0.6856810182180197\ +degress: 2373.0\ +return: -2373*29:41#\ +RA 00:03:00# (0.01312 radians), dec -41*29:41# (-41.42530 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 41.42529836439985\ +fraction: 0.6856810182180197\ +degress: 2373.0\ +return: -2373*29:41#\ +Command ':GD', sending '-41*29:41#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 6.074876903279252\ +az 6.241127006815121\ +Command ':GR', sending '00:23:25#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.268614934269164\ +az 1.3477381793176053\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 45.87497874241245\ +fraction: 0.5600315561550815\ +degress: 2628.0\ +return: -2628*26:34#\ +RA 00:20:12# (0.08811 radians), dec -45*26:34# (-45.87498 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 45.87497874241245\ +fraction: 0.5600315561550815\ +degress: 2628.0\ +return: -2628*26:34#\ +Command ':GD', sending '-45*26:34#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.817255695421861\ +az 2.8851913047246565\ +Command ':GR', sending '00:22:23#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 0.4831531368285667\ +az 3.429697894243076\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 43.79301902748699\ +fraction: 0.30974466680709156\ +degress: 2509.0\ +return: -2509*09:19#\ +RA 00:01:03# (0.00459 radians), dec -43*09:19# (-43.79302 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 43.79301902748699\ +fraction: 0.30974466680709156\ +degress: 2509.0\ +return: -2509*09:19#\ +Command ':GD', sending '-43*09:19#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 1.1223151850992228\ +az 4.375332947959413\ +Command ':GR', sending '00:03:37#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 0.5308506535765699\ +az 0.021786591125376828\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 47.200930330604706\ +fraction: 0.8458220812517538\ +degress: 2704.0\ +return: -2704*24:51#\ +RA 00:01:15# (0.00542 radians), dec -47*24:51# (-47.20093 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 47.200930330604706\ +fraction: 0.8458220812517538\ +degress: 2704.0\ +return: -2704*24:51#\ +Command ':GD', sending '-47*24:51#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 5.480430382655608\ +az 0.3313191953215984\ +Command ':GR', sending '00:21:02#'\ +Processing ':GD#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 6.193524899340062\ +az 3.65846867950813\ +\ +FUNCTION meade_lx200_cmd_GD_get_dec\ +\ +FUNCTION radians_to_sddmmss\ +angle: 43.564248242221936\ +fraction: 0.8537163719465752\ +degress: 2496.0\ +return: -2496*02:51#\ +RA 00:23:54# (0.10426 radians), dec -43*02:51# (-43.56425 radians)\ +\ +FUNCTION radians_to_sddmmss\ +angle: 43.564248242221936\ +fraction: 0.8537163719465752\ +degress: 2496.0\ +return: -2496*02:51#\ +Command ':GD', sending '-43*02:51#'\ +Processing ':GR#'\ +\ +FUNCTION update_alt_az\ +\ +FUNCTION alt_az_to_equatorial\ +alt 1.423081651570082\ +az 5.8403320402102015\ +Command ':GR', sending '00:04:49#'\ +Processing ':Q#'\ +Command ':Q', no response} \ No newline at end of file diff --git a/results/log_slew_test_25Jan2328.txt b/results/log_slew_test_25Jan2328.txt new file mode 100644 index 0000000..7e0a424 --- /dev/null +++ b/results/log_slew_test_25Jan2328.txt @@ -0,0 +1,476 @@ +Processing ':St+51*40#' +Command ':St', argument '+51*40' +meade_lx200_cmd_St_set_latitude: +51*40 +Command ':St', sending '1' +Processing ':Sg351*40#' +Command ':Sg', argument '351*40' +meade_lx200_cmd_Sg_set_longitude: 351*40 +Local site now latitude +51d40, longitude 351d40 +Command ':Sg', sending '1' +Processing ':SG-01.0#' +Command ':SG', argument '-01.0' +Local site timezone now -1.0 +Command ':SG', sending '1' +Processing ':SG-01.0#' +Command ':SG', argument '-01.0' +Local site timezone now -1.0 +Command ':SG', sending '1' +Processing ':SL23:38:18#' +Command ':SL', argument '23:38:18' +Requested site time 23:38:18 (TZ -1.0), new offset -1s, total offset -1s +Effective site date/time is 2022-01-26 00:38:18.275661 (local time), 2022-01-25 23:38:18.275887 (GMT/UTC) +Command ':SL', sending '1' +Processing ':SC01/25/22#' +Command ':SC', argument '01/25/22' +Requested site date 01/25/22 (MM/DD/YY) gives offset of 0 days +Effective site date/time is 2022-01-26 00:38:18.428540 (local time), 2022-01-25 23:38:18.428761 (GMT/UTC) +Command ':SC', sending '1Updating Planetary Data# #' +Processing ':GR#' + +FUNCTION update_alt_az +local_az 0.6768823333675326 +local_alt 5.459970321996165 + +FUNCTION alt_az_to_equatorial +alt 5.459970321996165 +az 0.6768823333675326 +Actual Values +ra 0.2664599355565045 +dec -95.09979412809093 +Command ':GR', sending '01:01:04#' +Processing ':RS#' +Command ':RS', no response +Processing ':GD#' + +FUNCTION update_alt_az +local_az 3.712762577352128 +local_alt 1.35003929037928 + +FUNCTION alt_az_to_equatorial +alt 1.35003929037928 +az 3.712762577352128 +Actual Values +ra 0.2664599355565045 +dec -92.06391388410634 + +FUNCTION meade_lx200_cmd_GD_get_dec + +FUNCTION radians_to_sddmmss +angle: 92.06391388410634 +fraction: 0.2912370050518547 +degress: 29.0 +arcminutes: 18.0 +return: -29*18:17# +RA 01:01:04# (0.26646 radians), dec -29*18:17# (-92.06391 radians) + +FUNCTION radians_to_sddmmss +angle: 92.06391388410634 +fraction: 0.2912370050518547 +degress: 29.0 +arcminutes: 18.0 +return: -29*18:17# +Command ':GD', sending '-29*18:17#' +Processing ':GR#' + +FUNCTION update_alt_az +local_az 0.031572477830419554 +local_alt 0.7402277536840056 + +FUNCTION alt_az_to_equatorial +alt 0.7402277536840056 +az 0.031572477830419554 +Actual Values +ra 0.2664599355565045 +dec -95.74510398362804 +Command ':GR', sending '01:01:04#' +Processing ':RS#' +Command ':RS', no response +Processing ':GD#' + +FUNCTION update_alt_az +local_az 3.171688225340013 +local_alt 5.061476734195773 + +FUNCTION alt_az_to_equatorial +alt 5.061476734195773 +az 3.171688225340013 +Actual Values +ra 0.2664599355565045 +dec -92.60498823611846 + +FUNCTION meade_lx200_cmd_GD_get_dec + +FUNCTION radians_to_sddmmss +angle: 92.60498823611846 +fraction: 0.6249959294084277 +degress: 29.0 +arcminutes: 28.0 +return: -29*28:37# +RA 01:01:04# (0.26646 radians), dec -29*28:37# (-92.60499 radians) + +FUNCTION radians_to_sddmmss +angle: 92.60498823611846 +fraction: 0.6249959294084277 +degress: 29.0 +arcminutes: 28.0 +return: -29*28:37# +Command ':GD', sending '-29*28:37#' +Processing ':GR#' + +FUNCTION update_alt_az +local_az 3.0103557105795105 +local_alt 0.04407296271579985 + +FUNCTION alt_az_to_equatorial +alt 0.04407296271579985 +az 3.0103557105795105 +Actual Values +ra 0.2664599355565045 +dec -92.76632075087895 +Command ':GR', sending '01:01:04#' +Processing ':GD#' + +FUNCTION update_alt_az +local_az 2.242409388097259 +local_alt 1.3982340279514778 + +FUNCTION alt_az_to_equatorial +alt 1.3982340279514778 +az 2.242409388097259 +Actual Values +ra 0.2664599355565045 +dec -93.5342670733612 + +FUNCTION meade_lx200_cmd_GD_get_dec + +FUNCTION radians_to_sddmmss +angle: 93.5342670733612 +fraction: 0.3729143843531233 +degress: 29.0 +arcminutes: 46.0 +return: -29*46:22# +RA 01:01:04# (0.26646 radians), dec -29*46:22# (-93.53427 radians) + +FUNCTION radians_to_sddmmss +angle: 93.5342670733612 +fraction: 0.3729143843531233 +degress: 29.0 +arcminutes: 46.0 +return: -29*46:22# +Command ':GD', sending '-29*46:22#' +Processing ':GR#' + +FUNCTION update_alt_az +local_az 0.1832795760342468 +local_alt 0.5114757564414291 + +FUNCTION alt_az_to_equatorial +alt 0.5114757564414291 +az 0.1832795760342468 +Actual Values +ra 0.2664599355565045 +dec -95.59339688542423 +Command ':GR', sending '01:01:04#' +Processing ':GD#' + +FUNCTION update_alt_az +local_az 6.075427958560113 +local_alt 5.175074233795774 + +FUNCTION alt_az_to_equatorial +alt 5.175074233795774 +az 6.075427958560113 +Actual Values +ra 0.2664599355565045 +dec -89.70124850289835 + +FUNCTION meade_lx200_cmd_GD_get_dec + +FUNCTION radians_to_sddmmss +angle: 89.70124850289835 +fraction: 0.16765209008991633 +degress: 28.0 +arcminutes: 33.0 +return: -28*33:10# +RA 01:01:04# (0.26646 radians), dec -28*33:10# (-89.70125 radians) + +FUNCTION radians_to_sddmmss +angle: 89.70124850289835 +fraction: 0.16765209008991633 +degress: 28.0 +arcminutes: 33.0 +return: -28*33:10# +Command ':GD', sending '-28*33:10#' +Processing ':GR#' + +FUNCTION update_alt_az +local_az 3.397604161664236 +local_alt 5.404771098403139 + +FUNCTION alt_az_to_equatorial +alt 5.404771098403139 +az 3.397604161664236 +Actual Values +ra 0.2664599355565045 +dec -92.37907229979425 +Command ':GR', sending '01:01:04#' +Processing ':GD#' + +FUNCTION update_alt_az +local_az 2.860820148878184 +local_alt 0.4836037276029206 + +FUNCTION alt_az_to_equatorial +alt 0.4836037276029206 +az 2.860820148878184 +Actual Values +ra 0.2664599355565045 +dec -92.91585631258027 + +FUNCTION meade_lx200_cmd_GD_get_dec + +FUNCTION radians_to_sddmmss +angle: 92.91585631258027 +fraction: 0.562138851612545 +degress: 29.0 +arcminutes: 34.0 +return: -29*34:34# +RA 01:01:04# (0.26646 radians), dec -29*34:34# (-92.91586 radians) + +FUNCTION radians_to_sddmmss +angle: 92.91585631258027 +fraction: 0.562138851612545 +degress: 29.0 +arcminutes: 34.0 +return: -29*34:34# +Command ':GD', sending '-29*34:34#' +Processing ':GR#' + +FUNCTION update_alt_az +local_az 0.9958191715539206 +local_alt 1.1739160089283902 + +FUNCTION alt_az_to_equatorial +alt 1.1739160089283902 +az 0.9958191715539206 +Actual Values +ra 0.2664599355565045 +dec -94.78085728990453 +Command ':GR', sending '01:01:04#' +Processing ':GD#' + +FUNCTION update_alt_az +local_az 6.1920136362880935 +local_alt 6.216508468219399 + +FUNCTION alt_az_to_equatorial +alt 6.216508468219399 +az 6.1920136362880935 +Actual Values +ra 0.2664599355565045 +dec -89.58466282517037 + +FUNCTION meade_lx200_cmd_GD_get_dec + +FUNCTION radians_to_sddmmss +angle: 89.58466282517037 +fraction: 0.9410296615946834 +degress: 28.0 +arcminutes: 30.0 +return: -28*30:56# +RA 01:01:04# (0.26646 radians), dec -28*30:56# (-89.58466 radians) + +FUNCTION radians_to_sddmmss +angle: 89.58466282517037 +fraction: 0.9410296615946834 +degress: 28.0 +arcminutes: 30.0 +return: -28*30:56# +Command ':GD', sending '-28*30:56#' +Processing ':GR#' + +FUNCTION update_alt_az +local_az 5.347919069989869 +local_alt 5.220369615777074 + +FUNCTION alt_az_to_equatorial +alt 5.220369615777074 +az 5.347919069989869 +Actual Values +ra 0.2664599355565045 +dec -90.4287573914686 +Command ':GR', sending '01:01:04#' +Processing ':GD#' + +FUNCTION update_alt_az +local_az 3.1949392296502213 +local_alt 5.96371209065219 + +FUNCTION alt_az_to_equatorial +alt 5.96371209065219 +az 3.1949392296502213 +Actual Values +ra 0.2664599355565045 +dec -92.58173723180823 + +FUNCTION meade_lx200_cmd_GD_get_dec + +FUNCTION radians_to_sddmmss +angle: 92.58173723180823 +fraction: 0.1809344572696574 +degress: 29.0 +arcminutes: 28.0 +return: -29*28:11# +RA 01:01:04# (0.26646 radians), dec -29*28:11# (-92.58174 radians) + +FUNCTION radians_to_sddmmss +angle: 92.58173723180823 +fraction: 0.1809344572696574 +degress: 29.0 +arcminutes: 28.0 +return: -29*28:11# +Command ':GD', sending '-29*28:11#' +Processing ':GR#' + +FUNCTION update_alt_az +local_az 3.056606444413971 +local_alt 0.7533805937250719 + +FUNCTION alt_az_to_equatorial +alt 0.7533805937250719 +az 3.056606444413971 +Actual Values +ra 0.2664599355565045 +dec -92.72007001704452 +Command ':GR', sending '01:01:04#' +Processing ':GD#' + +FUNCTION update_alt_az +local_az 0.2609537143182802 +local_alt 0.8085618195193353 + +FUNCTION alt_az_to_equatorial +alt 0.8085618195193353 +az 0.2609537143182802 +Actual Values +ra 0.2664599355565045 +dec -95.51572274714016 + +FUNCTION meade_lx200_cmd_GD_get_dec + +FUNCTION radians_to_sddmmss +angle: 95.51572274714016 +fraction: 0.21593018428140454 +degress: 30.0 +arcminutes: 24.0 +return: -30*24:13# +RA 01:01:04# (0.26646 radians), dec -30*24:13# (-95.51572 radians) + +FUNCTION radians_to_sddmmss +angle: 95.51572274714016 +fraction: 0.21593018428140454 +degress: 30.0 +arcminutes: 24.0 +return: -30*24:13# +Command ':GD', sending '-30*24:13#' +Processing ':GR#' + +FUNCTION update_alt_az +local_az 0.12469143663294126 +local_alt 5.67161132995596 + +FUNCTION alt_az_to_equatorial +alt 5.67161132995596 +az 0.12469143663294126 +Actual Values +ra 0.2664599355565045 +dec -95.65198502482554 +Command ':GR', sending '01:01:04#' +Processing ':GD#' + +FUNCTION update_alt_az +local_az 2.912769543393607 +local_alt 5.09300130151974 + +FUNCTION alt_az_to_equatorial +alt 5.09300130151974 +az 2.912769543393607 +Actual Values +ra 0.2664599355565045 +dec -92.86390691806486 + +FUNCTION meade_lx200_cmd_GD_get_dec + +FUNCTION radians_to_sddmmss +angle: 92.86390691806486 +fraction: 0.5699785002812945 +degress: 29.0 +arcminutes: 33.0 +return: -29*33:34# +RA 01:01:04# (0.26646 radians), dec -29*33:34# (-92.86391 radians) + +FUNCTION radians_to_sddmmss +angle: 92.86390691806486 +fraction: 0.5699785002812945 +degress: 29.0 +arcminutes: 33.0 +return: -29*33:34# +Command ':GD', sending '-29*33:34#' +Processing ':GR#' + +FUNCTION update_alt_az +local_az 3.140118836813804 +local_alt 6.154082558381589 + +FUNCTION alt_az_to_equatorial +alt 6.154082558381589 +az 3.140118836813804 +Actual Values +ra 0.2664599355565045 +dec -92.63655762464464 +Command ':GR', sending '01:01:04#' +Processing ':GD#' + +FUNCTION update_alt_az +local_az 3.302477870329738 +local_alt 1.0960525148343025 + +FUNCTION alt_az_to_equatorial +alt 1.0960525148343025 +az 3.302477870329738 +Actual Values +ra 0.2664599355565045 +dec -92.47419859112875 + +FUNCTION meade_lx200_cmd_GD_get_dec + +FUNCTION radians_to_sddmmss +angle: 92.47419859112875 +fraction: 0.12709770876712412 +degress: 29.0 +arcminutes: 26.0 +return: -29*26:08# +RA 01:01:04# (0.26646 radians), dec -29*26:08# (-92.47420 radians) + +FUNCTION radians_to_sddmmss +angle: 92.47419859112875 +fraction: 0.12709770876712412 +degress: 29.0 +arcminutes: 26.0 +return: -29*26:08# +Command ':GD', sending '-29*26:08#' +Processing ':GR#' + +FUNCTION update_alt_az +local_az 6.281114571103999 +local_alt 0.7869913587999734 + +FUNCTION alt_az_to_equatorial +alt 0.7869913587999734 +az 6.281114571103999 +Actual Values +ra 0.2664599355565045 +dec -89.49556189035445 +Command ':GR', sending '01:01:04#' +Processing ':Q#' +Command ':Q', no response \ No newline at end of file diff --git a/results/log_slew_test_27Jan0103.txt b/results/log_slew_test_27Jan0103.txt new file mode 100644 index 0000000..01bccd4 --- /dev/null +++ b/results/log_slew_test_27Jan0103.txt @@ -0,0 +1,102 @@ +Checking Configuration +Connecting to sensors... +Connected to MPU9250 sensor +Opening network port... +FUNCTION parse_hhmm +FUNCTION parse_hhmm +FUNCTION parse_hhmm +FUNCTION parse_hhmm +FUNCTION parse_hhmm +FUNCTION parse_sddmm +FUNCTION parse_sddmm +FUNCTION parse_sddmm +FUNCTION parse_sddmm +FUNCTION parse_hhmm +FUNCTION parse_sddmm +FUNCTION radians_to_hms +FUNCTION radians_to_hms +FUNCTION obs_time +Location + +Starting up on 192.168.86.42 port 4030 +Processing ':St+51*40#' +Command ':St', argument '+51*40' +FUNCTION meade_lx200_cmd_St_set_latitude - passed value: +51*40 +Command ':St', sending '1' +Processing ':Sg351*40#' +Command ':Sg', argument '351*40' +FUNCTION meade_lx200_cmd_Sg_set_longitude - passed value: 351*40 +Local site now latitude +51d40, longitude 351d40 +Command ':Sg', sending '1' +Processing ':SG-01.0#' +Command ':SG', argument '-01.0' +FUNCTION meade_lx200_cmd_SG_set_local_timezone - passed values: site_tz = -01.0 +Local site timezone now -1.0 +Command ':SG', sending '1' +Processing ':SG-01.0#' +Command ':SG', argument '-01.0' +FUNCTION meade_lx200_cmd_SG_set_local_timezone - passed values: site_tz = -01.0 +Local site timezone now -1.0 +Command ':SG', sending '1' +Processing ':SL01:02:29#' +Command ':SL', argument '01:02:29' +FUNCTION meade_lx200_cmd_SL_set_local_time - passed values: 01:02:29 +Requested site time 1:02:29 (TZ -1.0), new offset 0s, total offset 0s +FUNCTION debug_time - site_tz -1.0 +FUNCTION site_time_local_as_datetime - site_tz -1.0 +FUNCTION site_time_gmt_as_datetime +FUNCTION site_time_gmt_as_epoch +FUNCTION site_time_gmt_as_datetime +FUNCTION site_time_gmt_as_epoch +Effective site date/time is 2022-01-27 02:02:29.343210 (local time), 2022-01-27 01:02:29.343619 (GMT/UTC) +Command ':SL', sending '1' +Processing ':SC01/27/22#' +Command ':SC', argument '01/27/22' +FUNCTION meade_lx200_cmd_SC_set_local_date - passed values: 01/27/22 +Requested site date 01/27/22 (MM/DD/YY) gives offset of 0 days +FUNCTION debug_time - site_tz -1.0 +FUNCTION site_time_local_as_datetime - site_tz -1.0 +FUNCTION site_time_gmt_as_datetime +FUNCTION site_time_gmt_as_epoch +FUNCTION site_time_gmt_as_datetime +FUNCTION site_time_gmt_as_epoch +Effective site date/time is 2022-01-27 02:02:29.400176 (local time), 2022-01-27 01:02:29.400627 (GMT/UTC) +Command ':SC', sending '1Updating Planetary Data# #' +Processing ':GR#' +FUNCTION meade_lx200_cmd_GR_get_ra +FUNCTION update_alt_az - local_alt 5.822129413903568 - local_aaz 2.0243499945347363 +FUNCTION alt_az_to_equatorial - passed values: alt 5.822129413903568 - az 2.0243499945347363 +FUNCTION greenwich_sidereal_time_in_radians - value +FUNCTION alt_az_to_equatorial - deterime ra from latitude: 0.9018937841346785 +FUNCTION alt_az_to_equatorial - az wrap at 90d: 0.03533157261736036 +FUNCTION alt_az_to_equatorial - actual values: ra 0.9018937841346785 - dec 0.03533157261736036 +FUNCTION radians_to_hhmmss +FUNCTION radians_to_hms +Command ':GR', sending '03:26:42#' +Processing ':RS#:GD#' +Command ':RS', no response +FUNCTION meade_lx200_cmd_GD_get_dec +FUNCTION update_alt_az - local_alt 5.254304692558707 - local_aaz 0.41393608180040975 +FUNCTION alt_az_to_equatorial - passed values: alt 5.254304692558707 - az 0.41393608180040975 +FUNCTION greenwich_sidereal_time_in_radians - value +FUNCTION alt_az_to_equatorial - deterime ra from latitude: 0.9018937841346785 +FUNCTION alt_az_to_equatorial - az wrap at 90d: 0.007224547520221727 +FUNCTION alt_az_to_equatorial - actual values: ra 0.9018937841346785 - dec 0.007224547520221727 + +FUNCTION meade_lx200_cmd_GD_get_dec +FUNCTION radians_to_hhmmss +FUNCTION radians_to_hms +FUNCTION radians_to_sddmmss - passed values: 0.007224547520221727 +FUNCTION radians_to_sddmmss - actual values: angle = 0.007224547520221727, fraction = 0.1379786939334699, degrees = 0.0, arcminutes = 0.0 + +FUNCTION radians_to_sddmmss - return values: +00*00:08# + +RA 03:26:42# (0.90189 radians), dec +00*00:08# (0.00722 radians) +FUNCTION radians_to_sddmmss - passed values: 0.007224547520221727 +FUNCTION radians_to_sddmmss - actual values: angle = 0.007224547520221727, fraction = 0.1379786939334699, degrees = 0.0, arcminutes = 0.0 + +FUNCTION radians_to_sddmmss - return values: +00*00:08# + +Command ':GD', sending '+00*00:08#' +Processing ':Q#' +Command ':Q', no response \ No newline at end of file diff --git a/results/log_slew_test_27Jan2336.txt b/results/log_slew_test_27Jan2336.txt new file mode 100644 index 0000000..f952685 --- /dev/null +++ b/results/log_slew_test_27Jan2336.txt @@ -0,0 +1,236 @@ +Checking Configuration +Connecting to sensors... +Connected to MPU9250 sensor +Opening network port... +FUNCTION parse_hhmm +FUNCTION parse_hhmm +FUNCTION parse_hhmm +FUNCTION parse_hhmm +FUNCTION parse_hhmm +FUNCTION parse_sddmm +FUNCTION parse_sddmm +FUNCTION parse_sddmm +FUNCTION parse_sddmm +FUNCTION parse_hhmm +FUNCTION parse_sddmm +FUNCTION radians_to_hms +FUNCTION radians_to_hms +FUNCTION obs_time +Location + +Starting up on 192.168.86.42 port 4030 +Processing ':St+51*40#' +Command ':St', argument '+51*40' +FUNCTION meade_lx200_cmd_St_set_latitude - passed value: +51*40 +Command ':St', sending '1' +Processing ':Sg351*40#' +Command ':Sg', argument '351*40' +FUNCTION meade_lx200_cmd_Sg_set_longitude - passed value: 351*40 +Local site now latitude +51d40, longitude 351d40 +Command ':Sg', sending '1' +Processing ':SG-01.0#' +Command ':SG', argument '-01.0' +FUNCTION meade_lx200_cmd_SG_set_local_timezone - passed values: site_tz = -01.0 +Local site timezone now -1.0 +Command ':SG', sending '1' +Processing ':SG-01.0#' +Command ':SG', argument '-01.0' +FUNCTION meade_lx200_cmd_SG_set_local_timezone - passed values: site_tz = -01.0 +Local site timezone now -1.0 +Command ':SG', sending '1' +Processing ':SL23:32:56#' +Command ':SL', argument '23:32:56' +FUNCTION meade_lx200_cmd_SL_set_local_time - passed values: 23:32:56 +Requested site time 23:32:56 (TZ -1.0), new offset -1s, total offset -1s +FUNCTION debug_time - site_tz -1.0 +FUNCTION site_time_local_as_datetime - site_tz -1.0 +FUNCTION site_time_gmt_as_datetime +FUNCTION site_time_gmt_as_epoch +FUNCTION site_time_gmt_as_datetime +FUNCTION site_time_gmt_as_epoch +Effective site date/time is 2022-01-28 00:32:56.019326 (local time), 2022-01-27 23:32:56.020744 (GMT/UTC) +Command ':SL', sending '1' +Processing ':SC01/27/22#' +Command ':SC', argument '01/27/22' +FUNCTION meade_lx200_cmd_SC_set_local_date - passed values: 01/27/22 +Requested site date 01/27/22 (MM/DD/YY) gives offset of 0 days +FUNCTION debug_time - site_tz -1.0 +FUNCTION site_time_local_as_datetime - site_tz -1.0 +FUNCTION site_time_gmt_as_datetime +FUNCTION site_time_gmt_as_epoch +FUNCTION site_time_gmt_as_datetime +FUNCTION site_time_gmt_as_epoch +Effective site date/time is 2022-01-28 00:32:56.072903 (local time), 2022-01-27 23:32:56.074310 (GMT/UTC) +Command ':SC', sending '1Updating Planetary Data# #' +Processing ':GR#' +FUNCTION meade_lx200_cmd_GR_get_ra +FUNCTION update_alt_az - local_alt 1.313276800826052 - local_aaz 2.176034165243983 +FUNCTION alt_az_to_equatorial - passed values: alt 1.313276800826052 - az 2.176034165243983 +FUNCTION greenwich_sidereal_time_in_radians - value +FUNCTION alt_az_to_equatorial - deterime ra from latitude: 0.9018937841346785 +FUNCTION alt_az_to_equatorial - DEC from latitude: 0.732559926031784 +FUNCTION alt_az_to_equatorial - gst: 2.102621500125476 +FUNCTION alt_az_to_equatorial - hours_in_rad: 5.997607960487637 +FUNCTION alt_az_to_equatorial - site_longitude: 351d40 +FUNCTION alt_az_to_equatorial - lon: 6.137741202846726 +FUNCTION alt_az_to_equatorial - Forumula: ra = gst - lon.radian - hours_in_rad +FUNCTION alt_az_to_equatorial - RA from longitude: 0.732559926031784 +FUNCTION alt_az_to_equatorial - actual values: ra 2.5336429511502843 - dec 0.732559926031784 +FUNCTION radians_to_hhmmss +FUNCTION radians_to_hms +Command ':GR', sending '09:40:40#' +Processing ':RS#:GD#' +Command ':RS', no response +FUNCTION meade_lx200_cmd_GD_get_dec +FUNCTION update_alt_az - local_alt 5.106510827845283 - local_aaz 5.614902444254167 +FUNCTION alt_az_to_equatorial - passed values: alt 5.106510827845283 - az 5.614902444254167 +FUNCTION greenwich_sidereal_time_in_radians - value +FUNCTION alt_az_to_equatorial - deterime ra from latitude: 0.9018937841346785 +FUNCTION alt_az_to_equatorial - DEC from latitude: -0.567417066838458 +FUNCTION alt_az_to_equatorial - gst: 2.104491221117832 +FUNCTION alt_az_to_equatorial - hours_in_rad: 2.8555519854513913 +FUNCTION alt_az_to_equatorial - site_longitude: 351d40 +FUNCTION alt_az_to_equatorial - lon: 6.137741202846726 +FUNCTION alt_az_to_equatorial - Forumula: ra = gst - lon.radian - hours_in_rad +FUNCTION alt_az_to_equatorial - RA from longitude: -0.567417066838458 +FUNCTION alt_az_to_equatorial - actual values: ra 5.677568647178887 - dec -0.567417066838458 + +FUNCTION meade_lx200_cmd_GD_get_dec +FUNCTION radians_to_hhmmss +FUNCTION radians_to_hms +FUNCTION radians_to_sddmmss - passed values: -0.567417066838458 +FUNCTION radians_to_sddmmss - actual values: angle = 0.567417066838458, fraction = 0.8368677178453954, degrees = 0.0, arcminutes = 10.0 + +FUNCTION radians_to_sddmmss - return values: -00*10:50# + +RA 21:41:12# (5.67757 radians), dec -00*10:50# (-0.56742 radians) +FUNCTION radians_to_sddmmss - passed values: -0.567417066838458 +FUNCTION radians_to_sddmmss - actual values: angle = 0.567417066838458, fraction = 0.8368677178453954, degrees = 0.0, arcminutes = 10.0 + +FUNCTION radians_to_sddmmss - return values: -00*10:50# + +Command ':GD', sending '-00*10:50#' +Processing ':Q#' +Command ':Q', no response +Processing ':RS#' +Command ':RS', no response +Processing ':St+51*40#' +Command ':St', argument '+51*40' +FUNCTION meade_lx200_cmd_St_set_latitude - passed value: +51*40 +Command ':St', sending '1' +Processing ':GR#' +FUNCTION meade_lx200_cmd_GR_get_ra +FUNCTION update_alt_az - local_alt 5.4154637956892575 - local_aaz 0.1721633412113443 +FUNCTION alt_az_to_equatorial - passed values: alt 5.4154637956892575 - az 0.1721633412113443 +FUNCTION greenwich_sidereal_time_in_radians - value +FUNCTION alt_az_to_equatorial - deterime ra from latitude: 0.9018937841346785 +FUNCTION alt_az_to_equatorial - DEC from latitude: -0.20486930124571734 +FUNCTION alt_az_to_equatorial - gst: 2.104507473422555 +FUNCTION alt_az_to_equatorial - hours_in_rad: 3.2549671825939575 +FUNCTION alt_az_to_equatorial - site_longitude: 351d40 +FUNCTION alt_az_to_equatorial - lon: 6.137741202846726 +FUNCTION alt_az_to_equatorial - Forumula: ra = gst - lon.radian - hours_in_rad +FUNCTION alt_az_to_equatorial - RA from longitude: -0.20486930124571734 +FUNCTION alt_az_to_equatorial - actual values: ra 5.278169702341043 - dec -0.20486930124571734 +FUNCTION radians_to_hhmmss +FUNCTION radians_to_hms +Command ':GR', sending '20:09:40#' +Processing ':RS#:GD#' +Command ':RS', no response +FUNCTION meade_lx200_cmd_GD_get_dec +FUNCTION update_alt_az - local_alt 5.771216213980958 - local_aaz 0.3541670929035306 +FUNCTION alt_az_to_equatorial - passed values: alt 5.771216213980958 - az 0.3541670929035306 +FUNCTION greenwich_sidereal_time_in_radians - value +FUNCTION alt_az_to_equatorial - deterime ra from latitude: 0.9018937841346785 +FUNCTION alt_az_to_equatorial - DEC from latitude: 0.1230475126348478 +FUNCTION alt_az_to_equatorial - gst: 2.1045201889778338 +FUNCTION alt_az_to_equatorial - hours_in_rad: 3.451158644712569 +FUNCTION alt_az_to_equatorial - site_longitude: 351d40 +FUNCTION alt_az_to_equatorial - lon: 6.137741202846726 +FUNCTION alt_az_to_equatorial - Forumula: ra = gst - lon.radian - hours_in_rad +FUNCTION alt_az_to_equatorial - RA from longitude: 0.1230475126348478 +FUNCTION alt_az_to_equatorial - actual values: ra 5.0819909557777105 - dec 0.1230475126348478 + +FUNCTION meade_lx200_cmd_GD_get_dec +FUNCTION radians_to_hhmmss +FUNCTION radians_to_hms +FUNCTION radians_to_sddmmss - passed values: 0.1230475126348478 +FUNCTION radians_to_sddmmss - actual values: angle = 0.1230475126348478, fraction = 0.35003438451981683, degrees = 0.0, arcminutes = 2.0 + +FUNCTION radians_to_sddmmss - return values: +00*02:21# + +RA 19:24:42# (5.08199 radians), dec +00*02:21# (0.12305 radians) +FUNCTION radians_to_sddmmss - passed values: 0.1230475126348478 +FUNCTION radians_to_sddmmss - actual values: angle = 0.1230475126348478, fraction = 0.35003438451981683, degrees = 0.0, arcminutes = 2.0 + +FUNCTION radians_to_sddmmss - return values: +00*02:21# + +Command ':GD', sending '+00*02:21#' +Processing ':GR#' +FUNCTION meade_lx200_cmd_GR_get_ra +FUNCTION update_alt_az - local_alt 6.134166612370002 - local_aaz 0.5104310107233799 +FUNCTION alt_az_to_equatorial - passed values: alt 6.134166612370002 - az 0.5104310107233799 +FUNCTION greenwich_sidereal_time_in_radians - value +FUNCTION alt_az_to_equatorial - deterime ra from latitude: 0.9018937841346785 +FUNCTION alt_az_to_equatorial - DEC from latitude: 0.4319147468538843 +FUNCTION alt_az_to_equatorial - gst: 2.1045332077393195 +FUNCTION alt_az_to_equatorial - hours_in_rad: 3.702546434271568 +FUNCTION alt_az_to_equatorial - site_longitude: 351d40 +FUNCTION alt_az_to_equatorial - lon: 6.137741202846726 +FUNCTION alt_az_to_equatorial - Forumula: ra = gst - lon.radian - hours_in_rad +FUNCTION alt_az_to_equatorial - RA from longitude: 0.4319147468538843 +FUNCTION alt_az_to_equatorial - actual values: ra 4.830616184980197 - dec 0.4319147468538843 +FUNCTION radians_to_hhmmss +FUNCTION radians_to_hms +Command ':GR', sending '18:27:06#' +Processing ':RS#' +Command ':RS', no response +Processing ':GD#' +FUNCTION meade_lx200_cmd_GD_get_dec +FUNCTION update_alt_az - local_alt 1.1297169252286379 - local_aaz 3.2386534488011933 +FUNCTION alt_az_to_equatorial - passed values: alt 1.1297169252286379 - az 3.2386534488011933 +FUNCTION greenwich_sidereal_time_in_radians - value +FUNCTION alt_az_to_equatorial - deterime ra from latitude: 0.9018937841346785 +FUNCTION alt_az_to_equatorial - DEC from latitude: 0.4622060344949627 +FUNCTION alt_az_to_equatorial - gst: 2.104800598714319 +FUNCTION alt_az_to_equatorial - hours_in_rad: 0.04623823685945453 +FUNCTION alt_az_to_equatorial - site_longitude: 351d40 +FUNCTION alt_az_to_equatorial - lon: 6.137741202846726 +FUNCTION alt_az_to_equatorial - Forumula: ra = gst - lon.radian - hours_in_rad +FUNCTION alt_az_to_equatorial - RA from longitude: 0.4622060344949627 +FUNCTION alt_az_to_equatorial - actual values: ra 2.2040064661877246 - dec 0.4622060344949627 + +FUNCTION meade_lx200_cmd_GD_get_dec +FUNCTION radians_to_hhmmss +FUNCTION radians_to_hms +FUNCTION radians_to_sddmmss - passed values: 0.4622060344949627 +FUNCTION radians_to_sddmmss - actual values: angle = 0.4622060344949627, fraction = 0.8274850140131687, degrees = 0.0, arcminutes = 8.0 + +FUNCTION radians_to_sddmmss - return values: +00*08:50# + +RA 08:25:07# (2.20401 radians), dec +00*08:50# (0.46221 radians) +FUNCTION radians_to_sddmmss - passed values: 0.4622060344949627 +FUNCTION radians_to_sddmmss - actual values: angle = 0.4622060344949627, fraction = 0.8274850140131687, degrees = 0.0, arcminutes = 8.0 + +FUNCTION radians_to_sddmmss - return values: +00*08:50# + +Command ':GD', sending '+00*07:58#' +Processing ':GR#' +FUNCTION meade_lx200_cmd_GR_get_ra +FUNCTION update_alt_az - local_alt 0.8022747940176379 - local_aaz 1.4048704672402863 +FUNCTION alt_az_to_equatorial - passed values: alt 0.8022747940176379 - az 1.4048704672402863 +FUNCTION greenwich_sidereal_time_in_radians - value +FUNCTION alt_az_to_equatorial - deterime ra from latitude: 0.9018937841346785 +FUNCTION alt_az_to_equatorial - DEC from latitude: 0.6882692240444466 +FUNCTION alt_az_to_equatorial - gst: 2.1067065101894116 +FUNCTION alt_az_to_equatorial - hours_in_rad: 5.191099413285302 +FUNCTION alt_az_to_equatorial - site_longitude: 351d40 +FUNCTION alt_az_to_equatorial - lon: 6.137741202846726 +FUNCTION alt_az_to_equatorial - Forumula: ra = gst - lon.radian - hours_in_rad +FUNCTION alt_az_to_equatorial - RA from longitude: 0.6882692240444466 +FUNCTION alt_az_to_equatorial - actual values: ra 3.3442365084165555 - dec 0.6882692240444466 +FUNCTION radians_to_hhmmss +FUNCTION radians_to_hms +Command ':GR', sending '12:46:27#' +Processing ':Q#' +Command ':Q', no response \ No newline at end of file diff --git a/results/log_slew_test_30Jan2134.txt b/results/log_slew_test_30Jan2134.txt new file mode 100644 index 0000000..3909ba3 --- /dev/null +++ b/results/log_slew_test_30Jan2134.txt @@ -0,0 +1,75 @@ +FUNCTION meade_lx200_cmd_GD_get_dec +RA 17:27:46# (4.57175 radians), dec -00*00:34# (-0.03000 radians) +':GR#' --> ':GR' as command +FUNCTION alt_az_to_equatorial - passed values: alt 5.488861906010419 - az 0.007464491527548339 +FUNCTION alt_az_to_equatorial - deterime ra from latitude: 0.9017534468637369 +FUNCTION alt_az_to_equatorial - DEC from latitude: -0.12529272564088567 +FUNCTION alt_az_to_equatorial - gst: 1.625194455281565 +FUNCTION alt_az_to_equatorial - hours_in_rad: 3.1468648310141463 +FUNCTION alt_az_to_equatorial - site_longitude: 351d40 +FUNCTION alt_az_to_equatorial - lon: 6.137741202846726 +FUNCTION alt_az_to_equatorial - Forumula: ra = gst - lon.radian - hours_in_rad +FUNCTION alt_az_to_equatorial - RA from longitude: -0.12529272564088567 +FUNCTION alt_az_to_equatorial - actual values: ra 4.906959035779865 - dec -0.12529272564088567 +':RS#' --> ':RS' as command +':GD#' --> ':GD' as command +FUNCTION alt_az_to_equatorial - passed values: alt 5.604684794734311 - az 5.201755924259443 +FUNCTION alt_az_to_equatorial - deterime ra from latitude: 0.9017534468637369 +FUNCTION alt_az_to_equatorial - DEC from latitude: -0.2685587555830068 +FUNCTION alt_az_to_equatorial - gst: 1.6254529274917295 +FUNCTION alt_az_to_equatorial - hours_in_rad: 2.3482704110130546 +FUNCTION alt_az_to_equatorial - site_longitude: 351d40 +FUNCTION alt_az_to_equatorial - lon: 6.137741202846726 +FUNCTION alt_az_to_equatorial - Forumula: ra = gst - lon.radian - hours_in_rad +FUNCTION alt_az_to_equatorial - RA from longitude: -0.2685587555830068 +FUNCTION alt_az_to_equatorial - actual values: ra 5.705811927991121 - dec -0.2685587555830068 + +FUNCTION meade_lx200_cmd_GD_get_dec +RA 21:47:41# (5.70581 radians), dec -00*05:08# (-0.26856 radians) +':GR#' --> ':GR' as command +FUNCTION alt_az_to_equatorial - passed values: alt 5.792763970705213 - az 4.861410321883307 +FUNCTION alt_az_to_equatorial - deterime ra from latitude: 0.9017534468637369 +FUNCTION alt_az_to_equatorial - DEC from latitude: -0.2923727888350321 +FUNCTION alt_az_to_equatorial - gst: 1.625465855393648 +FUNCTION alt_az_to_equatorial - hours_in_rad: 1.9958445055521141 +FUNCTION alt_az_to_equatorial - site_longitude: 351d40 +FUNCTION alt_az_to_equatorial - lon: 6.137741202846726 +FUNCTION alt_az_to_equatorial - Forumula: ra = gst - lon.radian - hours_in_rad +FUNCTION alt_az_to_equatorial - RA from longitude: -0.2923727888350321 +FUNCTION alt_az_to_equatorial - actual values: ra 6.05825076135398 - dec -0.2923727888350321 +':GD#' --> ':GD' as command +FUNCTION alt_az_to_equatorial - passed values: alt 6.053566438444271 - az 4.59030024025292 +FUNCTION alt_az_to_equatorial - deterime ra from latitude: 0.9017534468637369 +FUNCTION alt_az_to_equatorial - DEC from latitude: -0.25484069778244123 +FUNCTION alt_az_to_equatorial - gst: 1.6254811714637758 +FUNCTION alt_az_to_equatorial - hours_in_rad: 1.6205700958079672 +FUNCTION alt_az_to_equatorial - site_longitude: 351d40 +FUNCTION alt_az_to_equatorial - lon: 6.137741202846726 +FUNCTION alt_az_to_equatorial - Forumula: ra = gst - lon.radian - hours_in_rad +FUNCTION alt_az_to_equatorial - RA from longitude: -0.25484069778244123 +FUNCTION alt_az_to_equatorial - actual values: ra 0.15035517998866865 - dec -0.25484069778244123 + +FUNCTION meade_lx200_cmd_GD_get_dec +RA 00:34:28# (0.15036 radians), dec -00*04:52# (-0.25484 radians) +':GR#' --> ':GR' as command +FUNCTION alt_az_to_equatorial - passed values: alt 6.249970046720756 - az 4.387708795650179 +FUNCTION alt_az_to_equatorial - deterime ra from latitude: 0.9017534468637369 +FUNCTION alt_az_to_equatorial - DEC from latitude: -0.22571091432518617 +FUNCTION alt_az_to_equatorial - gst: 1.6254920799598602 +FUNCTION alt_az_to_equatorial - hours_in_rad: 1.3330939939989874 +FUNCTION alt_az_to_equatorial - site_longitude: 351d40 +FUNCTION alt_az_to_equatorial - lon: 6.137741202846726 +FUNCTION alt_az_to_equatorial - Forumula: ra = gst - lon.radian - hours_in_rad +FUNCTION alt_az_to_equatorial - RA from longitude: -0.22571091432518617 +FUNCTION alt_az_to_equatorial - actual values: ra 0.4378421902937326 - dec -0.22571091432518617 +':GD#' --> ':GD' as command +FUNCTION alt_az_to_equatorial - passed values: alt 0.13026583095959435 - az 4.226486223691618 +FUNCTION alt_az_to_equatorial - deterime ra from latitude: 0.9017534468637369 +FUNCTION alt_az_to_equatorial - DEC from latitude: -0.18638351681985768 +FUNCTION alt_az_to_equatorial - gst: 1.6255029204933702 +FUNCTION alt_az_to_equatorial - hours_in_rad: 1.102224563232978 +FUNCTION alt_az_to_equatorial - site_longitude: 351d40 +FUNCTION alt_az_to_equatorial - lon: 6.137741202846726 +FUNCTION alt_az_to_equatorial - Forumula: ra = gst - lon.radian - hours_in_rad +FUNCTION alt_az_to_equatorial - RA from longitude: -0.18638351681985768 +FUNCTION alt_az_to_equatorial - actual values: ra 0.6687224615932523 - dec -0.18638351681985768 \ No newline at end of file diff --git a/results/readme.md b/results/readme.md new file mode 100644 index 0000000..75ecbca --- /dev/null +++ b/results/readme.md @@ -0,0 +1,37 @@ +# Items to Check once it runs +- Did the refactoring to astropy provide the right values? + +# Pending Items to Solve + +``` +Processing ':CM#' +':CM#' --> ':CM' as command +FUNCTION meade_lx200_cmd_CM_sync +FUNCTION radians_to_sddmmss - passed values: 6.102735949907029 +FUNCTION radians_to_sddmmss - actual values: angle = 6.102735949907029, fraction = 0.5536711374780481, degrees = 1.0, arcminutes = 56.0 + +FUNCTION radians_to_sddmmss - return values: +01*56:33# + +FUNCTION radians_to_hhmmss +FUNCTION radians_to_hms +Resetting from current position Alt +01*56:33# (6.10274 radians), Az 19:20:10# (5.06215 radians) +FUNCTION radians_to_hhmmss +FUNCTION radians_to_hms +FUNCTION radians_to_sddmmss - passed values: -0.2921487242366064 +FUNCTION radians_to_sddmmss - actual values: angle = 0.2921487242366064, fraction = 0.5796296296296308, degrees = 0.0, arcminutes = 5.0 + +FUNCTION radians_to_sddmmss - return values: -00*05:35# + +New target position RA 06:46:07# (1.77202 radians), Dec -00*05:35# (-0.29215 radians) +FUNCTION equatorial_to_alt_az - passed values: ra 1.7720182451394093 - dec -0.2921487242366064 +FUNCTION equatorial_to_alt_az - returned values: alt '177' - az '17' +Traceback (most recent call last): + File "/home/pi/longsight/telescope_server.py", line 732, in + resp = command_map[cmd]() + File "/home/pi/longsight/telescope_server.py", line 257, in meade_lx200_cmd_CM_sync + offset_alt += (target_alt - local_alt) +TypeError: unsupported operand type(s) for -: 'str' and 'float' +``` + +- Connecting to Sky Safari Plus 7.0 works, after connecting if you choose "align" the program crashes *lines 191 - equatorial_to_alt_az* + diff --git a/README.rst b/src/README.rst similarity index 100% rename from README.rst rename to src/README.rst diff --git a/capture.py b/src/capture.py similarity index 100% rename from capture.py rename to src/capture.py diff --git a/src/gy80.py b/src/gy80.py new file mode 100755 index 0000000..8467973 --- /dev/null +++ b/src/gy80.py @@ -0,0 +1,247 @@ +#!/usr/bin/env python +"""Code for talking to an GY-80 sensor chip via I2C, intended for use on Raspberry Pi. + +The GY-80 is a tiny orientation sensor chip with nine degrees of freedom (9-DOF, +from 3-DOF each for the accelerometer, compass and gyroscope) plus a barometer +which means it gets marketed as a ten dgree of freedom (10-DOF) sensor. Chips: + +- HMC5883L (3-Axis Digital Compass / vector magnetometer), I2C Address 0x1E +- ADXL345 (3-Axis Digital Accelerometer), I2C Address 0x53 +- L3G4200D (3-Axis Angular Rate Sensor / Gyro), I2C Address 0x69 +- BMP085 (Barometric Pressure / Temperature Sensor), I2C Address 0x77 + +For my notes on how to connect this to a Raspberry Pi, including the wiring and the +system configuration hanges and some useful I2C software, see: +http://astrobeano.blogspot.com/2014/01/gy-80-orientation-sensor-on-raspberry-pi.html + +Gyroscopes can track rotation of the sensor, but need an external point of reference +to give an absolute orientation or heading. This is provided by the accelerometer +(when at rest this tells us which way is down due to gravity), and the compass or +(more accurately vector magnetometer) tells us the direction of (magnetic) North. + +Using the accelerometer and magnetometer/compass alone would give an orientation, +but will give errors from vibration which can be compensated for by the gyroscope. +The gyroscope alone is prone to drift, so the combination is much more robust. + +In aeronautics and also submarines the standard axes convention is North, East, Down +(NED), while for ground based systems instead East, North, Up (ENU) is used. Most of +the online example code I've found is for remote control planes and gyrocopters and +therefore used NED. This does the same (even though I have a ground based project). + +Rotation angles in both aeronautics and nautical terminology can be defined relative +to the local frame of reference: pitch is about the X axis (direction of travel), +pitch is about the Y axis (lateral to right of travel) and yaw is about the Z axis +(down). +""" +from __future__ import print_function + +import sys +from time import sleep, time +from math import pi, sin, cos, asin, acos, atan2, sqrt +import numpy as np +import smbus + +try: + from adxl345 import ADXL345 + from hmc5883l import HMC5883L + from bmp085 import BMP085 + from l3g4200d import L3G4200D + from i2cutils import i2c_raspberry_pi_bus_number +except ImportError: + sys.stderr.write("Ensure adxl345.py, hmc5883l.py bmp085.py, l3g4200d.py and i2cutils.py are present and importable\n") + sys.stderr.write("\nSee the following links, tweak the i2cutils import inside hmc58831.py etc:\n") + sys.stderr.write("https://github.com/bitify/raspi/blob/master/i2c-sensors/bitify/python/sensors/hmc5883l.py\n") + sys.stderr.write("https://github.com/bitify/raspi/blob/master/i2c-sensors/bitify/python/utils/i2cutils.py\n") + sys.exit(1) + +#Local imports +from quaternions import _check_close +from quaternions import quaternion_to_rotation_matrix_rows, quaternion_from_rotation_matrix_rows +from quaternions import quaternion_from_axis_angle +from quaternions import quaternion_from_euler_angles, quaternion_to_euler_angles +from quaternions import quaternion_multiply, quaternion_normalise + + +class GY80(object): + def __init__(self, bus=None): + if bus is None: + bus = smbus.SMBus(i2c_raspberry_pi_bus_number()) + + #Default ADXL345 range +/- 2g is ideal for telescope use + self.accel = ADXL345(bus, 0x53, name="accel") + self.gyro = L3G4200D(bus, 0x69, name="gyro") + self.compass = HMC5883L(bus, 0x1e, name="compass") + self.barometer = BMP085(bus, 0x77, name="barometer") + + self._last_gyro_time = 0 #needed for interpreting gyro + self.read_gyro_delta() #Discard first reading + q_start = self.current_orientation_quaternion_mag_acc_only() + self._q_start = q_start + self._current_hybrid_orientation_q = q_start + self._current_gyro_only_q = q_start + + def update(self): + """Read the current sensor values & store them for smoothing. No return value.""" + t = time() + delta_t = t - self._last_gyro_time + if delta_t < 0.020: + #Want at least 20ms of data + return + v_gyro = np.array(self.read_gyro(), np.float) + v_acc = np.array(self.read_accel(), np.float) + v_mag = np.array(self.read_compass(), np.float) + self._last_gyro_time = t + + #Gyro only quaternion calculation (expected to drift) + rot_mag = sqrt(sum(v_gyro**2)) + v_rotation = v_gyro / rot_mag + q_rotation = quaternion_from_axis_angle(v_rotation, rot_mag * delta_t) + self._current_gyro_only_q = quaternion_multiply(self._current_gyro_only_q, q_rotation) + self._current_hybrid_orientation_q = quaternion_multiply(self._current_hybrid_orientation_q, q_rotation) + + if abs(sqrt(sum(v_acc**2)) - 1) < 0.3: + #Approx 1g, should be stationary, and can use this for down axis... + v_down = v_acc * -1.0 + v_east = np.cross(v_down, v_mag) + v_north = np.cross(v_east, v_down) + v_down /= sqrt((v_down**2).sum()) + v_east /= sqrt((v_east**2).sum()) + v_north /= sqrt((v_north**2).sum()) + #Complementary Filter + #Combine (noisy) orientation from acc/mag, 2% + #with (drifting) orientation from gyro, 98% + q_mag_acc = quaternion_from_rotation_matrix_rows(v_north, v_east, v_down) + self._current_hybrid_orientation_q = tuple(0.02*a + 0.98*b for a, b in + zip(q_mag_acc, self._current_hybrid_orientation_q)) + + + #1st order approximation of quaternion for this rotation (v_rotation, delta_t) + #using small angle approximation, cos(theta) = 1, sin(theta) = theta + #w, x, y, z = (1, v_rotation[0] * delta_t/2, v_rotation[1] *delta_t/2, v_rotation[2] * delta_t/2) + #q_rotation = (1, v_rotation[0] * delta_t/2, v_rotation[1] *delta_t/2, v_rotation[2] * delta_t/2) + return + + def current_orientation_quaternion_hybrid(self): + """Current orientation using North, East, Down (NED) frame of reference.""" + self.update() + return self._current_hybrid_orientation_q + + def current_orientation_quaternion_mag_acc_only(self): + """Current orientation using North, East, Down (NED) frame of reference.""" + #Can't use v_mag directly as North since it will usually not be + #quite horizontal (requiring tilt compensation), establish this + #using the up/down axis from the accelerometer. + #Note assumes starting at rest so only acceleration is gravity. + v_acc = np.array(self.read_accel(), np.float) + v_mag = np.array(self.read_compass(), np.float) + return self._quaternion_from_acc_mag(v_acc, v_mag) + + def _quaternion_from_acc_mag(self, v_acc, v_mag): + v_down = v_acc * -1.0 #(sign change depends on sensor design?) + v_east = np.cross(v_down, v_mag) + v_north = np.cross(v_east, v_down) + #Normalise the vectors... + v_down /= sqrt((v_down ** 2).sum()) + v_east /= sqrt((v_east ** 2).sum()) + v_north /= sqrt((v_north ** 2).sum()) + return quaternion_from_rotation_matrix_rows(v_north, v_east, v_down) + + def current_orientation_euler_angles_hybrid(self): + """Current orientation using yaw, pitch, roll (radians) using sensor's frame.""" + return quaternion_to_euler_angles(*self.current_orientation_quaternion_hybrid()) + + def current_orientation_euler_angles_mag_acc_only(self): + """Current orientation using yaw, pitch, roll (radians) using sensor's frame.""" + return quaternion_to_euler_angles(*self.current_orientation_quaternion_mag_acc_only()) + + def read_accel(self, scaled=True): + """Returns an X, Y, Z tuple; if scaled in units of gravity.""" + accel = self.accel + accel.read_raw_data() + if scaled: + return accel.accel_scaled_x, accel.accel_scaled_y, accel.accel_scaled_z + else: + return accel.accel_raw_x, accel.accel_raw_y, accel.accel_raw_z + + def read_gyro(self, scaled=True): + """Returns an X, Y, Z tuple; If scaled uses radians/second. + + WARNING: Calling this method directly will interfere with the higher-level + methods like ``read_gyro_delta`` which integrate the gyroscope readings to + track orientation (it will miss out on the rotation reported in this call). + """ + gyro = self.gyro + gyro.read_raw_data() + if scaled: + return gyro.gyro_scaled_x, gyro.gyro_scaled_y, gyro.gyro_scaled_z + else: + return gyro.gyro_raw_x, gyro.gyro_raw_y, gyro.gyro_raw_z + + def read_gyro_delta(self): + """Returns an X, Y, Z tuple - radians since last call.""" + g = self.gyro + t = time() + g.read_raw_data() + d = np.array([g.gyro_scaled_x, g.gyro_scaled_y, g.gyro_scaled_z], np.float) / (t - self._last_gyro_time) + self._last_gyro_time = t + return d + + def read_compass(self, scaled=True): + """Returns an X, Y, Z tuple.""" + compass = self.compass + compass.read_raw_data() + if scaled: + return compass.scaled_x, compass.scaled_y, compass.scaled_z + else: + return compass.raw_x, compass.raw_y, compass.raw_z + + +if __name__ == "__main__": + print("Starting...") + imu = GY80() + + #Sanity test: + x, y, z = imu.read_accel() + g = sqrt(x*x + y*y + z*z) + print("Magnitude of acceleration %0.2fg (%0.2f %0.2f %0.2f)" % (g, x, y, z)) + if abs(g - 1) > 0.3: + sys.stderr.write("Not starting from rest, acceleration %0.2f\n" % g) + sys.exit(1) + print("Starting q by acc/mag (%0.2f, %0.2f, %0.2f, %0.2f)" % imu._q_start) + + try: + while True: + print() + imu.update() + #w, x, y, z = imu.current_orientation_quaternion_hybrid() + w, x, y, z = imu._current_hybrid_orientation_q + #print("Gyroscope/Accl/Comp q (%0.2f, %0.2f, %0.2f, %0.2f)" % (w, x, y, z)) + yaw, pitch, roll = quaternion_to_euler_angles(w, x, y, z) + print("Gyroscope/Accl/Comp q (%0.2f, %0.2f, %0.2f, %0.2f), " + "yaw %0.1f, pitch %0.2f, roll %0.1f (degrees)" % (w, x, y, z, + yaw * 180.0 / pi, + pitch * 180.0 / pi, + roll * 180.0 / pi)) + + w, x, y, z = imu._current_gyro_only_q + #print("Gyro-only quaternion (%0.2f, %0.2f, %0.2f, %0.2f)" % (w, x, y, z)) + yaw, pitch, roll = quaternion_to_euler_angles(w, x, y, z) + print("Gyro-only quaternion (%0.2f, %0.2f, %0.2f, %0.2f), " + "yaw %0.1f, pitch %0.2f, roll %0.1f (degrees)" % (w, x, y, z, + yaw * 180.0 / pi, + pitch * 180.0 / pi, + roll * 180.0 / pi)) + + w, x, y, z = imu.current_orientation_quaternion_mag_acc_only() + #print("Accel/Comp quaternion (%0.2f, %0.2f, %0.2f, %0.2f)" % (w, x, y, z)) + yaw, pitch, roll = quaternion_to_euler_angles(w, x, y, z) + print("Accel/Comp quaternion (%0.2f, %0.2f, %0.2f, %0.2f), " + "yaw %0.1f, pitch %0.2f, roll %0.1f (degrees)" % (w, x, y, z, + yaw * 180.0 / pi, + pitch * 180.0 / pi, + roll * 180.0 / pi)) + sleep(0.25) + except KeyboardInterrupt: + print() + pass + print("Done") diff --git a/src/quaternions.py b/src/quaternions.py new file mode 100644 index 0000000..04b63a7 --- /dev/null +++ b/src/quaternions.py @@ -0,0 +1,154 @@ +"""Crude code for quaternions in Python. + +TODO - Define a quaternion class? +""" + +from __future__ import print_function + +from math import pi, sin, cos, asin, acos, atan2, sqrt + +def _check_close(a, b, error=0.0001): + if isinstance(a, (tuple, list)): + assert isinstance(b, (tuple, list)) + assert len(a) == len(b) + for a1, b1 in zip(a, b): + diff = abs(a1-b1) + if diff > error: + raise ValueError("%s vs %s, for %s vs %s difference %s > %s" + % (a, b, a1, b1, diff, error)) + return + diff = abs(a-b) + if diff > error: + raise ValueError("%s vs %s, difference %s > %s" + % (a, b, diff, error)) + +def quaternion_mgnitude(w, x, y, z): + return sqrt(w*w + x*x + y*y + z*z) + +def quaternion_normalise(w, x, y, z): + mag = sqrt(w*w + x*x + y*y + z*z) + return w/mag, x/mag, y/mag, z/mag + +def quaternion_from_axis_angle(vector, theta): + sin_half_theta = sin(theta/2) + return cos(theta/2), vector[0]*sin_half_theta, vector[1]*sin_half_theta, vector[2]*sin_half_theta + +#TODO - Write quaternion_to_axis_angle and cross-validate + +def quaternion_to_rotation_matrix_rows(w, x, y, z): + """Returns a tuple of three rows which make up a 3x3 rotatation matrix. + + It is trival to turn this into a NumPy array/matrix if desired.""" + x2 = x*x + y2 = y*2 + z2 = z*2 + row0 = (1 - 2*y2 - 2*z2, + 2*x*y - 2*w*z, + 2*x*z + 2*w*y) + row1 = (2*x*y + 2*w*z, + 1 - 2*x2 - 2*z2, + 2*y*z - 2*w*x) + row2 = (2*x*z - 2*w*y, + 2*y*z + 2*w*x, + 1 - 2*x2 - 2*y2) + return row0, row1, row2 + +def quaternion_from_rotation_matrix_rows(row0, row1, row2): + #No point merging three rows into a 3x3 matrix if just want quaternion + #Based on several sources including the C++ implementation here: + #http://www.camelsoftware.com/firetail/blog/uncategorized/quaternion-based-ahrs-using-altimu-10-arduino/ + #http://www.camelsoftware.com/firetail/blog/c/imu-maths/ + trace = row0[0] + row1[1] + row2[2] + if trace > row2[2]: + S = sqrt(1.0 + trace) * 2 + w = 0.25 * S + x = (row2[1] - row1[2]) / S + y = (row0[2] - row2[0]) / S + z = (row1[0] - row0[1]) / S + elif row0[0] < row1[1] and row0[0] < row2[2]: + S = sqrt(1.0 + row0[0] - row1[1] - row2[2]) * 2 + w = (row2[1] - row1[2]) / S + x = 0.25 * S + y = (row0[1] + row1[0]) / S + z = (row0[2] + row2[0]) / S + elif row1[1] < row2[2]: + S = sqrt(1.0 + row1[1] - row0[0] - row2[2]) * 2 + w = (row0[2] - row2[0]) / S + x = (row0[1] + row1[0]) / S + y = 0.25 * S + z = (row1[2] + row2[1]) / S + else: + S = sqrt(1.0 + row2[2] - row0[0] - row1[1]) * 2 + w = (row1[0] - row0[1]) / S + x = (row0[2] + row2[0]) / S + y = (row1[2] + row2[1]) / S + z = 0.25 * S + return w, x, y, z + + +#TODO - Double check which angles exactly have I calculated (which frame etc)? +def quaternion_from_euler_angles(yaw, pitch, roll): + """Returns (w, x, y, z) quaternion from angles in radians. + + Assuming angles given in the moving frame of reference of the sensor, + not a fixed Earth bound observer. + """ + #Roll = phi, pitch = theta, yaw = psi + return (cos(roll/2)*cos(pitch/2)*cos(yaw/2) + sin(roll/2)*sin(pitch/2)*sin(yaw/2), + sin(roll/2)*cos(pitch/2)*cos(yaw/2) - cos(roll/2)*sin(pitch/2)*sin(yaw/2), + cos(roll/2)*sin(pitch/2)*cos(yaw/2) + sin(roll/2)*cos(pitch/2)*sin(yaw/2), + cos(roll/2)*cos(pitch/2)*sin(yaw/2) - sin(roll/2)*sin(pitch/2)*cos(yaw/2)) + +def quaternion_to_euler_angles(w, x, y, z): + """Returns angles about Z, Y, X axes in radians (yaw, pitch, roll). + + Using moving frame of reference of the sensor, not the fixed frame of + an Earth bound observer.. + """ + w2 = w*w + x2 = x*x + y2 = y*y + z2 = z*z + return (atan2(2.0 * (x*y + z*w), (w2 + x2 - y2 - z2)), # -pi to pi + asin(2.0 * (w*y - x*z) / (w2 + x2 + y2 + z2)), # -pi/2 to +pi/2 + atan2(2.0 * (y*z + x*w), (w2 - x2 - y2 + z2))) # -pi to pi + +_check_close(quaternion_to_euler_angles(0, 1, 0, 0), (0, 0, pi)) +_check_close(quaternion_to_euler_angles(0,-1, 0, 0), (0, 0, pi)) +_check_close(quaternion_from_euler_angles(0, 0, pi), (0, 1, 0, 0)) + +_check_close(quaternion_to_euler_angles(0, 0, 1, 0), (pi, 0, pi)) +_check_close(quaternion_to_euler_angles(0, 0,-1, 0), (pi, 0, pi)) +_check_close(quaternion_from_euler_angles(pi, 0, pi), (0, 0, 1, 0)) + +_check_close(quaternion_to_euler_angles(0, 0, 0, 1), (pi, 0, 0)) +_check_close(quaternion_to_euler_angles(0, 0, 0,-1), (pi, 0, 0)) +_check_close(quaternion_from_euler_angles(pi, 0, 0), (0, 0, 0, 1)) + +_check_close(quaternion_to_euler_angles(0, 0, 0.5*sqrt(2), 0.5*sqrt(2)), (pi, 0, pi/2)) +_check_close(quaternion_from_euler_angles(pi, 0, pi/2), (0, 0, 0.5*sqrt(2), 0.5*sqrt(2))) + +_check_close(quaternion_to_euler_angles(0, 0.5*sqrt(2), 0, 0.5*sqrt(2)), (0, -pi/2, 0)) +_check_close(quaternion_to_euler_angles(0.5*sqrt(2), 0,-0.5*sqrt(2), 0), (0, -pi/2, 0)) +_check_close(quaternion_from_euler_angles(0, -pi/2, 0), (0.5*sqrt(2), 0, -0.5*sqrt(2), 0)) + +_check_close(quaternion_to_euler_angles(0, 1, 1, 0), (pi/2, 0, pi)) #Not normalised +_check_close(quaternion_to_euler_angles(0, 0.5*sqrt(2), 0.5*sqrt(2), 0), (pi/2, 0, pi)) +_check_close(quaternion_from_euler_angles(pi/2, 0, pi), (0, 0.5*sqrt(2), 0.5*sqrt(2), 0)) + +#w, x, y, z = quaternion_from_euler_angles(pi, 0, pi) +#print("quarternion (%0.2f, %0.2f, %0.2f, %0.2f) magnitude %0.2f" % (w, x, y, z, sqrt(w*w + x*x + y*y + z*z))) + +def quaternion_multiply(a, b): + a_w, a_x, a_y, a_z = a + b_w, b_x, b_y, b_z = b + return (a_w*b_w - a_x*b_x - a_y*b_y - a_z*b_z, + a_w*b_x + a_x*b_w + a_y*b_z - a_z*b_y, + a_w*b_y - a_x*b_z + a_y*b_w + a_z*b_x, + a_w*b_z + a_x*b_y - a_y*b_x + a_z*b_w) + +_check_close(quaternion_multiply((0, 0, 0, 1), (0, 0, 1, 0)), (0, -1, 0, 0)) + +def quaternion_scalar_multiply(q, s): + w, x, y, z = q + return (w*s, x*s, y*s, z*q) diff --git a/src/telescope_server.py b/src/telescope_server.py new file mode 100755 index 0000000..1fd54cd --- /dev/null +++ b/src/telescope_server.py @@ -0,0 +1,798 @@ +#!/usr/bin/env python +"""TCP/IP server which listens for Meade LX200 style serial commands. + +Intended to mimick a SkyFi (serial to TCP/IP bridge) and compatible +Meade telescope normally controlled via a serial cable. In theory +this could be modified to listen to an actual serial port too... + +The intended goal is that celestial/planetarium software like the +SkySafari applications can talk to this server as if it was an off +the shelf Meade LX200 compatible "Go To" telescope, when in fact +it is a DIY intrumented telescope or simulation. + +See http://astrobeano.blogspot.co.uk/2014/01/instrumented-telescope-with-raspberry.html + +Testing with Sky Safari Plus v4.0, with the telescope usually setup as: + +Scope Type: Meade LX-200 GPS +Mount Type: Equatorial Push-To (or any push to setting) +Auto-Detect SkyFi: Off +IP Address: That of the computer running this script (default 10.0.0.1) +Port Number: 4030 (default) +Set Time & Location: On (default is off) +Readout Rate: 4 per second (default) +Save Log File: Off (default) + +With this, the "Connect/Disconnect" button works fine, once connected +the scope queries the position using the :GR# and :GD# commands. + +The "Goto" button is disabled (when configured as a Push-To telecope). + +The "Align" button gives an are you sure prompt with the currently +selected objects name (e.g. a star), and then sends its position +using the Sr and Sd commands, followed by the :CM# command. + +The "Lock/Unlock" button controls if SkySafari automatically pans +the display to keep the reported telescope direction centered. + +If configured as a Goto telescope, additional left/right and up/down +buttons appear on screen (which send East/West, North/South movement +commands. Also, a slew rate slider control appears. Depending on which +model telescope was selected, this may give four rates via the +RC/RG/RM/RS commands, or Sw commands (in the range 2 to 8). + +If SkySafari's "Set Time & Location" feature is selected, it will +send commands St and Sg (for the location) then SG, SL, SC to set +the time and date. If using "Meade LX-200 Classic" this imposes +a 15s delay, using a newer model like the "Meade LX-200 GPS" there +is no noticeable delay on connection. + +Additional limited testing also done with the Celestron NexStar +protocol, although SkySafari 4 does not seem to use its built in +commands for setting the date/time or location, nor the synching +commands for alignment. +""" + +#More references on Alt/Az horizontal coordinates to equatorial: +#http://pythonhosted.org/Astropysics/coremods/obstools.html#astropysics.obstools.Site +#https://github.com/eteq/astropysics/issues/21 +#https://github.com/astropy/astropy-api/pull/6 +#http://infohost.nmt.edu/tcc/help/lang/python/examples/sidereal/ims/ + +import socket +import os +import sys +import commands +try: + import configparser +except ImportError: + import ConfigParser as configparser +import time +import datetime +from math import pi, sin, cos, asin, acos, atan2, modf + +#TODO - Try astropy if I can get it to compile on Mac OS X... +from astropysics import coords +from astropysics import obstools + +#Local import +from gy80 import GY80 + +config_file = "telescope_server.ini" +if not os.path.isfile(config_file): + print("Using default settings") + h = open("telescope_server.ini", "w") + h.write("[server]\nname=10.0.0.1\nport=4030\n") + #Default to Greenwich as the site + h.write("[site]\nlatitude=+51d28m38s\nlongitude=0\n") + #Default to no correction of the angles + h.write("[offsets]\nazimuth=0\naltitude=0\n") + h.close() + +print("Connecting to sensors...") +imu = GY80() +print("Connected to GY-80 sensor") + +print("Opening network port...") +config = configparser.ConfigParser() +config.read("telescope_server.ini") +server_name = config.get("server", "name") #e.g. 10.0.0.1 +server_port = config.getint("server", "port") #e.g. 4030 +#server_name = socket.gethostbyname(socket.gethostname()) +#if server_name.startswith("127.0."): #e.g. 127.0.0.1 +# #This works on Linux but not on Mac OS X or Windows: +# server_name = commands.getoutput("/sbin/ifconfig").split("\n")[1].split()[1][5:] +##server_name = "10.0.0.1" #Override for wifi access +#server_port = 4030 #Default port used by SkySafari + +#If default to low precision, SkySafari turns it on anyway: +high_precision = True + +#Default to Greenwich, GMT - Latitude 51deg 28' 38'' N, Longitude zero +local_site = obstools.Site(coords.AngularCoordinate(config.get("site", "latitude")), + coords.AngularCoordinate(config.get("site", "longitude")), + tz=0) +#Rather than messing with the system clock, will store any difference +#between the local computer's date/time and any date/time set by the +#client (which should match any location set by the client). +local_time_offset = 0 + +#This will probably best be inferred by calibration... +#For Greenwich, magnetic north is estimated to be 2 deg 40 min west +#of grid north at Greenwich in July 2013. +#http://www.geomag.bgs.ac.uk/data_service/models_compass/gma_calc.html +#local_site_magnetic_offset = -2.67 * pi / 180.0 + +#These will come from sensor information... storing them in radians +local_alt = 85 * pi / 180.0 +local_az = 30 * pi / 180.0 +offset_alt = config.getfloat("offsets", "altitude") +offset_az = config.getfloat("offsets", "azimuth") + +#These will come from the client... store them in radians +target_ra = 0.0 +target_dec = 0.0 + +#Turn on for lots of logging... +debug = False + +def save_config(): + global condig, config_file + with open(config_file, "w") as handle: + config.write(handle) + +def _check_close(a, b, error=0.0001): + if isinstance(a, (tuple, list)): + assert isinstance(b, (tuple, list)) + assert len(a) == len(b) + for a1, b1 in zip(a, b): + diff = abs(a1-b1) + if diff > error: + raise ValueError("%s vs %s, for %s vs %s difference %s > %s" + % (a, b, a1, b1, diff, error)) + return + diff = abs(a-b) + if diff > error: + raise ValueError("%s vs %s, difference %s > %s" + % (a, b, diff, error)) + +def update_alt_az(): + global imu, offset_alt, offset_az, local_alt, local_az + yaw, pitch, roll = imu.current_orientation_euler_angles_hybrid() + #yaw, pitch, roll = imu.current_orientation_euler_angles_mag_acc_only() + #Yaw is measured from (magnetic) North, + #Azimuth is measure from true North: + local_az = (offset_az + yaw) % (2*pi) + #Pitch is measured downwards (using airplane style NED system) + #Altitude is measured upwards + local_alt = (offset_alt + pitch) % (2*pi) + #We don't care about the roll for the Meade LX200 protocol. + +def site_time_gmt_as_epoch(): + global local_time_offset + return time.time() + local_time_offset + +def site_time_gmt_as_datetime(): + return datetime.datetime.fromtimestamp(site_time_gmt_as_epoch()) + +def site_time_local_as_datetime(): + global local_site + return site_time_gmt_as_datetime() - datetime.timedelta(hours=local_site.tz) + +def debug_time(): + global local_site + if local_site.tz: + sys.stderr.write("Effective site date/time is %s (local time), %s (GMT/UTC)\n" + % (site_time_local_as_datetime(), site_time_gmt_as_datetime())) + else: + sys.stderr.write("Effective site date/time is %s (local/GMT/UTC)\n" + % site_time_gmt_as_datetime()) + +def greenwich_sidereal_time_in_radians(): + """Calculate using GMT (according to client's time settings).""" + #Function astropysics.obstools.epoch_to_jd wants a decimal year as input + #Function astropysics.obstools.calendar_to_jd can take a datetime object + gmt_jd = obstools.calendar_to_jd(site_time_gmt_as_datetime()) + #Convert from hours to radians... 24hr = 2*pi + return coords.greenwich_sidereal_time(gmt_jd) * pi / 12 + +def alt_az_to_equatorial(alt, az, gst=None): + global local_site #and time offset used too + if gst is None: + gst = greenwich_sidereal_time_in_radians() + lat = local_site.latitude.r + #Calculate these once only for speed + sin_lat = sin(lat) + cos_lat = cos(lat) + sin_alt = sin(alt) + cos_alt = cos(alt) + sin_az = sin(az) + cos_az = cos(az) + dec = asin(sin_alt*sin_lat + cos_alt*cos_lat*cos_az) + hours_in_rad = acos((sin_alt - sin_lat*sin(dec)) / (cos_lat*cos(dec))) + if sin_az > 0.0: + hours_in_rad = 2*pi - hours_in_rad + ra = gst - local_site.longitude.r - hours_in_rad + return ra % (pi*2), dec + +def equatorial_to_alt_az(ra, dec, gst=None): + global local_site #and time offset used too + if gst is None: + gst = greenwich_sidereal_time_in_radians() + lat = local_site.latitude.r + #Calculate these once only for speed + sin_lat = sin(lat) + cos_lat = cos(lat) + sin_dec = sin(dec) + cos_dec = cos(dec) + h = gst - local_site.longitude.r - ra + sin_h = sin(h) + cos_h = cos(h) + alt = asin(sin_lat*sin_dec + cos_lat*cos_dec*cos_h) + az = atan2(-cos_dec*sin_h, cos_lat*sin_dec - sin_lat*cos_dec*cos_h) + return alt, az % (2*pi) +#This test implicitly assumes time between two calculations not significant: +_check_close((1.84096, 0.3984), alt_az_to_equatorial(*equatorial_to_alt_az(1.84096, 0.3984))) +#_check_close(parse_hhmm("07:01:55"), 1.84096) # RA +#_check_close(parse_sddmm("+22*49:43"), 0.3984) # Dec + +#This ensures identical time stamp used: +gst = greenwich_sidereal_time_in_radians() +for ra in [0.1, 1, 2, 3, pi, 4, 5, 6, 1.99*pi]: + for dec in [-0.49*pi, -1.1, -1, 0, 0.001, 1.55, 0.49*pi]: + alt, az = equatorial_to_alt_az(ra, dec, gst) + _check_close((ra, dec), alt_az_to_equatorial(alt, az, gst)) +del gst, ra, dec + +# ==================== +# Meade LX200 Protocol +# ==================== + +def meade_lx200_cmd_CM_sync(): + """For the :CM# command, Synchronizes the telescope's position with the currently selected database object's coordinates. + + Returns: + LX200's - a "#" terminated string with the name of the object that was synced. + Autostars & LX200GPS - At static string: "M31 EX GAL MAG 3.5 SZ178.0'#" + """ + #SkySafari's "align" command sends this after a pair of :Sr# and :Sd# commands. + global offset_alt, offset_az + global local_alt, local_az, target_alt, target_dec + sys.stderr.write("Resetting from current position Alt %s (%0.5f radians), Az %s (%0.5f radians)\n" % + (radians_to_sddmmss(local_alt), local_alt, radians_to_hhmmss(local_az), local_az)) + sys.stderr.write("New target position RA %s (%0.5f radians), Dec %s (%0.5f radians)\n" % + (radians_to_hhmmss(target_ra), target_ra, radians_to_sddmmss(target_dec), target_dec)) + target_alt, target_az = equatorial_to_alt_az(target_ra, target_dec) + offset_alt += (target_alt - local_alt) + offset_az += (target_az - local_az) + offset_alt %= 2*pi + offset_az %= 2*pi + config.set("offsets", "altitude", offset_alt) + config.set("offsets", "azimuth", offset_az) + save_config() + update_alt_az() + sys.stderr.write("Revised current position Alt %s (%0.5f radians), Az %s (%0.5f radians)\n" % + (radians_to_sddmmss(local_alt), local_alt, radians_to_hhmmss(local_az), local_az)) + return "M31 EX GAL MAG 3.5 SZ178.0'" + +def meade_lx200_cmd_MS_move_to_target(): + """For the :MS# command, Slew to Target Object + + Returns: + 0 - Slew is Possible + 1# - Object Below Horizon w/string message + 2# - Object Below Higher w/string message + """ + #SkySafari's "goto" command sends this after a pair of :Sr# and :Sd# commands. + #For return code 1 and 2 the error message is not shown, simply that the + #target is below the horizon (1) or out of reach of the mount (2). + global target_ra, target_dec + if target_dec < 0: + return "1Target declination negative" + else: + return "2Sorry, no goto" + +def parse_hhmm(value): + """Turn string HH:MM.T or HH:MM:SS into radians.""" + parts = value.split(":") + if len(parts) == 2: + h = int(parts[0]) + m = float(parts[1]) + s = 0 + else: + h, m, s = [int(v) for v in parts] + # 12 hours = 43200 seconds = pi radians + return (h*3600 + m*60 + s) * pi / 43200 +_check_close(parse_hhmm("00:02.3"), 0.010035643198967393) +_check_close(parse_hhmm("00:02.4"), 0.010471975511965976) +_check_close(parse_hhmm("00:02:17"), 0.009962921146800963) +_check_close(parse_hhmm("00:02:18"), 0.010035643198967393) +_check_close(parse_hhmm("12:00:00"), pi) + +def parse_sddmm(value): + """Turn string sDD*MM or sDD*MM:SS into radians.""" + if value[3] != "*": + if len(value) == 9 and value[3] == chr(223) and value[6] == ":": + # Stellarium's variant in v0.12.4, since fixed: + # https://bugs.launchpad.net/stellarium/+bug/1272960 + # http://bazaar.launchpad.net/~stellarium/stellarium/trunk/revision/6529 + value = value.replace(chr(223), "*") + else: + raise ValueError("Bad format %r" % value) + if value[0] == "+": + sign = +1 + elif value[0] == "-": + sign = -1 + else: + raise ValueError("Bad sign in %r" % value) + deg = int(value[1:3]) + if len(value) == 6: + arc_minutes = int(value[4:6]) + arc_seconds = 0 + elif len(value) != 9 or value[6] != ":": + raise ValueError("Bad format %r" % value) + else: + arc_minutes = int(value[4:6]) + arc_seconds = int(value[7:9]) + return sign * (deg + arc_minutes/60.0 + arc_seconds/3600.0) * pi / 180.0 +_check_close(parse_sddmm("+00*01"), 0.000290888208666) +_check_close(parse_sddmm("+00*01:00"), 0.000290888208666) +_check_close(parse_sddmm("+57*17:45"), 1.0) +_check_close(parse_sddmm("+57*18"), 1.0) + +_check_close(parse_hhmm("07:01:55"), 1.84096) # RA +_check_close(parse_sddmm("+22*49:43"), 0.3984) # Dec + +def radians_to_hms(angle): + fraction, hours = modf(angle * 12 / pi) + fraction, minutes = modf(fraction * 60) + return hours, minutes, fraction * 60 +_check_close(radians_to_hms(0.01), (0, 2, 17.50987083139755)) +_check_close(radians_to_hms(6.28), (23.0, 59.0, 16.198882117679716)) + +def radians_to_hhmmss(angle): + while angle < 0.0: + sys.stderr.write("Warning, radians_to_hhmmss called with %0.2f\n" % angle) + angle += 2*pi + h, m, s = radians_to_hms(angle) + return "%02i:%02i:%02i#" % (h, m, round(s)) + +def radians_to_hhmmt(angle): + while angle < 0.0: + sys.stderr.write("Warning, radians_to_hhmmt called with %0.2f\n" % angle) + angle += 2*pi + h, m, s = radians_to_hms(angle) + return "%02i:%02i.%01i#" % (h, m, round(s / 6)) + +def radians_to_sddmm(angle): + """Signed degrees, arc-minutes as sDD*MM# for protocol.""" + if angle < 0.0: + sign = "-" + angle = abs(angle) + else: + sign = "+" + fraction, degrees = modf(angle * 180 / pi) + return "%s%02i*%02i#" % (sign, degrees, round(fraction * 60.0)) + +def radians_to_sddmmss(angle): + """Signed degrees, arc-minutes, arc-seconds as sDD*MM:SS# for protocol.""" + if angle < 0.0: + sign = "-" + angle = abs(angle) + else: + sign = "+" + fraction, degrees = modf(angle * 180 / pi) + fraction, arcminutes = modf(fraction * 60.0) + return "%s%02i*%02i:%02i#" % (sign, degrees, arcminutes, round(fraction * 60.0)) + +for r in [0.000290888208666, 1, -0.49*pi, -1.55, 0, 0.01, 0.1, 0.5*pi]: + #Testing RA from -pi/2 to pi/2 + assert -0.5*pi <= r <= 0.5*pi, r + _check_close(parse_sddmm(radians_to_sddmm(r).rstrip("#")), r, 0.0002) + _check_close(parse_sddmm(radians_to_sddmmss(r).rstrip("#")), r) +for r in [0, 0.01, 0.1, pi, 2*pi]: + #Testing dec from 0 to 2*pi + assert 0 <= r <= 2*pi, r + _check_close(parse_hhmm(radians_to_hhmmt(r).rstrip("#")), r) + _check_close(parse_hhmm(radians_to_hhmmss(r).rstrip("#")), r) + + +def meade_lx200_cmd_GR_get_ra(): + """For the :GR# command, Get Telescope RA + + Returns: HH:MM.T# or HH:MM:SS# + Depending which precision is set for the telescope + """ + #TODO - Since :GR# and :GD# commands normally in pairs, cache this? + update_alt_az() + ra, dec = alt_az_to_equatorial(local_alt, local_az) + if high_precision: + return radians_to_hhmmss(ra) + else: + #The .T is for tenths of a minute, see e.g. + #http://www.manualslib.com/manual/295083/Meade-Lx200.html?page=55 + return radians_to_hhmmt(ra) + +def meade_lx200_cmd_GD_get_dec(): + """For the :GD# command, Get Telescope Declination. + + Returns: sDD*MM# or sDD*MM'SS# + Depending upon the current precision setting for the telescope. + """ + update_alt_az() + ra, dec = alt_az_to_equatorial(local_alt, local_az) + if debug: + sys.stderr.write("RA %s (%0.5f radians), dec %s (%0.5f radians)\n" + % (radians_to_hhmmss(ra), ra, radians_to_sddmmss(dec), dec)) + if high_precision: + return radians_to_sddmmss(dec) + else: + return radians_to_sddmm(dec) + +def meade_lx200_cmd_Sr_set_target_ra(value): + """For the commands :SrHH:MM.T# or :SrHH:MM:SS# + + Set target object RA to HH:MM.T or HH:MM:SS depending on the current precision setting. + Returns: 0 - Invalid, 1 - Valid + + Stellarium breaks the specification and sends things like ':Sr 20:39:38#' + with an extra space. + """ + global target_ra + try: + target_ra = parse_hhmm(value.strip()) # Remove any space added by Stellarium + # The extra space sent by Stellarium v0.12.4 has been fixed: + # https://bugs.launchpad.net/stellarium/+bug/1272960 + sys.stderr.write("Parsed right-ascension :Sr%s# command as %0.5f radians\n" % (value, target_ra)) + return "1" + except Exception as err: + sys.stderr.write("Error parsing right-ascension :Sr%s# command: %s\n" % (value, err)) + return "0" + +def meade_lx200_cmd_Sd_set_target_de(value): + """For the command :SdsDD*MM# or :SdsDD*MM:SS# + + Set target object declination to sDD*MM or sDD*MM:SS depending on the current precision setting + Returns: 1 - Dec Accepted, 0 - Dec invalid + + Stellarium breaks this specification and sends things like ':Sd +15\xdf54:44#' + with an extra space, and the wrong characters. Apparently chr(223) is the + degrees symbol on some character sets. + """ + global target_dec + try: + target_dec = parse_sddmm(value.strip()) # Remove any space added by Stellarium + # The extra space sent by Stellarium v0.12.4 has been fixed: + # https://bugs.launchpad.net/stellarium/+bug/1272960 + sys.stderr.write("Parsed declination :Sd%s# command as %0.5f radians\n" % (value, target_dec)) + return "1" + except Exception as err: + sys.stderr.write("Error parsing declination :Sd%s# command: %s\n" % (value, err)) + return "0" + +def meade_lx200_cmd_U_precision_toggle(): + """For the :U# command, Toggle between low/hi precision positions + + Low - RA displays and messages HH:MM.T sDD*MM + High - Dec/Az/El displays and messages HH:MM:SS sDD*MM:SS + + Returns Nothing + """ + global high_precision + high_precision = not high_precision + if high_precision: + sys.stderr.write("Toggled high precision, now ON.\n") + else: + sys.stderr.write("Toggled high precision, now OFF.\n") + return None + +def meade_lx200_cmd_St_set_latitude(value): + """For the :StsDD*MM# command, Sets the current site latitdue to sDD*MM + + Returns: 0 - Invalid, 1 - Valid + """ + #Expect this to be followed by an Sg command to set the longitude... + global local_site, config + try: + value = value.replace("*", "d") + local_site.latitude = coords.AngularCoordinate(value) + #That worked, should be safe to save the value to disk later... + config.set("site", "latitude", value) + return "1" + except Exception as err: + sys.stderr.write("Error with :St%s# latitude: %s\n" % (value, err)) + return "0" + +def meade_lx200_cmd_Sg_set_longitude(value): + """For the :SgDDD*MM# command, Set current site longitude to DDD*MM + + Returns: 0 - Invalid, 1 - Valid + """ + #Expected immediately after the set latitude command + #e.g. :St+56*29# then :Sg003*08'# + global local_site, config + try: + value = value.replace("*", "d") + local_site.longitude = coords.AngularCoordinate(value) + sys.stderr.write("Local site now latitude %0.3fd, longitude %0.3fd\n" + % (local_site.latitude.d, local_site.longitude.d)) + #That worked, should be safe to save the value to disk: + config.set("site", "longitude", value) + save_config() + return "1" + except Exception as err: + sys.stderr.write("Error with :Sg%s# longitude: %s\n" % (value, err)) + return "0" + +def meade_lx200_cmd_SG_set_local_timezone(value): + """For the :SGsHH.H# command, Set the number of hours added to local time to yield UTC + + Returns: 0 - Invalid, 1 - Valid + """ + #Expected immediately after the set latitude and longitude commands + #Seems the decimal is optional, e.g. :SG-00# + global local_site + try: + local_site.tz = float(value) # Can in theory be partial hour, so not int + sys.stderr.write("Local site timezone now %s\n" % local_site.tz) + return "1" + except Exception as err: + sys.stderr.write("Error with :SG%s# time zone: %s\n" % (value, err)) + return "0" + +def meade_lx200_cmd_SL_set_local_time(value): + """For the :SLHH:MM:SS# command, Set the local Time + + Returns: 0 - Invalid, 1 - Valid + """ + global local_time_offset + local = time.time() + local_time_offset + #e.g. :SL00:10:48# + #Expect to be followed by an SC command to set the date. + try: + hh, mm, ss = (int(v) for v in value.split(":")) + if not (0 <= hh <= 24): + raise ValueError("Bad hour") + if not (0 <= mm <= 59): + raise ValueError("Bad minutes") + if not (0 <= ss <= 59): + raise ValueError("Bad seconds") + desired_seconds_since_midnight = 60*60*(hh + local_site.tz) + 60*mm + ss + t = time.gmtime(local) + current_seconds_since_midnight = 60*60*t.tm_hour + 60*t.tm_min + t.tm_sec + new_offset = desired_seconds_since_midnight - current_seconds_since_midnight + local_time_offset += new_offset + sys.stderr.write("Requested site time %i:%02i:%02i (TZ %s), new offset %is, total offset %is\n" + % (hh, mm, ss, local_site.tz, new_offset, local_time_offset)) + debug_time() + return "1" + except ValueError as err: + sys.stderr.write("Error with :SL%s# time setting: %s\n" % (value, err)) + return "0" + +def meade_lx200_cmd_SC_set_local_date(value): + """For the :SCMM/DD/YY# command, Change Handbox Date to MM/DD/YY + + Returns: + + D = '0' if the date is invalid. The string is the null string. + D = '1' for valid dates and the string is + 'Updating Planetary Data# #', + + Note: For LX200GPS/RCX400/Autostar II this is the UTC data! + """ + #Expected immediately after an SL command setting the time. + # + #Exact list of values from http://www.dv-fansler.com/FTP%20Files/Astronomy/LX200%20Hand%20Controller%20Communications.pdf + #return "1Updating planetary data. #%s#" % (" "*32) + # + #This seems to work but SkySafari takes a while to finish + #if setup as a Meade LX200 Classic - much faster on other + #models. + # + #Idea is to calculate any difference between the computer's + #date (e.g. 1 Jan 1980 if the Raspberry Pi booted offline) + #and the client's date in days (using the datetime module), + #and add this to our offset (converting it into seconds). + # + global local_time_offset + #TODO - Test this in non-GMT/UTC other time zones, esp near midnight + current = datetime.date.fromtimestamp(time.time() + local_time_offset) + try: + wanted = datetime.date.fromtimestamp(time.mktime(time.strptime(value, "%m/%d/%y"))) + days = (wanted - current).days + local_time_offset += days * 24 * 60 * 60 # 86400 seconds in a day + sys.stderr.write("Requested site date %s (MM/DD/YY) gives offset of %i days\n" % (value, days)) + debug_time() + return "1Updating Planetary Data#%s#" % (" "*30) + except ValueError as err: + sys.stderr.write("Error with :SC%s# date setting: %s\n" % (value, err)) + return "0" + +def return_one(value=None): + """Dummy command implementation returning value 1.""" + return "1" + +def return_none(value=None): + """Dummy command implementation returning nothing.""" + return None + +# TODO - Can SkySafari show focus control buttons? +# Would be very cool to connect my motorised focuser to this... +# +# :F+# move in - returns nothing +# :F-# move out - returns nothing +# :FQ# halt Focuser Motion - returns: nothing +# :FF# Set Focus speed to fastest - Returns: Nothing +# :FS# Set Focus speed to slowest - Returns: Nothing +# :F# set focuser speed to where is 1..4 - Returns: Nothing + +# ========================== +# Celestron NexStar Protocol +# ========================== + +def nexstar_cmd_V_version(): + """NexStar command V, version query, returns v1.2""" + return chr(1) + chr(2) + "#" + +def nexstar_cmd_E_get_ra_dec(): + """Nexstar command E, get RA/Dec. + + Returns integers in hex, fraction of 65536. + """ + update_alt_az() + ra, dec = alt_az_to_equatorial(local_alt, local_az) + #Convert from radians to fraction of 65536 + ra = int((65536*ra) / (2*pi)) + dec = int((65536*dec) / (2*pi)) + return "%04X,%04X#" % (ra, dec) + +def nexstar_cmd_e_get_ra_dec_precise(): + """Nexstar command e, get precise RA/Dec. + + Returns integers in hex, fraction of 4294967296. + """ + update_alt_az() + ra, dec = alt_az_to_equatorial(local_alt, local_az) + #Convert from radians to fraction of 4294967296 + ra = int((4294967296*ra) / (2*pi)) + dec = int((4294967296*dec) / (2*pi)) + return "%08X,%08X#"% (ra, dec) + +def nexstar_cmd_R_goto_ra_dec(value): + """Nexstar command R, goto RA/Dec + + e.g R34AB,12CE + """ + global target_ra, target_dec + target_ra, target_dec = (int(v,16)*2*pi/65536 for v in value.split(",")) + return "#" + +def nexstar_cmd_r_goto_ra_dec_precise(value): + """Nexstar command r, goto RA/Dec + + e.g. r34AB0500,12CE0500 + """ + global target_ra, target_dec + target_ra, target_dec = (int(v,16)*2*pi/4294967296 for v in value.split(",")) + return "#" + +def nexstar_cmd_M_cancel_goto(): + """Nextstar command M, cancel goto (stop moving)""" + return "#" + +def nexstar_cmd_P_passthrough(value): + """Nexstar command P, pass-though to motor, GPS, etc. + + Used for the slew commands (which we don't support). + """ + return "ERROR#" + +# ================ +# Main Server Code +# ================ + +command_map = { + #Meade LX200 commands: + ":CM": meade_lx200_cmd_CM_sync, + ":GD": meade_lx200_cmd_GD_get_dec, + ":GR": meade_lx200_cmd_GR_get_ra, + ":Me": return_none, #start moving East + ":Mn": return_none, #start moving North + ":Ms": return_none, #start moving South + ":Mw": return_none, #start moving West + ":MS": meade_lx200_cmd_MS_move_to_target, + ":Q": return_none, #abort all current slewing + ":Qe": return_none, #abort slew East + ":Qn": return_none, #abort slew North + ":Qs": return_none, #abort slew South + ":Qw": return_none, #abort slew West + ":RC": return_none, #set slew rate to centering (2nd slowest) + ":RG": return_none, #set slew rate to guiding (slowest) + ":RM": return_none, #set slew rate to find (2nd fastest) + ":RS": return_none, #set Slew rate to max (fastest) + ":Sd": meade_lx200_cmd_Sd_set_target_de, + ":Sr": meade_lx200_cmd_Sr_set_target_ra, + ":St": meade_lx200_cmd_St_set_latitude, + ":Sg": meade_lx200_cmd_Sg_set_longitude, + ":Sw": return_one, #set max slew rate + ":SG": meade_lx200_cmd_SG_set_local_timezone, + ":SL": meade_lx200_cmd_SL_set_local_time, + ":SC": meade_lx200_cmd_SC_set_local_date, + ":U": meade_lx200_cmd_U_precision_toggle, + #Celestron NexStar Communication Protocol + "V": nexstar_cmd_V_version, + "E": nexstar_cmd_E_get_ra_dec, + "e": nexstar_cmd_e_get_ra_dec_precise, + "R": nexstar_cmd_R_goto_ra_dec, + "r": nexstar_cmd_r_goto_ra_dec_precise, + "M": nexstar_cmd_M_cancel_goto, + "P": nexstar_cmd_P_passthrough, +} + +# Create a TCP/IP socket +sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +server_address = (server_name, server_port) +sys.stderr.write("Starting up on %s port %s\n" % server_address) +sock.bind(server_address) +sock.listen(1) + +while True: + # SkySafari v4.0.1 continously opens and closed the connection, + # while Stellarium via socat opens it and keeps it open using: + # $ ./socat GOPEN:/dev/ptyp0,ignoreeof TCP:raspberrypi8:4030 + # (probably socat which is maintaining the link) + #sys.stdout.write("waiting for a connection\n") + connection, client_address = sock.accept() + data = "" + try: + #sys.stdout.write("Client connected: %s, %s\n" % client_address) + while True: + data += connection.recv(16) + if not data: + imu.update() + break + if debug: + sys.stdout.write("Processing %r\n" % data) + #For stacked commands like ":RS#:GD#", + #but also lone NexStar ones like "e" + while data: + while data[0:1] == "#": + #Stellarium seems to send '#:GR#' and '#:GD#' + #(perhaps to explicitly close and prior command?) + #sys.stderr.write("Problem in data: %r - dropping leading #\n" % data) + data = data[1:] + if not data: + break + if "#" in data: + raw_cmd = data[:data.index("#")] + #sys.stderr.write("%r --> %r as command\n" % (data, raw_cmd)) + data = data[len(raw_cmd)+1:] + cmd, value = raw_cmd[:3], raw_cmd[3:] + else: + #This will break on complex NexStar commands, + #but don't care - Meade LX200 is the prority. + raw_cmd = data + cmd = raw_cmd[:3] + value = raw_cmd[3:] + data = "" + if not cmd: + sys.stderr.write("Eh? No command?\n") + elif cmd in command_map: + if value: + if debug: + sys.stdout.write("Command %r, argument %r\n" % (cmd, value)) + resp = command_map[cmd](value) + else: + resp = command_map[cmd]() + if resp: + if debug: + sys.stdout.write("Command %r, sending %r\n" % (cmd, resp)) + connection.sendall(resp) + else: + if debug: + sys.stdout.write("Command %r, no response\n" % cmd) + else: + sys.stderr.write("Unknown command %r, from %r (data %r)\n" % (cmd, raw_cmd, data)) + finally: + connection.close() \ No newline at end of file diff --git a/telescope_server.py b/telescope_server.py index e870a09..3a8035e 100755 --- a/telescope_server.py +++ b/telescope_server.py @@ -2,127 +2,72 @@ """TCP/IP server which listens for Meade LX200 style serial commands. Intended to mimick a SkyFi (serial to TCP/IP bridge) and compatible -Meade telescope normally controlled via a serial cable. In theory -this could be modified to listen to an actual serial port too... - -The intended goal is that celestial/planetarium software like the -SkySafari applications can talk to this server as if it was an off -the shelf Meade LX200 compatible "Go To" telescope, when in fact -it is a DIY intrumented telescope or simulation. - -See http://astrobeano.blogspot.co.uk/2014/01/instrumented-telescope-with-raspberry.html - -Testing with Sky Safari Plus v4.0, with the telescope usually setup as: - -Scope Type: Meade LX-200 GPS -Mount Type: Equatorial Push-To (or any push to setting) -Auto-Detect SkyFi: Off -IP Address: That of the computer running this script (default 10.0.0.1) -Port Number: 4030 (default) -Set Time & Location: On (default is off) -Readout Rate: 4 per second (default) -Save Log File: Off (default) - -With this, the "Connect/Disconnect" button works fine, once connected -the scope queries the position using the :GR# and :GD# commands. - -The "Goto" button is disabled (when configured as a Push-To telecope). - -The "Align" button gives an are you sure prompt with the currently -selected objects name (e.g. a star), and then sends its position -using the Sr and Sd commands, followed by the :CM# command. - -The "Lock/Unlock" button controls if SkySafari automatically pans -the display to keep the reported telescope direction centered. - -If configured as a Goto telescope, additional left/right and up/down -buttons appear on screen (which send East/West, North/South movement -commands. Also, a slew rate slider control appears. Depending on which -model telescope was selected, this may give four rates via the -RC/RG/RM/RS commands, or Sw commands (in the range 2 to 8). - -If SkySafari's "Set Time & Location" feature is selected, it will -send commands St and Sg (for the location) then SG, SL, SC to set -the time and date. If using "Meade LX-200 Classic" this imposes -a 15s delay, using a newer model like the "Meade LX-200 GPS" there -is no noticeable delay on connection. - -Additional limited testing also done with the Celestron NexStar -protocol, although SkySafari 4 does not seem to use its built in -commands for setting the date/time or location, nor the synching -commands for alignment. -""" +Meade telescope normally controlled via a serial cable. -#More references on Alt/Az horizontal coordinates to equatorial: -#http://pythonhosted.org/Astropysics/coremods/obstools.html#astropysics.obstools.Site -#https://github.com/eteq/astropysics/issues/21 -#https://github.com/astropy/astropy-api/pull/6 -#http://infohost.nmt.edu/tcc/help/lang/python/examples/sidereal/ims/ +Peter Cook - https://github.com/peterjc +refactoring attempts - Craig Cmehil - https://github.com/ccmehil +""" import socket import os import sys -import commands +import subprocess try: import configparser except ImportError: import ConfigParser as configparser import time import datetime +from datetime import datetime as dt from math import pi, sin, cos, asin, acos, atan2, modf -#TODO - Try astropy if I can get it to compile on Mac OS X... -from astropysics import coords -from astropysics import obstools +from astropy.coordinates import SkyCoord, EarthLocation, AltAz, Longitude, Angle +from astropy import coordinates as coord +from astropy.time import Time +from astropy import units as u +import numpy as np #Local import -from gy80 import GY80 +from mpu9250 import GYMOD #MPU9250 hardware module +# from gy80 import GYMOD #GY-80 hardware module +print("Checking Configuration") config_file = "telescope_server.ini" if not os.path.isfile(config_file): print("Using default settings") h = open("telescope_server.ini", "w") - h.write("[server]\nname=10.0.0.1\nport=4030\n") - #Default to Greenwich as the site - h.write("[site]\nlatitude=+51d28m38s\nlongitude=0\n") + h.write("[server]\nname=127.0.0.1\nport=4030\n") + #Default to Greenwich as the site, 1 as tz + h.write("[site]\naddress=Greenwich\n") + h.write("[site]\ntz=1\n") + h.write("[site]\nlatitude=51.6712\n") + h.write("[site]\nlongitude=8.3406\n") #Default to no correction of the angles h.write("[offsets]\nazimuth=0\naltitude=0\n") h.close() print("Connecting to sensors...") -imu = GY80() -print("Connected to GY-80 sensor") +imu = GYMOD() +print("Connected to MPU9250 sensor") print("Opening network port...") config = configparser.ConfigParser() config.read("telescope_server.ini") server_name = config.get("server", "name") #e.g. 10.0.0.1 server_port = config.getint("server", "port") #e.g. 4030 -#server_name = socket.gethostbyname(socket.gethostname()) -#if server_name.startswith("127.0."): #e.g. 127.0.0.1 -# #This works on Linux but not on Mac OS X or Windows: -# server_name = commands.getoutput("/sbin/ifconfig").split("\n")[1].split()[1][5:] -##server_name = "10.0.0.1" #Override for wifi access -#server_port = 4030 #Default port used by SkySafari +site_address = config.get("site", "address") #e.g. Greenwich +site_tz = config.get("site", "tz") #e.g. 1 +site_latitude = config.get("site", "latitude") #e.g. 51.4176 +site_longitude = config.get("site", "longitude") #e.g. 8.1923 #If default to low precision, SkySafari turns it on anyway: high_precision = True -#Default to Greenwich, GMT - Latitude 51deg 28' 38'' N, Longitude zero -local_site = obstools.Site(coords.AngularCoordinate(config.get("site", "latitude")), - coords.AngularCoordinate(config.get("site", "longitude")), - tz=0) #Rather than messing with the system clock, will store any difference #between the local computer's date/time and any date/time set by the #client (which should match any location set by the client). local_time_offset = 0 -#This will probably best be inferred by calibration... -#For Greenwich, magnetic north is estimated to be 2 deg 40 min west -#of grid north at Greenwich in July 2013. -#http://www.geomag.bgs.ac.uk/data_service/models_compass/gma_calc.html -#local_site_magnetic_offset = -2.67 * pi / 180.0 - #These will come from sensor information... storing them in radians local_alt = 85 * pi / 180.0 local_az = 30 * pi / 180.0 @@ -133,14 +78,22 @@ target_ra = 0.0 target_dec = 0.0 -#Turn on for lots of logging... -debug = False +#Turn on for lots of logging, debug_function add the function name if you want to +# focus on a single functions output. Debug statements in each function start +# with 'FUNCTION xxxxx' or simply with ' ' to display all +debug = True +debug_function = ' ' def save_config(): global condig, config_file with open(config_file, "w") as handle: config.write(handle) +def debug_info(str): + if debug: + if debug_function in str: + sys.stdout.write("%s\n" % str) + def _check_close(a, b, error=0.0001): if isinstance(a, (tuple, list)): assert isinstance(b, (tuple, list)) @@ -156,6 +109,14 @@ def _check_close(a, b, error=0.0001): raise ValueError("%s vs %s, difference %s > %s" % (a, b, diff, error)) +def obs_time(): + debug_info("FUNCTION obs_time") + now = dt.now() + times = [now] + t = Time(times, scale='utc') + obstime = Time(t) + np.linspace(0, 6, 10000) * u.hour + return dt.utcnow() + def update_alt_az(): global imu, offset_alt, offset_az, local_alt, local_az yaw, pitch, roll = imu.current_orientation_euler_angles_hybrid() @@ -167,21 +128,26 @@ def update_alt_az(): #Altitude is measured upwards local_alt = (offset_alt + pitch) % (2*pi) #We don't care about the roll for the Meade LX200 protocol. + debug_info("FUNCTION update_alt_az - local_alt %r - local_az %r" % (local_alt, local_az) ) def site_time_gmt_as_epoch(): global local_time_offset + debug_info("FUNCTION site_time_gmt_as_epoch") return time.time() + local_time_offset def site_time_gmt_as_datetime(): + debug_info("FUNCTION site_time_gmt_as_datetime") return datetime.datetime.fromtimestamp(site_time_gmt_as_epoch()) def site_time_local_as_datetime(): - global local_site - return site_time_gmt_as_datetime() - datetime.timedelta(hours=local_site.tz) + global site_tz + debug_info("FUNCTION site_time_local_as_datetime - site_tz %r" % site_tz) + return site_time_gmt_as_datetime() - datetime.timedelta(hours=site_tz) def debug_time(): - global local_site - if local_site.tz: + global site_tz + debug_info("FUNCTION debug_time - site_tz %r" % site_tz) + if site_tz: sys.stderr.write("Effective site date/time is %s (local time), %s (GMT/UTC)\n" % (site_time_local_as_datetime(), site_time_gmt_as_datetime())) else: @@ -189,60 +155,28 @@ def debug_time(): % site_time_gmt_as_datetime()) def greenwich_sidereal_time_in_radians(): - """Calculate using GMT (according to client's time settings).""" - #Function astropysics.obstools.epoch_to_jd wants a decimal year as input - #Function astropysics.obstools.calendar_to_jd can take a datetime object - gmt_jd = obstools.calendar_to_jd(site_time_gmt_as_datetime()) - #Convert from hours to radians... 24hr = 2*pi - return coords.greenwich_sidereal_time(gmt_jd) * pi / 12 + now = dt.now() + times = [now] + t = Time(times, scale='utc') + debug_info("FUNCTION greenwich_sidereal_time_in_radians - value %r" % t.sidereal_time('apparent', 'greenwich')) + return t.sidereal_time('apparent', 'greenwich').radian[0] def alt_az_to_equatorial(alt, az, gst=None): - global local_site #and time offset used too - if gst is None: - gst = greenwich_sidereal_time_in_radians() - lat = local_site.latitude.r - #Calculate these once only for speed - sin_lat = sin(lat) - cos_lat = cos(lat) - sin_alt = sin(alt) - cos_alt = cos(alt) - sin_az = sin(az) - cos_az = cos(az) - dec = asin(sin_alt*sin_lat + cos_alt*cos_lat*cos_az) - hours_in_rad = acos((sin_alt - sin_lat*sin(dec)) / (cos_lat*cos(dec))) - if sin_az > 0.0: - hours_in_rad = 2*pi - hours_in_rad - ra = gst - local_site.longitude.r - hours_in_rad - return ra % (pi*2), dec + debug_info("FUNCTION alt_az_to_equatorial - passed values: alt %r - az %r" % (alt, az)) + global location + newAltAz = SkyCoord(alt = alt * u.deg, az = az * u.deg, obstime = dt.utcnow(), frame = 'altaz', location = location) + debug_info("FUNCTION alt_az_to_equatorial - actual values: ra %r - dec %r" % (newAltAz.transform_to('icrs').ra.radian, newAltAz.transform_to('icrs').dec.radian)) + return newAltAz.transform_to('icrs').ra.radian, newAltAz.transform_to('icrs').dec.radian def equatorial_to_alt_az(ra, dec, gst=None): - global local_site #and time offset used too - if gst is None: - gst = greenwich_sidereal_time_in_radians() - lat = local_site.latitude.r - #Calculate these once only for speed - sin_lat = sin(lat) - cos_lat = cos(lat) - sin_dec = sin(dec) - cos_dec = cos(dec) - h = gst - local_site.longitude.r - ra - sin_h = sin(h) - cos_h = cos(h) - alt = asin(sin_lat*sin_dec + cos_lat*cos_dec*cos_h) - az = atan2(-cos_dec*sin_h, cos_lat*sin_dec - sin_lat*cos_dec*cos_h) - return alt, az % (2*pi) -#This test implicitly assumes time between two calculations not significant: -_check_close((1.84096, 0.3984), alt_az_to_equatorial(*equatorial_to_alt_az(1.84096, 0.3984))) -#_check_close(parse_hhmm("07:01:55"), 1.84096) # RA -#_check_close(parse_sddmm("+22*49:43"), 0.3984) # Dec - -#This ensures identical time stamp used: -gst = greenwich_sidereal_time_in_radians() -for ra in [0.1, 1, 2, 3, pi, 4, 5, 6, 1.99*pi]: - for dec in [-0.49*pi, -1.1, -1, 0, 0.001, 1.55, 0.49*pi]: - alt, az = equatorial_to_alt_az(ra, dec, gst) - _check_close((ra, dec), alt_az_to_equatorial(alt, az, gst)) -del gst, ra, dec + debug_info("FUNCTION equatorial_to_alt_az - passed values: ra %r - dec %r" % (ra, dec)) + global location + skyobject = SkyCoord.from_name('M41') + skyobjectaltaz = skyobject.transform_to(AltAz(obstime=dt.utcnow(),location=location)) + az = skyobjectaltaz.az.to_string() + alt = skyobjectaltaz.alt.to_string() + debug_info("FUNCTION equatorial_to_alt_az - returned values: alt %r - az %r" % (az.rpartition('d')[0], alt.rpartition('d')[0])) + return az.rpartition('d')[0], alt.rpartition('d')[0] # ==================== # Meade LX200 Protocol @@ -255,14 +189,16 @@ def meade_lx200_cmd_CM_sync(): LX200's - a "#" terminated string with the name of the object that was synced. Autostars & LX200GPS - At static string: "M31 EX GAL MAG 3.5 SZ178.0'#" """ + debug_info("FUNCTION meade_lx200_cmd_CM_sync") #SkySafari's "align" command sends this after a pair of :Sr# and :Sd# commands. global offset_alt, offset_az global local_alt, local_az, target_alt, target_dec - sys.stderr.write("Resetting from current position Alt %s (%0.5f radians), Az %s (%0.5f radians)\n" % + debug_info("FUNCTION meade_lx200_cmd_CM_sync - Resetting from current position Alt %s (%0.5f radians), Az %s (%0.5f radians)\n" % (radians_to_sddmmss(local_alt), local_alt, radians_to_hhmmss(local_az), local_az)) - sys.stderr.write("New target position RA %s (%0.5f radians), Dec %s (%0.5f radians)\n" % + debug_info("FUNCTION meade_lx200_cmd_CM_sync - New target position RA %s (%0.5f radians), Dec %s (%0.5f radians)\n" % (radians_to_hhmmss(target_ra), target_ra, radians_to_sddmmss(target_dec), target_dec)) target_alt, target_az = equatorial_to_alt_az(target_ra, target_dec) + debug_info("FUNCTION meade_lx200_cmd_CM_sync - target_alt, target az: %s, %s" % (target_alt, target_az)) offset_alt += (target_alt - local_alt) offset_az += (target_az - local_az) offset_alt %= 2*pi @@ -271,7 +207,7 @@ def meade_lx200_cmd_CM_sync(): config.set("offsets", "azimuth", offset_az) save_config() update_alt_az() - sys.stderr.write("Revised current position Alt %s (%0.5f radians), Az %s (%0.5f radians)\n" % + debug_info("FUNCTION meade_lx200_cmd_CM_sync - Revised current position Alt %s (%0.5f radians), Az %s (%0.5f radians)\n" % (radians_to_sddmmss(local_alt), local_alt, radians_to_hhmmss(local_az), local_az)) return "M31 EX GAL MAG 3.5 SZ178.0'" @@ -283,6 +219,7 @@ def meade_lx200_cmd_MS_move_to_target(): 1# - Object Below Horizon w/string message 2# - Object Below Higher w/string message """ + debug_info("FUNCTION meade_lx200_cmd_MS_move_to_target") #SkySafari's "goto" command sends this after a pair of :Sr# and :Sd# commands. #For return code 1 and 2 the error message is not shown, simply that the #target is below the horizon (1) or out of reach of the mount (2). @@ -294,6 +231,7 @@ def meade_lx200_cmd_MS_move_to_target(): def parse_hhmm(value): """Turn string HH:MM.T or HH:MM:SS into radians.""" + debug_info("FUNCTION parse_hhmm") parts = value.split(":") if len(parts) == 2: h = int(parts[0]) @@ -311,6 +249,7 @@ def parse_hhmm(value): def parse_sddmm(value): """Turn string sDD*MM or sDD*MM:SS into radians.""" + debug_info("FUNCTION parse_sddmm") if value[3] != "*": if len(value) == 9 and value[3] == chr(223) and value[6] == ":": # Stellarium's variant in v0.12.4, since fixed: @@ -344,6 +283,7 @@ def parse_sddmm(value): _check_close(parse_sddmm("+22*49:43"), 0.3984) # Dec def radians_to_hms(angle): + debug_info("FUNCTION radians_to_hms") fraction, hours = modf(angle * 12 / pi) fraction, minutes = modf(fraction * 60) return hours, minutes, fraction * 60 @@ -351,6 +291,7 @@ def radians_to_hms(angle): _check_close(radians_to_hms(6.28), (23.0, 59.0, 16.198882117679716)) def radians_to_hhmmss(angle): + debug_info("FUNCTION radians_to_hhmmss") while angle < 0.0: sys.stderr.write("Warning, radians_to_hhmmss called with %0.2f\n" % angle) angle += 2*pi @@ -358,6 +299,7 @@ def radians_to_hhmmss(angle): return "%02i:%02i:%02i#" % (h, m, round(s)) def radians_to_hhmmt(angle): + debug_info("FUNCTION radians_to_hhmmt") while angle < 0.0: sys.stderr.write("Warning, radians_to_hhmmt called with %0.2f\n" % angle) angle += 2*pi @@ -366,30 +308,42 @@ def radians_to_hhmmt(angle): def radians_to_sddmm(angle): """Signed degrees, arc-minutes as sDD*MM# for protocol.""" + debug_info("FUNCTION radians_to_sddmm") if angle < 0.0: sign = "-" angle = abs(angle) else: sign = "+" - fraction, degrees = modf(angle * 180 / pi) + fraction, degrees = modf(angle / pi) return "%s%02i*%02i#" % (sign, degrees, round(fraction * 60.0)) def radians_to_sddmmss(angle): - """Signed degrees, arc-minutes, arc-seconds as sDD*MM:SS# for protocol.""" + """ + Signed degrees, arc-minutes, arc-seconds as sDD*MM:SS# for protocol. + FUNCTION radians_to_sddmmss + angle: 95.71562968082463 + fraction: 0.03387138278878865 + degress: 30.0 + return: -30*28:02# + """ + debug_info("FUNCTION radians_to_sddmmss - passed values: %s" % angle) if angle < 0.0: sign = "-" angle = abs(angle) else: sign = "+" - fraction, degrees = modf(angle * 180 / pi) + fraction, degrees = modf(angle / pi) fraction, arcminutes = modf(fraction * 60.0) + debug_info("FUNCTION radians_to_sddmmss - actual values: angle = %s, fraction = %s, degrees = %s, arcminutes = %s\n" % (angle, fraction, degrees, arcminutes)) + debug_info("FUNCTION radians_to_sddmmss - return values: %s\n" % "%s%02i*%02i:%02i#" % (sign, degrees, arcminutes, round(fraction * 60.0))) return "%s%02i*%02i:%02i#" % (sign, degrees, arcminutes, round(fraction * 60.0)) - +''' for r in [0.000290888208666, 1, -0.49*pi, -1.55, 0, 0.01, 0.1, 0.5*pi]: #Testing RA from -pi/2 to pi/2 assert -0.5*pi <= r <= 0.5*pi, r _check_close(parse_sddmm(radians_to_sddmm(r).rstrip("#")), r, 0.0002) _check_close(parse_sddmm(radians_to_sddmmss(r).rstrip("#")), r) +''' for r in [0, 0.01, 0.1, pi, 2*pi]: #Testing dec from 0 to 2*pi assert 0 <= r <= 2*pi, r @@ -404,6 +358,7 @@ def meade_lx200_cmd_GR_get_ra(): Depending which precision is set for the telescope """ #TODO - Since :GR# and :GD# commands normally in pairs, cache this? + debug_info("FUNCTION meade_lx200_cmd_GR_get_ra") update_alt_az() ra, dec = alt_az_to_equatorial(local_alt, local_az) if high_precision: @@ -419,9 +374,11 @@ def meade_lx200_cmd_GD_get_dec(): Returns: sDD*MM# or sDD*MM'SS# Depending upon the current precision setting for the telescope. """ + debug_info("FUNCTION meade_lx200_cmd_GD_get_dec") update_alt_az() ra, dec = alt_az_to_equatorial(local_alt, local_az) if debug: + sys.stdout.write("\nFUNCTION meade_lx200_cmd_GD_get_dec\n") sys.stderr.write("RA %s (%0.5f radians), dec %s (%0.5f radians)\n" % (radians_to_hhmmss(ra), ra, radians_to_sddmmss(dec), dec)) if high_precision: @@ -438,6 +395,7 @@ def meade_lx200_cmd_Sr_set_target_ra(value): Stellarium breaks the specification and sends things like ':Sr 20:39:38#' with an extra space. """ + debug_info("FUNCTION meade_lx200_cmd_Sr_set_target_ra - passed values: %s" % value) global target_ra try: target_ra = parse_hhmm(value.strip()) # Remove any space added by Stellarium @@ -459,6 +417,7 @@ def meade_lx200_cmd_Sd_set_target_de(value): with an extra space, and the wrong characters. Apparently chr(223) is the degrees symbol on some character sets. """ + debug_info("FUNCTION meade_lx200_cmd_Sd_set_target_de - passed values: %s" % value) global target_dec try: target_dec = parse_sddmm(value.strip()) # Remove any space added by Stellarium @@ -478,6 +437,7 @@ def meade_lx200_cmd_U_precision_toggle(): Returns Nothing """ + debug_info("FUNCTION meade_lx200_cmd_U_precision_toggle") global high_precision high_precision = not high_precision if high_precision: @@ -491,11 +451,12 @@ def meade_lx200_cmd_St_set_latitude(value): Returns: 0 - Invalid, 1 - Valid """ + debug_info("FUNCTION meade_lx200_cmd_St_set_latitude - passed value: %s" % value ) #Expect this to be followed by an Sg command to set the longitude... - global local_site, config + global config, site_latitude try: value = value.replace("*", "d") - local_site.latitude = coords.AngularCoordinate(value) + site_latitude = value #That worked, should be safe to save the value to disk later... config.set("site", "latitude", value) return "1" @@ -508,14 +469,14 @@ def meade_lx200_cmd_Sg_set_longitude(value): Returns: 0 - Invalid, 1 - Valid """ + debug_info("FUNCTION meade_lx200_cmd_Sg_set_longitude - passed value: %s" % value ) #Expected immediately after the set latitude command #e.g. :St+56*29# then :Sg003*08'# - global local_site, config + global config, site_latitude, site_longitude try: value = value.replace("*", "d") - local_site.longitude = coords.AngularCoordinate(value) - sys.stderr.write("Local site now latitude %0.3fd, longitude %0.3fd\n" - % (local_site.latitude.d, local_site.longitude.d)) + site_longitude = value + sys.stderr.write("Local site now latitude %s, longitude %s\n" % (site_latitude, site_longitude)) #That worked, should be safe to save the value to disk: config.set("site", "longitude", value) save_config() @@ -531,10 +492,11 @@ def meade_lx200_cmd_SG_set_local_timezone(value): """ #Expected immediately after the set latitude and longitude commands #Seems the decimal is optional, e.g. :SG-00# - global local_site + debug_info("FUNCTION meade_lx200_cmd_SG_set_local_timezone - passed values: site_tz = %s" % value ) + global site_tz try: - local_site.tz = float(value) # Can in theory be partial hour, so not int - sys.stderr.write("Local site timezone now %s\n" % local_site.tz) + site_tz = float(value) # Can in theory be partial hour, so not int + sys.stderr.write("Local site timezone now %s\n" % site_tz) return "1" except Exception as err: sys.stderr.write("Error with :SG%s# time zone: %s\n" % (value, err)) @@ -545,7 +507,8 @@ def meade_lx200_cmd_SL_set_local_time(value): Returns: 0 - Invalid, 1 - Valid """ - global local_time_offset + debug_info("FUNCTION meade_lx200_cmd_SL_set_local_time - passed values: %s" % value ) + global local_time_offset, site_tz local = time.time() + local_time_offset #e.g. :SL00:10:48# #Expect to be followed by an SC command to set the date. @@ -557,13 +520,13 @@ def meade_lx200_cmd_SL_set_local_time(value): raise ValueError("Bad minutes") if not (0 <= ss <= 59): raise ValueError("Bad seconds") - desired_seconds_since_midnight = 60*60*(hh + local_site.tz) + 60*mm + ss + desired_seconds_since_midnight = 60*60*(hh + site_tz) + 60*mm + ss t = time.gmtime(local) current_seconds_since_midnight = 60*60*t.tm_hour + 60*t.tm_min + t.tm_sec new_offset = desired_seconds_since_midnight - current_seconds_since_midnight local_time_offset += new_offset sys.stderr.write("Requested site time %i:%02i:%02i (TZ %s), new offset %is, total offset %is\n" - % (hh, mm, ss, local_site.tz, new_offset, local_time_offset)) + % (hh, mm, ss, site_tz, new_offset, local_time_offset)) debug_time() return "1" except ValueError as err: @@ -581,6 +544,7 @@ def meade_lx200_cmd_SC_set_local_date(value): Note: For LX200GPS/RCX400/Autostar II this is the UTC data! """ + debug_info("FUNCTION meade_lx200_cmd_SC_set_local_date - passed values: %s" % value ) #Expected immediately after an SL command setting the time. # #Exact list of values from http://www.dv-fansler.com/FTP%20Files/Astronomy/LX200%20Hand%20Controller%20Communications.pdf @@ -617,9 +581,6 @@ def return_none(value=None): """Dummy command implementation returning nothing.""" return None -# TODO - Can SkySafari show focus control buttons? -# Would be very cool to connect my motorised focuser to this... -# # :F+# move in - returns nothing # :F-# move out - returns nothing # :FQ# halt Focuser Motion - returns: nothing @@ -627,67 +588,6 @@ def return_none(value=None): # :FS# Set Focus speed to slowest - Returns: Nothing # :F# set focuser speed to where is 1..4 - Returns: Nothing -# ========================== -# Celestron NexStar Protocol -# ========================== - -def nexstar_cmd_V_version(): - """NexStar command V, version query, returns v1.2""" - return chr(1) + chr(2) + "#" - -def nexstar_cmd_E_get_ra_dec(): - """Nexstar command E, get RA/Dec. - - Returns integers in hex, fraction of 65536. - """ - update_alt_az() - ra, dec = alt_az_to_equatorial(local_alt, local_az) - #Convert from radians to fraction of 65536 - ra = int((65536*ra) / (2*pi)) - dec = int((65536*dec) / (2*pi)) - return "%04X,%04X#" % (ra, dec) - -def nexstar_cmd_e_get_ra_dec_precise(): - """Nexstar command e, get precise RA/Dec. - - Returns integers in hex, fraction of 4294967296. - """ - update_alt_az() - ra, dec = alt_az_to_equatorial(local_alt, local_az) - #Convert from radians to fraction of 4294967296 - ra = int((4294967296*ra) / (2*pi)) - dec = int((4294967296*dec) / (2*pi)) - return "%08X,%08X#"% (ra, dec) - -def nexstar_cmd_R_goto_ra_dec(value): - """Nexstar command R, goto RA/Dec - - e.g R34AB,12CE - """ - global target_ra, target_dec - target_ra, target_dec = (int(v,16)*2*pi/65536 for v in value.split(",")) - return "#" - -def nexstar_cmd_r_goto_ra_dec_precise(value): - """Nexstar command r, goto RA/Dec - - e.g. r34AB0500,12CE0500 - """ - global target_ra, target_dec - target_ra, target_dec = (int(v,16)*2*pi/4294967296 for v in value.split(",")) - return "#" - -def nexstar_cmd_M_cancel_goto(): - """Nextstar command M, cancel goto (stop moving)""" - return "#" - -def nexstar_cmd_P_passthrough(value): - """Nexstar command P, pass-though to motor, GPS, etc. - - Used for the slew commands (which we don't support). - """ - return "ERROR#" - # ================ # Main Server Code # ================ @@ -720,58 +620,49 @@ def nexstar_cmd_P_passthrough(value): ":SL": meade_lx200_cmd_SL_set_local_time, ":SC": meade_lx200_cmd_SC_set_local_date, ":U": meade_lx200_cmd_U_precision_toggle, - #Celestron NexStar Communication Protocol - "V": nexstar_cmd_V_version, - "E": nexstar_cmd_E_get_ra_dec, - "e": nexstar_cmd_e_get_ra_dec_precise, - "R": nexstar_cmd_R_goto_ra_dec, - "r": nexstar_cmd_r_goto_ra_dec_precise, - "M": nexstar_cmd_M_cancel_goto, - "P": nexstar_cmd_P_passthrough, } +#Set local site (AltAz) +obs = obs_time() +location = EarthLocation.of_address(site_address) +debug_info("Location %r" % location) + +#c = SkyCoord(ra=site_latitude*u.degree, dec=site_longitude*u.degree, frame='icrs') +#local_site = c.transform_to(AltAz(obstime = obs, location = loc)) + # Create a TCP/IP socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_address = (server_name, server_port) -sys.stderr.write("Starting up on %s port %s\n" % server_address) +sys.stderr.write("\nStarting up on %s port %s\n" % server_address) sock.bind(server_address) -sock.listen(1) +sock.listen(5) while True: - # SkySafari v4.0.1 continously opens and closed the connection, - # while Stellarium via socat opens it and keeps it open using: - # $ ./socat GOPEN:/dev/ptyp0,ignoreeof TCP:raspberrypi8:4030 - # (probably socat which is maintaining the link) - #sys.stdout.write("waiting for a connection\n") + sys.stdout.write("Waiting for a connection\n") connection, client_address = sock.accept() data = "" try: - #sys.stdout.write("Client connected: %s, %s\n" % client_address) + sys.stdout.write("Client connected: %s, %s\n" % client_address) while True: - data += connection.recv(16) + data_received = connection.recv(16) + data = data_received.decode() if not data: imu.update() break - if debug: - sys.stdout.write("Processing %r\n" % data) #For stacked commands like ":RS#:GD#", - #but also lone NexStar ones like "e" + debug_info("Processing %r" % data) while data: while data[0:1] == "#": - #Stellarium seems to send '#:GR#' and '#:GD#' - #(perhaps to explicitly close and prior command?) - #sys.stderr.write("Problem in data: %r - dropping leading #\n" % data) + sys.stderr.write("Problem in data: %r - dropping leading #\n" % data) data = data[1:] if not data: break if "#" in data: raw_cmd = data[:data.index("#")] - #sys.stderr.write("%r --> %r as command\n" % (data, raw_cmd)) + sys.stderr.write("%r --> %r as command\n" % (data, raw_cmd)) data = data[len(raw_cmd)+1:] cmd, value = raw_cmd[:3], raw_cmd[3:] else: - #This will break on complex NexStar commands, - #but don't care - Meade LX200 is the prority. raw_cmd = data cmd = raw_cmd[:3] value = raw_cmd[3:] @@ -780,18 +671,15 @@ def nexstar_cmd_P_passthrough(value): sys.stderr.write("Eh? No command?\n") elif cmd in command_map: if value: - if debug: - sys.stdout.write("Command %r, argument %r\n" % (cmd, value)) + debug_info("Command %r, argument %r" % (cmd, value)) resp = command_map[cmd](value) else: resp = command_map[cmd]() if resp: - if debug: - sys.stdout.write("Command %r, sending %r\n" % (cmd, resp)) - connection.sendall(resp) + debug_info("Command %r, sending %r" % (cmd, resp)) + connection.sendall(resp.encode()) else: - if debug: - sys.stdout.write("Command %r, no response\n" % cmd) + debug_info("Command %r, no response" % cmd) else: sys.stderr.write("Unknown command %r, from %r (data %r)\n" % (cmd, raw_cmd, data)) finally: diff --git a/testing/mpu9250_test.py b/testing/mpu9250_test.py new file mode 100644 index 0000000..fe920bd --- /dev/null +++ b/testing/mpu9250_test.py @@ -0,0 +1,28 @@ +# https://pypi.org/project/mpu9250-jmdev/ + +import time +from mpu9250_jmdev.registers import * +from mpu9250_jmdev.mpu_9250 import MPU9250 + +mpu = MPU9250( + address_ak=AK8963_ADDRESS, + address_mpu_master=MPU9050_ADDRESS_68, # In 0x68 Address + address_mpu_slave=None, + bus=1, + gfs=GFS_1000, + afs=AFS_8G, + mfs=AK8963_BIT_16, + mode=AK8963_MODE_C100HZ) + +mpu.configure() # Apply the settings to the registers. + +while True: + + print("|.....MPU9250 in 0x68 Address.....|") + print("Accelerometer", mpu.readAccelerometerMaster()) + print("Gyroscope", mpu.readGyroscopeMaster()) + print("Magnetometer", mpu.readMagnetometerMaster()) + print("Temperature", mpu.readTemperatureMaster()) + print("\n") + + time.sleep(1) diff --git a/testing/readme.md b/testing/readme.md new file mode 100644 index 0000000..586f454 --- /dev/null +++ b/testing/readme.md @@ -0,0 +1,40 @@ +# Testing Hardware + +Current Hardware being used with a *Raspberry PI Zero WH*, *MPU9250 Module*. + +MPU-9250 is a multi-chip module (MCM) consisting of two dies integrated into a single QFN package. One die the MPU-6500 houses the 3-Axis gyroscope, the 3-Axis accelerometer and temperature sensor. The other die houses the AK8963 3-Axis magnetometer. Hence, the MPU-9250 is a 9-axis MotionTracking device that combines a 3-axis gyroscope, 3-axis accelerometer, 3-axis magnetometer and a Digital Motion Processorâ„¢ (DMP). The hardware documentation for MPU-9250 can be found at [Product Specification](https://github.com/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect/blob/master/doc/MPU-9250%20Product%20Specification%20Revision%201.1.pdf) and [Register Map and Descriptions](https://github.com/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect/blob/master/doc/MPU-9250%20Register%20Map%20and%20Descriptions%20Revision%201.6.pdf). +- [Source](https://pypi.org/project/mpu9250-jmdev/) + + pip install mpu9250-jmdev + +Run *sudo raspi-config* and enable under interfaces REMOTE GPIO + +Then to enable the hardware on your Raspberry PI you will need to do the following: + + sudo nano /etc/modules + +Ensure both of these lines are listed. + + i2c-bcm2708 + i2c-dev + +Now run + + sudo apt-get install i2c-tools + sudo i2cdetect -l + +You should hopefully now see 2 IC2 Adapters listed. + + sudo i2cdetect -y 1 (or sudo i2cdetect -y 0) + +Should now hopefully give you some results. Numbers will be in place of the "-" in some areas. + + sudo usermod -a -G i2c pi + +Tip to David Grayson's documentation for his Raspberry C++ code for the MinIMU-9 sensor which is similar to the GY-80. And http://astrobeano.blogspot.com/2014/01/gy-80-orientation-sensor-on-raspberry-pi.html for figuring it all out! + +Now to wire up the module to the Raspberry Pi, in most cases it is a female-to-female connector and you will need 4 wires. + +Wiring: https://www.maxbotix.com/Setup-Raspberry-Pi-Zero-for-i2c-Sensor-151 + +Python test script file is from [mpu9250-jmdev 1.0.12](https://pypi.org/project/mpu9250-jmdev/)