def run(self): # folder = 'D:/star_guiding/images/2019-02-25.18-18-55' folder = '../test/images-2019-02-25.18-11-26' filenames = list(map(lambda s2: folder + '/' + s2, os.listdir(folder))) filenames = sorted(filenames, key = lambda s: int(s.split('/')[-1].split('.')[0])) filenames = filenames[:100] imgs = [None for file in filenames] count = 0 while self.keepRunning: time.sleep(max(0.5, self.shutter_speed_ms / 1000.)) index = count % len(imgs) if (count // len(imgs)) % 2 > 0: #flip around backwards for continuity index = len(imgs) - index - 1 if imgs[index] is None: imgs[index] = load_image(filenames[index]) img = imgs[index] count += 1 img = img * int(self.shutter_speed_ms / BASE_SHUTTER_SPEED_MS) r.publish(messages.NEW_IMAGE_FRAME, redis_helpers.toRedis(img)) max_value = np.max(img) r.publish(messages.STATUS_MAX_PIXEL_VALUE, redis_helpers.toRedis(max_value)) self.thread.stop()
def test_actor(): import matplotlib.pyplot as plt d = Ditherer() d.start() r = redis.StrictRedis(host='localhost', port=6379) xs = [] ys = [] def dither_offset_handler(message): offsets = redis_helpers.fromRedis(message['data']) # print(offsets) xs.append(offsets[1]) ys.append(offsets[0]) p = r.pubsub(ignore_subscribe_messages=True) p.subscribe(**{messages.CMD_SET_DITHERING_POSITION_OFFSET_PIXELS: dither_offset_handler}) thread = p.run_in_thread(sleep_time=0.1) time.sleep(1) r.publish(messages.CMD_SET_DITHERING_MAGNITUDE, redis_helpers.toRedis(1)) r.publish(messages.CMD_SET_DITHERING_INTERVAL, redis_helpers.toRedis(0.01)) time.sleep(30) r.publish(messages.STOP_ALL, "") plt.plot(xs, ys, '--o') plt.grid(True) plt.show()
def image_callback(self, port, buf): #TODO: smoothing of multiple images. if needed? if len(buf.data) > 0: img = np.frombuffer(buf.data, dtype=np.uint8).reshape(1088, 1920, 3) #TODO: average? bw_img = img[:, :, 1] r.publish(messages.NEW_IMAGE_FRAME, redis_helpers.toRedis(bw_img)) max_value = np.max(bw_img) r.publish(messages.STATUS_MAX_PIXEL_VALUE, redis_helpers.toRedis(max_value)) return False
def on_new_position(self): t = Time(datetime.datetime.utcnow(), scale='utc', location=vancouver_location) t.delta_ut1_utc = 0 sidereal_degrees = t.sidereal_time('mean').degree self.relative_ra_degrees = sidereal_degrees - self.ha_relative_degrees absolute_ra_degrees = self.relative_ra_degrees - self.ra_zero_pos_degrees absolute_dec_degrees = self.relative_dec_degrees - self.dec_zero_pos_degrees c = SkyCoord(ra=absolute_ra_degrees, dec=absolute_dec_degrees, frame='icrs', unit='deg') ra_output = '%dh%02dm%.2fs' % (c.ra.hms) dec_output = '%dd%2d%.1fs' % (c.dec.dms) #output_str = '%s/%s' % (ra_output, dec_output) #c = SkyCoord(ra=absolute_ra_degrees, dec=absolute_dec_degrees, frame='icrs', unit='deg') #ra_output = '%dh%02dm%.2fs' % (c.ra.hms) #dec_output = '%dd%2d%.1fs' % (c.dec.dms) #output_str = '%s/%s' % (ra_output, dec_output) #self.r.publish(messages.STATUS_DISPLAY_CURRENT_RA_DEC, redis_helpers.toRedis(output_str)) self.r.publish( messages.STATUS_DISPLAY_CURRENT_RA_DEC, redis_helpers.toRedis((absolute_ra_degrees, absolute_dec_degrees)))
def solve_image_handler(self, msg): print('solve_image_handler') img_path = self.take_picture(exposure_time_seconds = 2) arcsecperpix = (9.3, 9.4) arcsecperpix = (2.0, 2.2) ra, dec = self.solve_image(img_path, arcsecperpix = arcsecperpix) self.r.publish(messages.CMD_SET_ABSOLUTE_CURRENT_POSITION, redis_helpers.toRedis((ra, dec)))
def run(self): self.r = redis.StrictRedis(host='localhost', port=6379) p = self.r.pubsub(ignore_subscribe_messages=True) self.t = 0 self.dithering_magnitude_pixels = 1 self.dithering_interval_seconds = 30 self.dithering_enabled = False self.kill = False p.subscribe(**{messages.STOP_ALL : self.stop_all_handler, messages.CMD_START_GUIDING : self.start_guiding_handler, messages.CMD_SET_DITHERING_MAGNITUDE: self.set_dithering_magnitude_handler, messages.CMD_SET_DITHERING_INTERVAL : self.set_dithering_interval_handler, messages.CMD_START_DITHERING : self.start_dithering_handler, messages.CMD_STOP_DITHERING : self.stop_dithering_handler, messages.STATUS_GET_ALL_STATUS : self.get_status_handler, }) self.thread = p.run_in_thread(sleep_time = 0.1) scale_constant_divider = 5 while not self.kill: if not self.dithering_enabled: time.sleep(0.5) #don't take too long to get started else: self.t += 1 / (self.t + 1) dx = self.t * self.dithering_magnitude_pixels/scale_constant_divider * np.cos(self.t) dy = self.t * self.dithering_magnitude_pixels/scale_constant_divider * np.sin(self.t) dither_vector = np.array([dy, dx]) # print('dither vector: ', dither_vector) self.r.publish(messages.CMD_SET_DITHERING_POSITION_OFFSET_PIXELS, redis_helpers.toRedis(dither_vector)) #at end to reduce race condition when stopping time.sleep(self.dithering_interval_seconds) self.thread.stop()
def goto_position(ra_h, ra_m, ra_s, dec_d, dec_m, dec_s): def pos_to_num(pos_str): if len(pos_str.strip()) > 0: return float(pos_str) else: return 0 ra_h = pos_to_num(ra_h) ra_m = pos_to_num(ra_m) ra_s = pos_to_num(ra_s) dec_d = pos_to_num(dec_d) dec_m = pos_to_num(dec_m) dec_s = pos_to_num(dec_s) coords = SkyCoord(ra=ra_h * u.hour + ra_m * u.minute + ra_s * u.second, dec=dec_d * u.deg + dec_m * u.arcminute + dec_s * u.arcsecond) ra_degrees = coords.ra.deg dec_degrees = coords.dec.deg print('goto_position', ra_h, ra_m, ra_s, dec_d, dec_m, dec_s) r.publish(messages.CMD_GOTO_POSITION, redis_helpers.toRedis((ra_degrees, dec_degrees)))
def set_dithering_magnitude(magnitude): r.publish(messages.CMD_SET_DITHERING_MAGNITUDE, redis_helpers.toRedis(magnitude))
def get_status_handler(self, message): self.r.publish(messages.STATUS_DITHERING_STATUS, redis_helpers.toRedis(self.dithering_enabled))
def stop_dithering_handler(self, message): self.dithering_enabled = False self.r.publish(messages.CMD_SET_DITHERING_POSITION_OFFSET_PIXELS, redis_helpers.toRedis(np.array([0, 0])))
def ra_forward_stop(): r.publish(messages.CMD_SET_SPEED_ADJUSTMENT_RA, redis_helpers.toRedis(0))
def run(self): self.adjustment_factor = 0.0 self.prev_speed_error = 0 self.dspin.connect_l6470() #print('baseline steps per second: ', self.base_steps_per_second) last_position_steps = 0 #position_steps_offset = 0 last_position_steps = self.dspin.dspin_GetPositionSteps() start_time = None while not self.kill: if MotorControl.movement_enabled: new_speed = self.base_steps_per_second * ( self.default_speed + self.adjustment_factor) new_speed_abs = np.abs(new_speed) # print('new_speed: ', new_speed) speed_float = self.dspin.dspin_SpdCalc( new_speed_abs) - self.prev_speed_error # print(speed_float) speed_int = int(np.round(speed_float)) self.prev_speed_error = speed_int - speed_float direction = dspin_l6470.FWD if new_speed > 0 else dspin_l6470.REV # print('speed, dir: ', speed_int, direction) self.dspin.dspin_Run(direction, speed_int) else: self.dspin.dspin_SoftStop() time.sleep(0.5) abs_position_steps = self.dspin.dspin_GetPositionSteps() #if start_time is None: start_time = datetime.now() #else: print(abs_position_steps / (self.base_steps_per_second * (datetime.now() - start_time).total_seconds())) #print(abs_position_steps) position_steps = abs_position_steps - last_position_steps last_position_steps = abs_position_steps #if last_position_steps #print(position_steps) position_total_seconds = position_steps / self.base_steps_per_second position_total_degrees = position_total_seconds * 360 / (24 * 60 * 60) position_seconds = int(position_total_seconds % 60) position_minutes = int((position_total_seconds / 60) % 60) position_hours = int((position_total_seconds / 3600)) #broadcast_position_str = "%2dh%2dm%2ds" % (position_hours, position_minutes, position_seconds) #broadcast_position_str = str(abs_position_steps) #self.r.publish(self.position_broadcast_msg, redis_helpers.toRedis(broadcast_position_str)) #self.r.publish(self.position_broadcast_msg, redis_helpers.toRedis([position_hours, position_minutes, position_seconds])) self.r.publish(self.position_broadcast_msg, redis_helpers.toRedis(position_total_degrees)) self.dspin.disconnect_l6470() self.thread.stop()
def dec_forward_start(speed): r.publish(messages.CMD_SET_SPEED_ADJUSTMENT_DEC, redis_helpers.toRedis(speed))
def ra_forward_start(speed): r.publish(messages.CMD_SET_SPEED_ADJUSTMENT_RA, redis_helpers.toRedis(-speed))
def set_dithering_interval(seconds): r.publish(messages.CMD_SET_DITHERING_INTERVAL, redis_helpers.toRedis(seconds))
def dec_back_stop(): r.publish(messages.CMD_SET_SPEED_ADJUSTMENT_DEC, redis_helpers.toRedis(0))
def get_status_handler(self, message): self.r.publish(messages.STATUS_MOVEMENT_STATUS, redis_helpers.toRedis(MotorControl.movement_enabled))
def new_sub_image_frame_handler(self, message): jpeg_bytes = self.message_to_scaled_jpeg_bytes(message) self.r.publish(messages.NEW_SUB_PREVIEW_FRAME, redis_helpers.toRedis(jpeg_bytes))
def setVisualGain(value): r.publish(messages.CMD_SET_VISUAL_GAIN, redis_helpers.toRedis(int(value)))
def setShutterSpeed(value): r.publish(messages.CMD_SET_SHUTTER_SPEED, redis_helpers.toRedis(int(value)))
def broadcast_current_position(ra, dec): r = redis.StrictRedis(host='10.0.0.110', port=6379) r.publish(messages.CMD_SET_ABSOLUTE_CURRENT_POSITION, redis_helpers.toRedis((ra, dec)))
def run(self): desired_location = None guide_vector = None guide_vector_orthogonal = None orthogonal_distance = None parallel_distance = None update_time = None filtered_adjustment = 0 ema_factor = 0.8 current_state = AdjusterStates.NOT_GUIDING r = redis.StrictRedis(host='localhost', port=6379) p = r.pubsub(ignore_subscribe_messages=True) p.subscribe(messages.CMD_START_GUIDING) p.subscribe(messages.CMD_STOP_GUIDING) p.subscribe(messages.STATUS_CURRENT_TRACKING_POSITION) p.subscribe(messages.CMD_START_TRACKING) p.subscribe(messages.STATUS_STARTING_TRACKING_POSITION) p.subscribe(messages.CMD_SET_DITHERING_POSITION_OFFSET_PIXELS) p.subscribe(messages.STATUS_GET_ALL_STATUS) start_guiding_dir_1_start_time = None start_guiding_dir_1_start_location = None guiding_dir_2_start_time = None guiding_dir_orth_start_time = None failed_track_count = 0 dithering_offset = [0, 0] while not self.kill: message = p.get_message() if message: channel = message['channel'].decode('ASCII') data = message['data'] if channel == messages.CMD_START_TRACKING: #reset things desired_location = None elif channel == messages.CMD_START_GUIDING: print('start guiding received') #desired_location = None #will get grabbed first current_state = AdjusterStates.CMD_START_GUIDING #TODO: publish state? elif channel == messages.CMD_STOP_GUIDING: r.publish( messages.CMD_ENABLE_MOVEMENT, "") #in case this came in during guide vector finding r.publish(messages.CMD_SET_SPEED_ADJUSTMENT_RA, redis_helpers.toRedis(0)) r.publish(messages.STATUS_CURRENT_RAW_ADJUSTMENT, redis_helpers.toRedis(0)) r.publish(messages.CMD_SET_SPEED_ADJUSTMENT_DEC, redis_helpers.toRedis(0)) current_state = AdjusterStates.NOT_GUIDING desired_location = None #publish state? elif channel == messages.STATUS_STARTING_TRACKING_POSITION: desired_location = redis_helpers.fromRedis(data) print('adjuster got new desired location: ', desired_location) elif channel == messages.CMD_SET_DITHERING_POSITION_OFFSET_PIXELS: dithering_offset = redis_helpers.fromRedis(data) # print('new dithering offset: ', dithering_offset) elif channel == messages.STATUS_GET_ALL_STATUS: r.publish( messages.STATUS_GUIDING_STATUS, redis_helpers.toRedis( current_state != AdjusterStates.NOT_GUIDING)) elif channel == messages.STATUS_CURRENT_TRACKING_POSITION: current_position = redis_helpers.fromRedis(data) if desired_location is None: print('trying to track with no desired location?') #desired_location = current_position continue else: shift = current_position - desired_location r.publish(messages.STATUS_DRIFT_X, redis_helpers.toRedis(shift[1])) r.publish(messages.STATUS_DRIFT_Y, redis_helpers.toRedis(shift[0])) if current_state == AdjusterStates.NOT_GUIDING: pass elif current_state == AdjusterStates.CMD_START_GUIDING: #set up to calc guiding vector r.publish(messages.CMD_SET_SPEED_ADJUSTMENT_RA, redis_helpers.toRedis(-1)) #desired_location = current_position #TODO: wait a frame or two? start_guiding_dir_1_start_location = None start_guiding_dir_1_start_time = None current_state = AdjusterStates.START_GUIDING_DIR_1 elif current_state == AdjusterStates.START_GUIDING_DIR_1: #calculate the guiding vector if start_guiding_dir_1_start_location is None: start_guiding_dir_1_start_time = datetime.now() start_guiding_dir_1_start_location = current_position elif ( datetime.now() - start_guiding_dir_1_start_time ).total_seconds() < VECTOR_ESTIMATION_TIME_SECONDS: pass else: #end of guide vector finding in direction 1 start_guiding_dir_1_end_time = datetime.now() start_guiding_dir_1_end_location = current_position guide_vector = np.array((start_guiding_dir_1_end_location[0] - start_guiding_dir_1_start_location[0], start_guiding_dir_1_end_location[1] - start_guiding_dir_1_start_location[1])) / \ (start_guiding_dir_1_end_time - start_guiding_dir_1_start_time).total_seconds() print('guide vector: ', guide_vector) r.publish(messages.STATUS_GUIDE_VECTOR_RA, redis_helpers.toRedis(guide_vector)) #now speed forwards to get back to original position # r.publish(messages.CMD_ENABLE_MOVEMENT, "") r.publish(messages.CMD_SET_SPEED_ADJUSTMENT_RA, redis_helpers.toRedis(1.0)) current_state = AdjusterStates.START_GUIDING_DIR_2 elif current_state == AdjusterStates.START_GUIDING_DIR_2: #return to starting point, get off-axis vector if guiding_dir_2_start_time is None: guiding_dir_2_start_time = datetime.now() else: distance_along_guide = np.dot( shift, guide_vector) / ( np.linalg.norm(guide_vector)**2) print('guide state 2, distance along guide: ', distance_along_guide) if distance_along_guide > 0: #still getting back to the start pass else: # elapsed_time_seconds = (datetime.now() - guiding_dir_2_start_time).total_seconds() calibration_time_seconds = ( datetime.now() - start_guiding_dir_1_start_time ).total_seconds() shift = current_position - desired_location orthogonal_distance_entire_calibration_pixels = np.dot( shift, [-guide_vector[1], guide_vector[0]]) calibration_process_orthogonal_drift = orthogonal_distance_entire_calibration_pixels * GUIDE_CAM_ARC_SECONDS_PER_PIXEL / calibration_time_seconds # orthogonal_vector = (shift - distance_along_guide * guide_vector) / elapsed_time_seconds # print('orthogonal vector: ', orthogonal_vector) # #convert pixels/second to arc-seconds/s or something # orthogonal_distance = np.linalg.norm(orthogonal_vector) r.publish( messages. STATUS_CALIBRATION_DRIFT_ARC_SECONDS, redis_helpers.toRedis( calibration_process_orthogonal_drift)) r.publish(messages.CMD_SET_SPEED_ADJUSTMENT_RA, redis_helpers.toRedis(0.)) filtered_adjustment = 0 #reset current_state = AdjusterStates.START_GUIDING_DIR_ORTH_1 guiding_dir_orth_start_time = None print('guiding...') elif current_state in [ AdjusterStates.START_GUIDING_DIR_ORTH_1, AdjusterStates.START_GUIDING_DIR_ORTH_2, AdjusterStates.GUIDING ]: if current_position is None: failed_track_count += 1 if failed_track_count > 20: print( 'failed tracking too many times, trying to restart...?' ) # r.publish(messages.CMD_START_TRACKING, "") # r.publish(messages.CMD_STOP_GUIDING) # r.publish(messages.CMD_START_GUIDING) current_state = AdjusterStates.NOT_GUIDING filtered_adjustment_ra = 0 raw_adjustment_ra = 0 parallel_distance = 0 orthogonal_distance = 0 filtered_adjustment_dec = 0 raw_adjustment_dec = 0 r.publish( messages.STATUS_FAILED_TRACKING_COUNT, redis_helpers.toRedis(failed_track_count)) else: failed_track_count = 0 r.publish( messages.STATUS_FAILED_TRACKING_COUNT, redis_helpers.toRedis(failed_track_count)) #do parallel guiding in all states. only dither once we're up and running if current_state == AdjusterStates.GUIDING: shift = current_position - (desired_location + dithering_offset) else: shift = current_position - desired_location # print('shift: ', shift) parallel_distance = np.dot(shift, guide_vector) / ( np.linalg.norm(guide_vector)**2) if guide_vector_orthogonal is None: orthogonal_distance = 0 else: orthogonal_distance = np.dot( shift, guide_vector_orthogonal) / ( np.linalg.norm(guide_vector_orthogonal) **2) raw_adjustment_ra = parallel_distance / ADJUSTMENT_TARGET_SECONDS clipped_adjustment = np.clip( raw_adjustment_ra, -MAX_ADJUSTMENT, MAX_ADJUSTMENT) filtered_adjustment = filtered_adjustment * ema_factor + clipped_adjustment * ( 1 - ema_factor) filtered_adjustment_ra = filtered_adjustment if current_state == AdjusterStates.START_GUIDING_DIR_ORTH_1: if guiding_dir_orth_start_time is None: print('starting guiding for orthogonal') guiding_dir_orth_start_time = datetime.now( ) guiding_dir_orth_start_location = current_position filtered_adjustment_dec = -1 raw_adjustment_dec = -1 else: elapsed_time_seconds = ( datetime.now() - guiding_dir_orth_start_time ).total_seconds() print( 'orth guide vector estimating time: ', elapsed_time_seconds) if elapsed_time_seconds >= VECTOR_ESTIMATION_TIME_SECONDS: distance_along_guide = np.dot( shift, guide_vector) / ( np.linalg.norm(guide_vector)** 2) orthogonal_vector = shift - distance_along_guide * guide_vector guide_vector_orthogonal = orthogonal_vector / elapsed_time_seconds print('guide vector orthogonal: ', guide_vector_orthogonal) print( 'angle between vectors: ', angle_between_vectors( guide_vector, guide_vector_orthogonal)) r.publish( messages.STATUS_GUIDE_VECTOR_DEC, redis_helpers.toRedis( guide_vector_orthogonal)) current_state = AdjusterStates.GUIDING filtered_adjustment_dec = 1 #start speeding back towards origin raw_adjustment_dec = 1 elif current_state == AdjusterStates.START_GUIDING_DIR_ORTH_2: print('dir_orth_2, orth distance = ', orthogonal_distance) if orthogonal_distance < 0: print('back to origin, moving to guiding') filtered_adjustment_dec = 0 raw_adjustment_dec = 0 current_state = AdjusterStates.GUIDING #TODO: back to original position elif current_state == AdjusterStates.GUIDING: orthogonal_vector = shift - parallel_distance * guide_vector #TODO: filter realllll slow instead of just making it slow raw_adjustment_dec = orthogonal_distance / ORTHOGONAL_ADJUSTMENT_TARGET_SECONDS filtered_adjustment_dec = np.clip( raw_adjustment_dec, -MAX_ADJUSTMENT, MAX_ADJUSTMENT) r.publish( messages.CMD_SET_SPEED_ADJUSTMENT_RA, redis_helpers.toRedis(filtered_adjustment_ra)) r.publish(messages.STATUS_CURRENT_RAW_ADJUSTMENT, redis_helpers.toRedis(raw_adjustment_ra)) r.publish(messages.STATUS_PARALLEL_ERROR, redis_helpers.toRedis(parallel_distance)) r.publish(messages.STATUS_ORTHOGONAL_ERROR, redis_helpers.toRedis(orthogonal_distance)) r.publish( messages.CMD_SET_SPEED_ADJUSTMENT_DEC, redis_helpers.toRedis(filtered_adjustment_dec)) guiding_status = { 'drift_x': str(shift[1]), 'drift_y': str(shift[0]), 'parallel_error': str(parallel_distance), 'orthogonal_error': str(orthogonal_distance), 'raw_adjustment_ra': str(raw_adjustment_ra), 'filtered_adjustment_ra': str(filtered_adjustment_ra), 'raw_adjustment_dec': str(raw_adjustment_dec), 'filtered_adjustment_dec': str(filtered_adjustment_dec) } r.publish(messages.STATUS_GUIDING_STATUS, redis_helpers.toRedis(guiding_status)) else: print('unknown state: ', current_state)
gear_ratio = 128. steps_per_rotation = 400. base_steps_per_second = steps_per_rotation * gear_ratio / seconds_per_rotation mc_ra = MotorControl( bus=0, cs_pin=0, slave_pin=25, reset_pin=3, speed_adjustment_msg=messages.CMD_SET_SPEED_ADJUSTMENT_RA, base_steps_per_second=base_steps_per_second, default_speed=1, position_broadcast_msg=None) mc_ra.start() print('after MotorControl()') time.sleep(3) r.publish(messages.CMD_SET_SPEED_ADJUSTMENT_RA, redis_helpers.toRedis(1.2)) time.sleep(3) r.publish(messages.CMD_DISABLE_MOVEMENT, "") time.sleep(3) r.publish(messages.CMD_ENABLE_MOVEMENT, "") time.sleep(3) r.publish(messages.STOP_ALL, "")