Skip to content

Commit

Permalink
Merge pull request #7 from brickbots/beta
Browse files Browse the repository at this point in the history
Beta
  • Loading branch information
brickbots authored Mar 21, 2023
2 parents 1605d8d + 3dba80f commit 1255d3c
Show file tree
Hide file tree
Showing 11 changed files with 204 additions and 50 deletions.
2 changes: 2 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
},
"camera_exp": 750000,
"camera_gain": 20,
"screen_direction": "right",
"solver_debug": 0,
"catalogs": [
"NGC",
"IC",
Expand Down
63 changes: 50 additions & 13 deletions python/PiFinder/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
"""
import os
import queue
import pprint
import time

from PIL import Image, ImageDraw, ImageFont, ImageChops
Expand All @@ -21,24 +20,39 @@
RED = (0, 0, 255)


def set_camera_defaults(camera, cfg):
exposure_time = None
analog_gain = None


def set_camera_defaults(camera):
# Initialize camera, defaults :
# gain: 10
# exposure: 1.5m
exposure_time = cfg.get_option("camera_exp")
analog_gain = cfg.get_option("camera_gain")
global exposure_time, analog_gain
camera.stop()
cam_config = camera.create_still_configuration(main={"size": (512, 512)})

# using this smaller scale auto-selects binning on the sensor...
cam_config = camera.create_still_configuration({"size": (512, 512)})
camera.configure(cam_config)
camera.set_controls({"AeEnable": False})
camera.set_controls({"AnalogueGain": analog_gain})
camera.set_controls({"ExposureTime": exposure_time})
camera.start()


def set_camera_highres(camera, cfg):
exposure_time = cfg.get_option("camera_exp")
analog_gain = cfg.get_option("camera_gain")
def set_camera_config(camera):
# Initialize camera, defaults :
# gain: 10
# exposure: 1.5m
global exposure_time, analog_gain
camera.stop()
camera.set_controls({"AnalogueGain": analog_gain})
camera.set_controls({"ExposureTime": exposure_time})
camera.start()


def set_camera_highres(camera):
global exposure_time, analog_gain
camera.stop()
cam_config = camera.create_still_configuration()
camera.configure(cam_config)
Expand All @@ -49,12 +63,23 @@ def set_camera_highres(camera, cfg):


def get_images(shared_state, camera_image, command_queue, console_queue):
global exposure_time, analog_gain
debug = False
camera = Picamera2()

# Figure out camera type, hq or gs (global shutter)
camera_type = 'hq'
gain_mult = 1
sensor_modes = camera.sensor_modes
if len(sensor_modes) == 1:
gain_mult = 3
camera_type='gs'

cfg = config.Config()
exposure_time = cfg.get_option("camera_exp")
set_camera_defaults(camera, cfg)
# pprint.pprint(camera.camera_controls)
analog_gain = cfg.get_option("camera_gain") * gain_mult
screen_direction = cfg.get_option("screen_direction")
set_camera_defaults(camera)

red_image = Image.new("RGB", (128, 128), (0, 0, 255))

Expand All @@ -71,7 +96,8 @@ def get_images(shared_state, camera_image, command_queue, console_queue):
if not debug:
base_image = camera.capture_image("main")
base_image = base_image.convert("L")
base_image = base_image.rotate(90)
if screen_direction == "right":
base_image = base_image.rotate(90)
else:
# load image and wait
base_image = Image.open(test_image_path)
Expand All @@ -92,6 +118,16 @@ def get_images(shared_state, camera_image, command_queue, console_queue):
else:
debug = True

if command.startswith("set_exp"):
exposure_time = int(command.split(":")[1])
set_camera_config(camera)
console_queue.put("CAM: Exp=" + str(exposure_time))

if command.startswith("set_gain"):
analog_gain = int(command.split(":")[1]) * gain_mult
set_camera_config(camera)
console_queue.put("CAM: Gain=" + str(analog_gain))

if command == "exp_up" or command == "exp_dn":
if command == "exp_up":
exposure_time = int(exposure_time * 1.25)
Expand All @@ -102,6 +138,7 @@ def get_images(shared_state, camera_image, command_queue, console_queue):
if command == "exp_save":
console_queue.put("CAM: Exp Saved")
cfg.set_option("camera_exp", exposure_time)
cfg.set_option("camera_gain", int(analog_gain/gain_mult))

if command.startswith("save"):
filename = command.split(":")[1]
Expand All @@ -113,7 +150,7 @@ def get_images(shared_state, camera_image, command_queue, console_queue):
# Save high res image....
filename = command.split(":")[1]
filename = f"/home/pifinder/PiFinder_data/captures/{filename}.png"
set_camera_highres(camera, cfg)
set_camera_highres(camera)
camera.capture_file(filename)
console_queue.put("CAM: Saved Hi Image")
set_camera_defaults(camera, cfg)
set_camera_defaults(camera)
48 changes: 28 additions & 20 deletions python/PiFinder/imu.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,17 @@

from scipy.spatial.transform import Rotation

QUEUE_LEN = 5
QUEUE_LEN = 50
AVG_LEN = 2
MOVE_CHECK_LEN = 10


class Imu:
def __init__(self):
i2c = board.I2C()
self.sensor = adafruit_bno055.BNO055_I2C(i2c)
self.sensor.mode = adafruit_bno055.IMUPLUS_MODE
# self.sensor.mode = adafruit_bno055.IMUPLUS_MODE
self.sensor.mode = adafruit_bno055.NDOF_MODE
self.sensor.axis_remap = (
adafruit_bno055.AXIS_REMAP_Z,
adafruit_bno055.AXIS_REMAP_Y,
Expand Down Expand Up @@ -50,20 +53,23 @@ def moving(self):
with past readings
"""
diff_list = []
# compare last 4 quats
for quat in self.quat_history[-4:]:
# compare last MOVE_CHECK_LEN quats
for quat in self.quat_history[-MOVE_CHECK_LEN:]:
diff = (
abs(quat[0] - self.quat_history[0][0])
+ abs(quat[1] - self.quat_history[0][1])
+ abs(quat[2] - self.quat_history[0][2])
+ abs(quat[3] - self.quat_history[0][3])
abs(quat[0] - self.quat_history[-MOVE_CHECK_LEN][0])
+ abs(quat[1] - self.quat_history[-MOVE_CHECK_LEN][1])
+ abs(quat[2] - self.quat_history[-MOVE_CHECK_LEN][2])
+ abs(quat[3] - self.quat_history[-MOVE_CHECK_LEN][3])
)
diff_list.append(diff)

if diff_list[0] < diff_list[1] < diff_list[2] < diff_list[3]:
self.__moving = True
else:
self.__moving = False
self.__moving = True
last_diff = diff_list[0]
for diff in diff_list[1:]:
if diff <= last_diff:
self.__moving = False
last_diff = diff

return self.__moving

def flip(self, quat):
Expand Down Expand Up @@ -100,28 +106,28 @@ def update(self):
print("IMU: Failed to get sensor values")
return

# update moving
if not self.flip(quat):

# add to averages
if len(self.quat_history) == QUEUE_LEN:
self.quat_history = self.quat_history[1:]
self.quat_history.append(quat)
self.calc_avg_quat()

def calc_avg_quat(self):
quat = [0, 0, 0, 0]
for q in self.quat_history:
if not self.__moving:
self.avg_quat = self.quat_history[-1]

for q in self.quat_history[-AVG_LEN:]:
quat[0] += q[0]
quat[1] += q[1]
quat[2] += q[2]
quat[3] += q[3]

self.avg_quat = (
quat[0] / QUEUE_LEN,
quat[1] / QUEUE_LEN,
quat[2] / QUEUE_LEN,
quat[3] / QUEUE_LEN,
quat[0] / AVG_LEN,
quat[1] / AVG_LEN,
quat[2] / AVG_LEN,
quat[3] / AVG_LEN,
)

def get_euler(self):
Expand Down Expand Up @@ -156,10 +162,12 @@ def imu_monitor(shared_state, console_queue):
imu_data["moving"] = False
imu_data["pos"] = imu.get_euler()
imu_data["move_end"] = time.time()

if imu_calibrated == False:
if imu_data["status"] == 3:
imu_calibrated = True
console_queue.put("IMU: NDOF Calibrated!")

if shared_state != None and imu_calibrated:
shared_state.set_imu(imu_data)
# pprint(imu_data)
22 changes: 19 additions & 3 deletions python/PiFinder/solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
)

