Skip to content

Commit

Permalink
Update Cedar Detect / Solve and Solidify Align (#256)
Browse files Browse the repository at this point in the history
* Starting cedar update, align code changed

* Cedar detect update

* Cedar detect update - RPI version

* Switching to selective migrations

* Add submodule migration

* switch check for files

* working on conditionals

* Recompile on rpi4

* Use cedar-solve 0.5.1

* Remove debug prints

* Working on mypy failure

* Update to proper tetra3

* Update for mypy

* Maybe working now?

* Remove symlink

* Update tetra3 version

* Simplify tetra3 update

* Simplify tetra3 update

* Ignore imu on alignment screen, adjust menu, clean up debug

* Fix reticle position after alignment
  • Loading branch information
brickbots authored Dec 21, 2024
1 parent a75e413 commit baebe38
Show file tree
Hide file tree
Showing 13 changed files with 128 additions and 138 deletions.
3 changes: 1 addition & 2 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
[submodule "python/PiFinder/tetra3"]
path = python/PiFinder/tetra3
url = https://github.com/esa/tetra3.git
branch = no_big_files
url = https://github.com/smroid/cedar-solve
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ A plate solving telescope finder based around a Raspberry PI, imx296 camera, and

For an overview of what the PiFinder™ is and how it came to be visit the official project website at [PiFinder.io](https://www.pifinder.io/build-yours)

The PiFinder™ uses the [Ceder Detect](https://github.com/smroid/cedar-detect) and
[Cedar Solve](https://github.com/smroid/cedar-solve) libraries with express permission.
Thank you to [smroid] for all your support of the PiFinder project!

![Banner](./docs/source/images/PiFinder_v3_banner.png)
The PiFinder™ is my attempt to improve my time at my telescope. I don't get nearly enough of it and I want to enjoy it as much as possible. So after years of observing with paper charts and, later, a Nexus DSC here is what I felt I was missing:
* **Reliable telescope positioning:** The Nexus DSC is great, but my scope just isn't built for solid encoder integration. The slop in the way I have to couple the encoders means poor pointing accuracy.
Expand Down Expand Up @@ -45,4 +49,3 @@ If you'd like to learn more about how it works, and potentially build your own,
## Discord
Join the [PiFinder™ Discord server](https://discord.gg/Nk5fHcAtWD) for support with your build, usage questions, and suggestions for improvement.

<a href='https://ko-fi.com/brickbots' target='_blank'><img height='35' style='border:0px;height:46px;' src='https://az743702.vo.msecnd.net/cdn/kofi3.png?v=0' border='0' alt='Buy Me a Coffee at ko-fi.com' />
Binary file modified bin/cedar-detect-server-aarch64
Binary file not shown.
Binary file modified bin/cedar-detect-server-arm64
Binary file not shown.
48 changes: 48 additions & 0 deletions migration_source/v1.x.x.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# GPSD
sudo apt install -y gpsd
sudo dpkg-reconfigure -plow gpsd
sudo cp ~/PiFinder/pi_config_files/gpsd.conf /etc/default/gpsd

# PWM
sudo sed -zi '/dtoverlay=pwm,pin=13,func=4\n/!s/$/\ndtoverlay=pwm,pin=13,func=4\n/' /boot/config.txt

# Uart for GPS
sudo sed -zi '/dtoverlay=uart3\n/!s/$/\ndtoverlay=uart3\n/' /boot/config.txt

# Migrate DB
if [ -f "/home/pifinder/PiFinder/astro_data/observations.db" ]
then
echo "Migrating astro_data DB"
python -c "from PiFinder import setup;setup.create_logging_tables();"
sqlite3 < /home/pifinder/PiFinder/migrate_db.sql
rm /home/pifinder/PiFinder/astro_data/observations.db
fi

# Migrate Config files
if ! [ -f "/home/pifinder/PiFinder_data/config.json" ]
then
echo "Migrating config.json"
mv /home/pifinder/PiFinder/config.json /home/pifinder/PiFinder_data/config.json
fi

# Adjust service definition
sudo systemctl disable pifinder
sudo rm /etc/systemd/system/pifinder.service
sudo cp /home/pifinder/PiFinder/pi_config_files/pifinder.service /lib/systemd/system/pifinder.service
sudo systemctl daemon-reload
sudo systemctl enable pifinder

# add PiFinder_splash if not already in place
if ! [ -f "/lib/systemd/system/pifinder_spash.service" ]
then
sudo cp /home/pifinder/PiFinder/pi_config_files/pifinder_splash.service /lib/systemd/system/pifinder_splash.service
sudo systemctl daemon-reload
sudo systemctl enable pifinder_splash
fi

# open permissisons on wpa_supplicant file so we can adjust network config
sudo chmod 666 /etc/wpa_supplicant/wpa_supplicant.conf

# DONE
echo "Post Update Complete"

7 changes: 7 additions & 0 deletions migration_source/v2.1.0.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# swap tetra3 submodule
git submodule sync
git submodule update --init --recursive

# Set up symlink
ln -s /home/pifinder/PiFinder/python/PiFinder/tetra3/tetra3 /home/pifinder/PiFinder/python/tetra3

49 changes: 13 additions & 36 deletions pifinder_post_update.sh
Original file line number Diff line number Diff line change
@@ -1,51 +1,28 @@
git submodule update --init --recursive
sudo pip install -r /home/pifinder/PiFinder/python/requirements.txt

# GPSD
sudo apt install -y gpsd
sudo dpkg-reconfigure -plow gpsd
sudo cp ~/PiFinder/pi_config_files/gpsd.conf /etc/default/gpsd

# PWM
sudo sed -zi '/dtoverlay=pwm,pin=13,func=4\n/!s/$/\ndtoverlay=pwm,pin=13,func=4\n/' /boot/config.txt

# Uart for GPS
sudo sed -zi '/dtoverlay=uart3\n/!s/$/\ndtoverlay=uart3\n/' /boot/config.txt

# Migrate DB
if [ -f "/home/pifinder/PiFinder/astro_data/observations.db" ]
# Set up migrations folder if it does not exist
if ! [ -d "/home/pifinder/PiFinder_data/migrations" ]
then
echo "Migrating astro_data DB"
python -c "from PiFinder import setup;setup.create_logging_tables();"
sqlite3 < /home/pifinder/PiFinder/migrate_db.sql
rm /home/pifinder/PiFinder/astro_data/observations.db
mkdir /home/pifinder/PiFinder_data/migrations
fi

# Migrate Config files
if ! [ -f "/home/pifinder/PiFinder_data/config.json" ]
# v1.x.x
# everying prior to selecitve migrations
if ! [ -f "/home/pifinder/PiFinder_data/migrations/v1.x.x" ]
then
echo "Migrating config.json"
mv /home/pifinder/PiFinder/config.json /home/pifinder/PiFinder_data/config.json
source /home/pifinder/PiFinder/migration_source/v1.x.x.sh
touch /home/pifinder/PiFinder_data/migrations/v1.x.x
fi

# Adjust service definition
sudo systemctl disable pifinder
sudo rm /etc/systemd/system/pifinder.service
sudo cp /home/pifinder/PiFinder/pi_config_files/pifinder.service /lib/systemd/system/pifinder.service
sudo systemctl daemon-reload
sudo systemctl enable pifinder

# add PiFinder_splash if not already in place
if ! [ -f "/lib/systemd/system/pifinder_spash.service" ]
# v2.1.0
# Switch to Cedar
if ! [ -f "/home/pifinder/PiFinder_data/migrations/v2.1.0" ]
then
sudo cp /home/pifinder/PiFinder/pi_config_files/pifinder_splash.service /lib/systemd/system/pifinder_splash.service
sudo systemctl daemon-reload
sudo systemctl enable pifinder_splash
source /home/pifinder/PiFinder/migration_source/v2.1.0.sh
touch /home/pifinder/PiFinder_data/migrations/v2.1.0
fi

# open permissisons on wpa_supplicant file so we can adjust network config
sudo chmod 666 /etc/wpa_supplicant/wpa_supplicant.conf

# DONE
echo "Post Update Complete"

99 changes: 28 additions & 71 deletions python/PiFinder/solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,71 +20,12 @@
from PiFinder import utils

sys.path.append(str(utils.tetra3_dir))
import PiFinder.tetra3.tetra3 as tetra3
from PiFinder.tetra3.tetra3 import cedar_detect_client
import tetra3
from tetra3 import cedar_detect_client

logger = logging.getLogger("Solver")


def find_target_pixel(t3, fov_estimate, centroids, ra, dec):
"""
Searches the most recent solve for a pixel
that matches the requested RA/DEC the best
"""
print(f"{len(centroids)=}")
search_center = (256, 256)
search_distance = 128
while search_distance >= 1:
# try 5 search points
search_points = [
[search_center[0] - search_distance, search_center[1] - search_distance],
[search_center[0] - search_distance, search_center[1] + search_distance],
[search_center[0] + search_distance, search_center[1] - search_distance],
[search_center[0] + search_distance, search_center[1] + search_distance],
[search_center[0], search_center[1]],
]

# probe points
min_dist = 100000
for search_point in search_points:
solve_fails = 0
point_sol = {}
while point_sol.get("RA_target") is None:
solve_fails += 1
if solve_fails > 10:
print("Too many fails")
return (-1, -1)
try:
point_sol = t3.solve_from_centroids(
centroids,
(512, 512),
fov_estimate=fov_estimate,
fov_max_error=0.2,
return_matches=False,
target_pixel=[search_point[0], search_point[1]],
solve_timeout=1000,
)
except Exception:
return (-1, -1)

# distance...
p_dist = np.hypot(
point_sol["RA_target"] - ra, point_sol["Dec_target"] - dec
)
if p_dist < min_dist:
search_center = search_point
min_dist = p_dist

# cut search distance
search_distance = search_distance / 2

# Done?
if min_dist > 0.1:
# Didn't find a good pixel...
return (-1, -1)
return search_center


def solver(
shared_state,
solver_queue,
Expand All @@ -101,6 +42,8 @@ def solver(
str(utils.cwd_dir / "PiFinder/tetra3/tetra3/data/default_database.npz")
)
last_solve_time = 0
align_ra = 0
align_dec = 0
solved = {
# RA, Dec, Roll solved at the center of the camera FoV:
"RA_camera": None,
Expand Down Expand Up @@ -150,15 +93,10 @@ def solver(
# for this RA/DEC and set it as alignment pixel
align_ra = command[1]
align_dec = command[2]
align_target_pixel = find_target_pixel(
t3=t3,
fov_estimate=solved["FOV"],
centroids=centroids,
ra=align_ra,
dec=align_dec,
)
logger.debug(f"Align {align_target_pixel=}")
align_result_queue.put(["aligned", align_target_pixel])

if command[0] == "align_cancel":
align_ra = 0
align_dec = 0

state_utils.sleep_for_framerate(shared_state)

Expand Down Expand Up @@ -192,15 +130,20 @@ def solver(
logger.warn("No stars found, skipping")
continue
else:
_solver_args = {}
if align_ra != 0 and align_dec != 0:
_solver_args["target_sky_coord"] = [[align_ra, align_dec]]

solution = t3.solve_from_centroids(
centroids,
(512, 512),
fov_estimate=12.0,
fov_max_error=4.0,
match_max_error=0.005,
return_matches=True,
# return_matches=True,
target_pixel=shared_state.solve_pixel(),
solve_timeout=1000,
**_solver_args,
)

if "matched_centroids" in solution:
Expand Down Expand Up @@ -238,6 +181,20 @@ def solver(
solved["cam_solve_time"] = solved["solve_time"]
solver_queue.put(solved)

# See if we are waiting for alignment
if align_ra != 0 and align_dec != 0:
if solved.get("x_target") is not None:
align_target_pixel = (
solved["y_target"],
solved["x_target"],
)
logger.debug(f"Align {align_target_pixel=}")
align_result_queue.put(["aligned", align_target_pixel])
align_ra = 0
align_dec = 0
solved["x_target"] = None
solved["y_target"] = None

last_solve_time = last_image_metadata["exposure_end"]
except EOFError:
logger.error("Main no longer running for solver")
Expand Down
2 changes: 1 addition & 1 deletion python/PiFinder/tetra3
36 changes: 24 additions & 12 deletions python/PiFinder/ui/align.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ def align_on_radec(ra, dec, command_queues, config_object, shared_state) -> bool
* Set the config item and the shared state
* return the pixel or -1/-1 for error
"""

# Clear out any pending responses
while True:
try:
command = command_queues["align_response"].get(block=False)
except queue.Empty:
break

# Send command to solver to work out the camera pixel for this target
command_queues["align_command"].put(
[
Expand All @@ -36,8 +44,16 @@ def align_on_radec(ra, dec, command_queues, config_object, shared_state) -> bool
received_response = False
start_time = time.time()
while not received_response:
# only wait a second
if time.time() - start_time > 1:
# only wait two seconds
if time.time() - start_time > 2:
command_queues["align_command"].put(
[
"align_cancel",
ra,
dec,
]
)
command_queues["console"].put("Align Timeout")
return False

try:
Expand All @@ -55,6 +71,7 @@ def align_on_radec(ra, dec, command_queues, config_object, shared_state) -> bool
return False

# success, set all the things...
command_queues["console"].put("Alignment Set")
shared_state.set_solve_pixel(target_pixel)
config_object.set_option("solve_pixel", target_pixel)
return True
Expand All @@ -81,17 +98,14 @@ def __init__(self, *args, **kwargs):
self.star_list = np.empty((0, 2))
self.alignment_star = None
self.reticle_position = (
self.config_object.get_option("solve_pixel", (256, 256))[0] / 4,
self.config_object.get_option("solve_pixel", (256, 256))[1] / 4,
self.config_object.get_option("solve_pixel", (256, 256))[0] / 4,
)

# Marking menu definition
self.marking_menu = MarkingMenu(
left=MarkingMenuOption(),
down=MarkingMenuOption(
label="Options",
menu_jump="chart_settings",
),
down=MarkingMenuOption(),
right=MarkingMenuOption(),
)

Expand All @@ -104,7 +118,7 @@ def draw_reticle(self):

if not self.align_mode:
self.reticle_position = self.starfield.radec_to_xy(
self.solution["RA"], self.solution["Dec"]
self.solution["RA_target"], self.solution["Dec_target"]
)

x_pos = round(self.reticle_position[0])
Expand Down Expand Up @@ -163,9 +177,7 @@ def update(self, force=False):

if self.shared_state.solve_state():
self.animate_fov()
constellation_brightness = self.config_object.get_option(
"chart_constellations", 64
)
constellation_brightness = 64
self.solution = self.shared_state.solution()
last_solve_time = self.solution["solve_time"]
if (
Expand All @@ -190,7 +202,7 @@ def update(self, force=False):
self.screen.paste(image_obj)

self.last_update = last_solve_time
self.draw_reticle()
self.draw_reticle()

else:
self.draw.rectangle(
Expand Down
Loading

0 comments on commit baebe38

Please sign in to comment.