from PiFinder.image_util import subtract_background
from PiFinder import config

IMU_ALT = 2
IMU_AZ = 0
Expand Down Expand Up @@ -108,6 +109,7 @@ def write_debug(
Writes the image + key solver
info to disk
"""
st = time.time()
root_dir = "/home/pifinder/PiFinder_data"
debug_path = os.path.join(root_dir, "solver_debug_dumps", prefix)

Expand All @@ -134,6 +136,7 @@ def write_debug(
json.dump(dt.isoformat(), f, indent=4)

console_queue.put(f"SLV: Debug {prefix}")
console_queue.put(f"\t {time.time() - st: 0.2}")


def solver(shared_state, camera_image, console_queue):
Expand All @@ -157,6 +160,12 @@ def solver(shared_state, camera_image, console_queue):
"constellation": None,
"last_image_solve": None,
}
cfg = config.Config()
solver_debug = cfg.get_option("solver_debug")
if cfg.get_option("screen_direction") == "left":
left_handed = True
else:
left_handed = False

# This holds the last image solve position info
# so we can delta for IMU updates
Expand All @@ -174,7 +183,11 @@ def solver(shared_state, camera_image, console_queue):
fov_estimate=10.2,
fov_max_error=0.1,
)
if new_solve["RA"] != None and solved["solve_source"] == "IMU":
if (
solver_debug
and new_solve["RA"] != None
and solved["solve_source"] == "IMU"
):
# we were on IMU, now we are back
# to image solve. Check if we have really moved...
if (
Expand Down Expand Up @@ -244,7 +257,7 @@ def solver(shared_state, camera_image, console_queue):
if solved["Alt"]:
imu = shared_state.imu()
if imu:
if imu["moving"]: # or imu_moving == True:
if imu["moving"] or imu_moving == True:
# we track imu_moving so that we do
# this one more time after we stop moving
imu_moving = imu["moving"]
Expand All @@ -259,7 +272,10 @@ def solver(shared_state, camera_image, console_queue):
imu_pos = imu["pos"]
if lis_imu != None and imu_pos != None:
alt_offset = imu_pos[IMU_ALT] - lis_imu[IMU_ALT]
alt_offset = (alt_offset + 180) % 360 - 180
if left_handed:
alt_offset = ((alt_offset + 180) % 360 - 180) * -1
else:
alt_offset = (alt_offset + 180) % 360 - 180
alt_upd = (last_image_solve["Alt"] - alt_offset) % 360

az_offset = imu_pos[IMU_AZ] - lis_imu[IMU_AZ]
Expand Down
7 changes: 7 additions & 0 deletions python/PiFinder/ui/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ def __init__(
self.ui_state = ui_state
self.config_object = config_object

def exit_config(self, option):
"""
Handy callback for exiting
config on option select
"""
return True

def update_config(self):
"""
callback when config is updated
Expand Down
9 changes: 5 additions & 4 deletions python/PiFinder/ui/chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,11 @@ def plot_obs_list(self):
return

marker_list = []
for obs_target in self.ui_state.get("observing_list", []):
if target == None or (
obs_target["designation"] != target["designation"]
and obs_target["catalog"] != target["catalog"]
for obs_target in self.ui_state["observing_list"]:
if (
target == None
or obs_target["designation"] != target["designation"]
or obs_target["catalog"] != target["catalog"]
):
marker = OBJ_TYPE_MARKERS.get(obs_target["obj_type"])
if marker:
Expand Down
15 changes: 10 additions & 5 deletions python/PiFinder/ui/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,6 @@ def key_number(self, number):

# Now that we have set config, see if there is a callback
if selected_item.get("callback") != None:
print("{self.__module =}")
callback_method = getattr(self.__module, selected_item["callback"])
exit_config = callback_method(selected_item["value"])
if exit_config:
Expand All @@ -187,16 +186,22 @@ def key_number(self, number):
if number >= len(self.__item_names):
return
self.__selected_item = self.__item_names[number]
if self.__config[self.__selected_item]["type"] == "bool":
if self.__config[self.__selected_item]["value"] == "On":
self.__config[self.__selected_item]["value"] = "Off"
selected_item = self.__config[self.__selected_item]
if selected_item["type"] == "bool":
if selected_item["value"] == "On":
selected_item["value"] = "Off"
else:
self.__config[self.__selected_item]["value"] = "On"
selected_item["value"] = "On"
self.update()
# sleep for a sec to give the user time to see the change
time.sleep(1)
# okay, reset and release
self.__selected_item = None
if selected_item.get("callback") != None:
callback_method = getattr(self.__module, selected_item["callback"])
exit_config = callback_method(selected_item["value"])
if exit_config:
self.switch_to = self.__module.__class__.__name__

def active(self):
self.__selected_item = None
Expand Down
6 changes: 3 additions & 3 deletions python/PiFinder/ui/locate.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,10 @@ def update(self, force=False):

# Target history index
if self.target_index != None:
if self.ui_state['active_list'] == self.ui_state['history_list']:
list_name = 'Hist'
if self.ui_state["active_list"] == self.ui_state["history_list"]:
list_name = "Hist"
else:
list_name = 'Obsv'
list_name = "Obsv"
line = f"{self.target_index + 1}/{len(self.ui_state['active_list'])}"
line = f"{line : >9}"
self.draw.text((72, 18), line, font=self.font_base, fill=RED)
Expand Down
Loading

0 comments on commit 1255d3c

Please sign in to comment.