Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
312 commits
Select commit Hold shift + click to select a range
9a10120
Rename func
Jul 5, 2025
8ab3613
Add new class ImuDeadReckoning
Jul 5, 2025
8143282
Update ImuDeadReckoning() class
Jul 5, 2025
6d25aa4
Remove unused dictionary entry (now using the new ImuDeadReckoning() …
Jul 5, 2025
42b5943
Update integrator.py to use ImuDeadReckoning()
Jul 5, 2025
7a181b8
Debug on PiFinder in test mode --> The charts move up/down and left/r…
Jul 5, 2025
01b7304
Remove cached astro_data/comets.txt
Jul 5, 2025
4efc862
Fix .gitignore to ignore astro_data/comets.txt
Jul 5, 2025
44961cf
Correct spelling in comments
Jul 12, 2025
733a349
Update README. Tested and runs OK. Reproduces functionality of the ex…
Jul 12, 2025
5626e65
Add __init__.py to pointing_model/
Jul 12, 2025
e5b5409
Refactor: Define axis_angle2quat()
Jul 18, 2025
6343fdd
Update README
Jul 18, 2025
52915ee
First attempt at non-upright support using roll offset
Jul 18, 2025
4b6bd1e
Fix bug -runs on PiFinder in simulation mode
Jul 18, 2025
fa008f4
Update README with EQ approach
Aug 10, 2025
e692a45
Move helper functions to quaternion_transforms.py
Aug 10, 2025
9bc3b40
Update name space of quaternion functions
Aug 10, 2025
c201a76
Move ImuDeadReckoning to imu_dead_reckoning.py
Aug 10, 2025
3c63e70
Fix import of custome package
Aug 10, 2025
d4d3cf4
Add ImuDeadReckoningEq and associated funcs for EQ frame
Aug 10, 2025
22975e0
Refactor integrator.py to encapsulate the altaz calculation
Aug 10, 2025
ebdf43f
Refactor integrator.py - Encapsulate another code block out of the wh…
Aug 10, 2025
e25bc3d
Fix - use last_image_solve to calculate cam2scope_offset
Aug 10, 2025
8a54b11
Refactor
Aug 10, 2025
bf081d7
Update comments
Aug 10, 2025
f6e6c7c
Use flag in ImuDeadReckoning rather than solved["Alt"] to determine i…
Aug 10, 2025
2e96a28
Add helper functions of the EQ versions (currently just a copy of the…
Aug 10, 2025
cc01e65
Refactor: Move if to where funcs are called
Aug 10, 2025
3185cb3
integrator.py: Modify the EQ version
Aug 10, 2025
90585e0
Init commit of RaDecRoll data class
Aug 10, 2025
9a0a4ff
Draft: calculating q_cam2scope (alignment)
Aug 10, 2025
1433995
Reorder
Aug 11, 2025
c11dfa4
Fix
Aug 11, 2025
2358dce
Fix: was not returning ra, dec of scope
Aug 11, 2025
28e9065
Set alignment between scope and camera
Aug 11, 2025
71bb9f1
Add comments
Aug 11, 2025
81a4382
Remove Horiz version
Aug 16, 2025
360144f
integrator.py: Fix to get it working for EQ version
Aug 16, 2025
f3cf177
Remove unused code block
Aug 16, 2025
e27e62b
Move initialization of logger to outside try:
Aug 16, 2025
dd3e891
Move init of solved dict to external module. Desktop-tested.
Aug 16, 2025
8800051
Remove setting of flip_alt_offset --> Not used. Desktop-tested.
Aug 16, 2025
7ad624d
Remove setting of location and datetime in the integrator.py loop -->…
Aug 16, 2025
2b22c0f
Remove unused datetime. Desktop-tested.
Aug 16, 2025
2f93f08
Rename func
Aug 16, 2025
060f65a
Refactor to set_alignment(). Desktop-tested.
Aug 16, 2025
8395eb9
Lint and update comments
Aug 16, 2025
6df3a18
Add comment
Aug 16, 2025
0aee663
Rename class to ImuDeadReckoning . Desktop-tested.
Aug 16, 2025
0e95c07
Add .get() methods
Aug 16, 2025
6a0861a
Add type hints
Aug 16, 2025
1af8e9a
Add comments
Aug 16, 2025
594354e
Add comments
Aug 16, 2025
ee27efd
Type hints. Desktop-check
Aug 16, 2025
47b4194
Re-order
Aug 16, 2025
30a15ae
Import RaDecRoll
Aug 16, 2025
5cf8aae
Add TODO
Aug 16, 2025
26e1681
Add sky test notes. --> Sky test OK
Aug 16, 2025
d6fa83f
Fix tuple type hints
Aug 17, 2025
536cbc4
Remove else: for clarity
Aug 17, 2025
2206da7
RaDecRoll: Make it a @dataclass and ddd support for None
Aug 17, 2025
5c4fbf7
Add note
Aug 17, 2025
7ce3303
imu_dead_reckoning: Disallow None as input to keep the interface clea…
Aug 17, 2025
431cbbf
Fix missing import
Aug 17, 2025
c8097f8
Rename object pointing_tracker --> imu_dead_reckoning to make it more…
Aug 17, 2025
a08d1a3
Remove returning unused dead_reckoning_flag
Aug 17, 2025
3a01c1c
Change invalid imu measurement from None to np.nan. Desktop-tested
Aug 17, 2025
15b0fe9
Remove unused code
Aug 17, 2025
85b39df
Move to class-level type hints
Aug 17, 2025
213d272
Rename confusing func name
Aug 17, 2025
d46c0cc
Move calculation of screen direction quaternion to a separate func fo…
Aug 17, 2025
020b880
screen_direction: Sketch other types. use axis_angle2quat() for flat …
Aug 17, 2025
a8eeab0
Fix latex equation formatting
Aug 17, 2025
e38ccab
Add photo and explanation in README for q_imu2cam
Aug 17, 2025
0c8510a
Move assert location for clarity.
Aug 17, 2025
6e4c519
Update README
Aug 17, 2025
f7ce9f4
Update q_imu2cam transformations for other types (not all done yet)
Aug 17, 2025
603fb05
Update comments
Aug 17, 2025
a566de2
Remove commented out code that change the IMU output axes.
Aug 17, 2025
3e31adf
Add type hints to integrator
Aug 17, 2025
af30980
Update README
Aug 17, 2025
9a09ec3
Reorder input parameter order for consistency
Aug 17, 2025
07f24f1
Update set_screen_direction with v3 Flat and as_dream
Aug 19, 2025
c15c12a
Update comments
Aug 19, 2025
700f77c
Add get_roll_by_mount_type(). --> Desktop-tested
Aug 19, 2025
4ce0012
Updated README with sky test observations --> Sky Test
Aug 19, 2025
b9df702
Update TODO
Aug 19, 2025
c7b65f0
Update altaz in integrator.py to see if this helps with the catalog i…
Aug 19, 2025
8d4346f
Refactored altaz calcuatlion. Now catalog works in altaz mount mode.
Aug 20, 2025
c0d1a88
Add note
Aug 20, 2025
e337805
Update README
Aug 20, 2025
06ac224
Add note to requirements_dev.txt
Aug 20, 2025
a80cc17
Merge branch 'main' into imu_quat_eq_coords
Aug 20, 2025
f3acc7c
Ruff: camera_interface.py
Aug 20, 2025
215f78a
Ruff: imu_pi.py
Aug 20, 2025
3921c81
Ruff: imu_print_measurements.py
Aug 20, 2025
f84b6e7
Move imu_print_measurements.py to pointing_model/
Aug 20, 2025
8836d36
Ruff: integrator.py
Aug 20, 2025
36e5709
Ruff: astro_coords.py
Aug 20, 2025
db274ce
Ruff: imu_dead_reckoning.py
Aug 20, 2025
684228a
Ruff: quaternion_transforms.py
Aug 20, 2025
b8e0a95
Move pip numpy-quaternion from requirements_dev.txt to requirements.txt
Aug 20, 2025
9d8e756
Fix screen_direction calculation bug for as_dream
Aug 20, 2025
bea3d50
Convert np.quaternion --> quaternion.quaternion to be compatible with…
Aug 20, 2025
355dc10
requirements.txt: Fix missing =
Aug 20, 2025
270a295
Ruff: imu_pi.py: Remove config that's no longer used because screen_d…
Aug 20, 2025
0c46ce1
Ruff
Aug 20, 2025
8be03fd
Fix type hints
Aug 20, 2025
92b898d
Lint
Aug 23, 2025
001da05
RaDecRoll: Add .initialize() method
Aug 26, 2025
312d6cd
Rename --> .reset()
Aug 26, 2025
d89455c
RaDecRoll: Add method to set using quaternions
Aug 26, 2025
daf4391
Change to using RaDecRoll class for inerfacing
Aug 26, 2025
06c636f
Update comments
Aug 26, 2025
4f7edd6
Update README
Aug 26, 2025
40b0466
Fix circular import. Desktop test --> OK
Aug 26, 2025
90d0620
Nox format
Aug 26, 2025
8b4de54
Fix issue from linting that was causing align to fail
Aug 31, 2025
af358e3
Refactor. Destop test --> OK (inc. align)
Aug 31, 2025
60b78ea
Move functionality from integrator.py to imu_dead_reckoning.py
Sep 6, 2025
a79f922
Add commens. Update README
Sep 6, 2025
b831815
astro_coords: Remove dependence on quaternion_transforms
Sep 6, 2025
ffb9883
Rename func --> get_q_eq()
Sep 6, 2025
842c727
Remove commented out code block
Sep 6, 2025
264a242
Update README issues list
Sep 21, 2025
b966269
Now shows RA difference to aim as -180 to +180 degrees rather than 0 …
Sep 21, 2025
4b91d20
README - detail out TODO & issues
Sep 21, 2025
50952b8
Lint
Sep 21, 2025
645c072
Add quaternion to mypy.overrides to ignore type hints
Sep 21, 2025
c3c30bf
Rename --> initialized_solved_dict
Sep 22, 2025
eea1e35
Fix bug in ra_diff calculation: Was causing a crash when catalogs sel…
Sep 22, 2025
1a082d6
Remove commented out code block
Sep 22, 2025
d0146da
Remove unused IMU data: "pos", "imu_pos", etc. which stored Euler ang…
Sep 22, 2025
79f00a7
Remove "imu_pos", "pos" etc. for Euler angles
Sep 22, 2025
7ce868c
Remove unused Euler angle functions/methods quat_to_euler() and get_e…
Sep 22, 2025
642f508
Merge branch 'main' into eq_mount_imu_support
Sep 22, 2025
d6b24bf
Address TODO items
Sep 22, 2025
f534001
ToDo items: Remove unused variables
Sep 22, 2025
944a6a8
Use solve dict from astro_coords
Sep 22, 2025
70717e7
Update README
Sep 22, 2025
03fc2e3
Update README
Sep 22, 2025
04465a2
Update README
Sep 22, 2025
5f1e1cc
Remove scipy spatial rotation package import - no longer needed for E…
Sep 22, 2025
dba10b1
Nox format
Sep 22, 2025
4ad6f5b
Nox format for changes merged from main
Sep 22, 2025
cc7b008
Nox format
Sep 22, 2025
76adc31
Change requirements.txt numpy=1.26.2 --> numpy=1.26.4 preferred by nu…
Sep 27, 2025
1cdf87b
Update README - remove parts that are no longer relevant (virtual env…
Sep 28, 2025
5d4946a
Merge branch 'brickbots:release' into eq_mount_imu_support
TakKanekoGit Sep 28, 2025
8229945
Change np.quaternion --> quaternion.quaternion so that it passes Nox …
Oct 1, 2025
c642224
Remove imu_print_measurements.py -- used for debugging
Oct 1, 2025
761653e
Sky-tested. Wrote notes in README.
Oct 5, 2025
1ac1f95
Merge branch 'main' into eq_mount_imu_support
Oct 5, 2025
040bbd9
Add issue to README
Oct 5, 2025
084bc4a
Fix typo in pyproject.toml --> Should pass nox
Oct 5, 2025
fae4033
Fix: adapt to changes in imu_pi.py from merging main
Oct 5, 2025
ce12196
Add details to issue in README
Oct 5, 2025
157d570
Merge branch 'main' into eq_mount_imu_support
Oct 17, 2025
398e538
Fix README
Oct 20, 2025
7519b7d
Edit README
Oct 21, 2025
4276701
Add test notes to README
Oct 24, 2025
2b8d178
Formatting
Oct 24, 2025
6f7e17b
Fixed q_imu2cam for 'right'
Oct 24, 2025
808ddb7
Fix rotation q_imu2cam for the "straight" type
Oct 25, 2025
3af5d57
Fix typo in comment
Oct 25, 2025
1ced258
Remove TODO in comments that's done
Oct 30, 2025
b8e09ff
Update comments
Oct 30, 2025
06df9be
Add notes from testing to README
Nov 1, 2025
958ce2c
Decrease IMU_MOVED_ANG_THRESHOLD from 0.1 deg to 0.06 deg, which is s…
Nov 2, 2025
175e32e
Lint
Nov 4, 2025
48230af
For testing: Disable 180 degree rotation of roll
Nov 4, 2025
ae6ec85
Merge branch 'main' into eq_mount_imu_support
Nov 4, 2025
92ba5e5
Update README
Nov 5, 2025
af785d9
Refactor: Rename functions/methodds
Nov 14, 2025
85b4bfd
Update README & comments
Nov 14, 2025
5015dce
Remove duplicate code and use the function from quaternion_transforms.py
Nov 14, 2025
ba3761e
For southern hemisphere, show south up.
Nov 14, 2025
d364fef
Big change: Change sign of rol calculated by quaternion_transforms
Nov 14, 2025
478a5c9
Update comments
Nov 14, 2025
3c16ef8
Merge branch 'main' into test_merge
Nov 15, 2025
d487b16
Merge issue fix: camera_interface.py: Now "focus" shows image. Still …
Nov 15, 2025
32165d2
Copy pre-merge versions of integrator.py to debug merge conflict issues.
Nov 15, 2025
3aed06b
Copy integrator from the last merge from main (ebca2) before the auto…
Nov 15, 2025
b6cc66e
Copy integrator from main and pre-merge for debugging
Nov 25, 2025
b75dd8a
Fix merge: Compared with camera_interface.py in main and restored cha…
Nov 25, 2025
5dffb15
Update as_dream --> as_bloom from main
Nov 25, 2025
a35c72b
Add TODO
Nov 25, 2025
1ad6aaf
Update initialized_solved_dict() to have same dict keys as main.
Nov 25, 2025
ac7cac7
Copy from main and pre-merge for debugging
Nov 25, 2025
a543144
Fix merge issues. Align `solve.py` with main
Nov 25, 2025
31d1ceb
Update comment
Nov 25, 2025
c41785c
Resolving merge conflicts in integrator.py
Nov 26, 2025
ccf5924
Attempt to align the merge with both branches
Dec 10, 2025
8d569c7
Add comments
Dec 10, 2025
60e8f45
Initialize Imu.__reading_diff
Dec 11, 2025
c2ceec9
Remove files added for debugging
Dec 11, 2025
69ac7ca
ZMerge remote-tracking branch 'origin/main' into eq_mount_imu_support
mrosseel Dec 23, 2025
63a7ce6
add constellation is None fix
mrosseel Dec 24, 2025
ab53116
Merge branch 'main' into eq_mount_imu_support
Jan 6, 2026
d1323ca
Adding readme and screen covers
brickbots Jan 7, 2026
f078c06
Add instructions to build guide how to test leds and buttons. (#371)
jscheidtmann Jan 12, 2026
cd3ae2b
Sqm improvements (#372)
Jan 28, 2026
65a234a
Adjust GPS antenna holder sizing
brickbots Jan 25, 2026
1ba6c1e
Rework gpsd gps code to fix issue with early dongle which never repor…
brickbots Jan 25, 2026
cb90c9f
Adding release notes
brickbots Jan 25, 2026
345b00a
Remove reference to assembled kit version
brickbots Jan 26, 2026
2ede939
Remove reference to assembled kit version
brickbots Jan 26, 2026
43d35bc
Merge branch 'main' into eq_mount_imu_support
Jan 30, 2026
83cfdce
Clean up
Jan 30, 2026
7d0220f
Add TODO
Jan 30, 2026
0626420
Nox & Edit comment
Jan 31, 2026
846b3e0
Fix freezing when chart selected
Feb 13, 2026
91438a2
Lint
Feb 13, 2026
bdac536
Fix freezing on align.py: Same as for chart.py
Feb 13, 2026
0da80c3
Rename method
Feb 13, 2026
ee41914
Validate input to .set_power_state()
Feb 14, 2026
619926c
status.py: Add checks to prevent it from freezing.
Feb 15, 2026
816bb7c
imu_pi.py: Add comment
Feb 15, 2026
b5d52c6
Rename status "LST SLV" to "LAST SLV" to avoid confusion with LST
Feb 15, 2026
098b51f
status.py: Deal with case when cam_solve_time = 0. Show "CAM_FAILED" …
Feb 15, 2026
a7d2259
Fix chart and align not showing "No solve yet"
Feb 15, 2026
e5c41b2
Remove file for debugging
Feb 15, 2026
37983ca
Move initialized_solved_dict() to solver.py and rename to get_initial…
Feb 15, 2026
90c488b
Fix: "can't plot yet" kept flashing up
Feb 15, 2026
d1e8e50
Add PiMount option for inserts and no_inserts
brickbots Jan 29, 2026
fa9e53c
Add support for Stellarium+ Mobile (#375)
oakamil Jan 29, 2026
41804a1
A bunch of typo/spelling fixes
brickbots Jan 31, 2026
2c147b6
Use J2000 as input epoch when Stellarium is connected (#376)
oakamil Feb 8, 2026
4c0e546
Rename --> set_cam2scope_alignment
Feb 17, 2026
6e80b48
Refactor
Feb 17, 2026
27eed52
Fix typo
Feb 19, 2026
91c9067
Alt and Az swapped around. Moving the scope in Az moves the chart in …
Feb 19, 2026
ec40272
Edit comments
Feb 19, 2026
14b091d
Move the hack for the PA to Roll calculation for testing from calc_ut…
Feb 20, 2026
17dee4b
Lint (Nox)
Feb 20, 2026
d779171
Merge branch 'main' into eq_mount_imu_support
Feb 20, 2026
6ba8475
Merge remote-tracking branch 'takkaneko/eq_mount_imu_support' into eq…
brickbots Feb 28, 2026
3032fc4
Make new IMU integrator conditional
brickbots Feb 28, 2026
4758fd8
Merge branch 'main' into eq_imu_conditional
brickbots Feb 28, 2026
eb926cc
Merge branch 'main' into eq_imu_conditional
brickbots Mar 1, 2026
498e487
Adjust menu option name
brickbots Mar 1, 2026
2d14136
Always try to solve
brickbots Mar 1, 2026
74bbe0b
Blank debug image if imu indicates motion to simulate real world moti…
brickbots Mar 1, 2026
e3ab23a
Merge branch 'main' into eq_imu_conditional
brickbots Mar 1, 2026
f7685c1
Removing cruft
brickbots Mar 1, 2026
10c03bc
Since arrows are configurable and user choice, remove screen based co…
brickbots Mar 1, 2026
c1b8e7b
Working on tracking down missing alt / calculating message
brickbots Mar 1, 2026
dec07af
Merged main
brickbots Mar 1, 2026
a50638c
Change config option name
brickbots Mar 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion default_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -176,5 +176,6 @@
"active_telescope_index": 0,
"active_eyepiece_index": 0
},
"imu_threshold_scale": 1
"imu_threshold_scale": 1,
"imu_integrator": "classic"
}
2 changes: 0 additions & 2 deletions python/PiFinder/calc_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,6 @@ def aim_degrees(shared_state, mount_type, screen_direction, target):
)
az_diff = target_az - solution["Az"]
az_diff = (az_diff + 180) % 360 - 180
if screen_direction in ["flat", "as_bloom"]:
az_diff *= -1 # TODO: Why should this depend on the screen type?

alt_diff = target_alt - solution["Alt"]
alt_diff = (alt_diff + 180) % 360 - 180
Expand Down
18 changes: 15 additions & 3 deletions python/PiFinder/camera_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* Takes full res images on demand

"""

from typing import Tuple, Optional
from PIL import Image
import os
Expand Down Expand Up @@ -56,14 +57,20 @@ def capture_file(self, filename) -> None:
def capture_raw_file(self, filename) -> None:
pass

def _blank_capture(self):
"""
Returns a properly formated black frame
"""
return Image.new("L", (512, 512), 0) # Black 512x512 image

def capture_bias(self):
"""
Capture a bias frame for pedestal calculation.
Base implementation returns a black frame (no bias correction).
Override in subclasses that support bias frames.
Returns Image.Image or np.ndarray depending on implementation.
"""
return Image.new("L", (512, 512), 0) # Black 512x512 image
return self._blank_capture()

def set_camera_config(
self, exposure_time: float, gain: float
Expand Down Expand Up @@ -171,7 +178,7 @@ def get_image_loop(
base_image = base_image.convert(
"L"
) # Convert to grayscale to match camera output
time.sleep(1)
time.sleep(0.2)
image_end_time = time.time()
# check imu to make sure we're still static
imu_end = shared_state.imu()
Expand All @@ -187,7 +194,12 @@ def get_image_loop(
else:
pointing_diff = 0.0

camera_image.paste(base_image)
# Make image available
if debug and abs(pointing_diff) > 0.01:
# Check if we moved and return a blank image
camera_image.paste(self._blank_capture())
else:
camera_image.paste(base_image)

image_metadata = {
"exposure_start": image_start_time,
Expand Down
250 changes: 250 additions & 0 deletions python/PiFinder/imu_pi_classic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
#!/usr/bin/python
# -*- coding:utf-8 -*-
"""
This module is for IMU related functions

Classic version: Uses axis remapping and euler angle output for the
classic (alt/az offset) integrator dead-reckoning approach.
"""

import time
from PiFinder.multiproclogging import MultiprocLogging
import board
import adafruit_bno055
import logging
import quaternion # numpy-quaternion

from scipy.spatial.transform import Rotation

from PiFinder import config

logger = logging.getLogger("IMU.pi")

QUEUE_LEN = 10
MOVE_CHECK_LEN = 2


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.NDOF_MODE
cfg = config.Config()
if (
cfg.get_option("screen_direction") == "flat"
or cfg.get_option("screen_direction") == "straight"
or cfg.get_option("screen_direction") == "flat3"
):
self.sensor.axis_remap = (
adafruit_bno055.AXIS_REMAP_Y,
adafruit_bno055.AXIS_REMAP_X,
adafruit_bno055.AXIS_REMAP_Z,
adafruit_bno055.AXIS_REMAP_POSITIVE,
adafruit_bno055.AXIS_REMAP_POSITIVE,
adafruit_bno055.AXIS_REMAP_NEGATIVE,
)
elif cfg.get_option("screen_direction") == "as_bloom":
self.sensor.axis_remap = (
adafruit_bno055.AXIS_REMAP_X,
adafruit_bno055.AXIS_REMAP_Z,
adafruit_bno055.AXIS_REMAP_Y,
adafruit_bno055.AXIS_REMAP_POSITIVE,
adafruit_bno055.AXIS_REMAP_POSITIVE,
adafruit_bno055.AXIS_REMAP_POSITIVE,
)
else:
self.sensor.axis_remap = (
adafruit_bno055.AXIS_REMAP_Z,
adafruit_bno055.AXIS_REMAP_Y,
adafruit_bno055.AXIS_REMAP_X,
adafruit_bno055.AXIS_REMAP_POSITIVE,
adafruit_bno055.AXIS_REMAP_POSITIVE,
adafruit_bno055.AXIS_REMAP_POSITIVE,
)
self.quat_history = [(0, 0, 0, 0)] * QUEUE_LEN
self._flip_count = 0
self.calibration = 0
self.avg_quat = (0, 0, 0, 0)
self.__moving = False

self.last_sample_time = time.time()

# Calibration settings
self.imu_sample_frequency = 1 / 30

# First value is delta to exceed between samples
# to start moving, second is threshold to fall below
# to stop moving.

imu_threshold_scale = cfg.get_option("imu_threshold_scale", 1)
self.__moving_threshold = (
0.0005 * imu_threshold_scale,
0.0003 * imu_threshold_scale,
)

def quat_to_euler(self, quat):
if quat[0] + quat[1] + quat[2] + quat[3] == 0:
return 0, 0, 0
rot = Rotation.from_quat(quat)
rot_euler = rot.as_euler("xyz", degrees=True)
# convert from -180/180 to 0/360
rot_euler[0] += 180
rot_euler[1] += 180
rot_euler[2] += 180
return rot_euler

def moving(self):
"""
Compares most recent reading
with past readings
"""
return self.__moving

def update(self):
# check for update frequency
if time.time() - self.last_sample_time < self.imu_sample_frequency:
return

self.last_sample_time = time.time()

# Throw out non-calibrated data
self.calibration = self.sensor.calibration_status[1]
if self.calibration == 0:
logger.warning("NOIMU CAL")
return True
quat = self.sensor.quaternion
if quat[0] is None:
logger.warning("IMU: Failed to get sensor values")
return

_quat_diff = []
for i in range(4):
_quat_diff.append(abs(quat[i] - self.quat_history[-1][i]))

self.__reading_diff = sum(_quat_diff)

# This seems to be some sort of defect / side effect
# of the integration system in the BNO055
# When not moving quat output will vaccilate
# by exactly this amount... so filter this out
if self.__reading_diff == 0.0078125:
self.__reading_diff = 0
return

# Sometimes the quat output will 'flip' and change by 2.0+
# from one reading to another. This is clearly noise or an
# artifact, so filter them out
if self.__reading_diff > 1.5:
self._flip_count += 1
if self._flip_count > 10:
# with the history initialized to 0,0,0,0 the unit
# can get stuck seeing flips if the IMU starts
# returning data. This count will reset history
# to the current state if it exceeds 10
self.quat_history = [quat] * QUEUE_LEN
self.__reading_diff = 0
else:
self.__reading_diff = 0
return
else:
# no flip
self._flip_count = 0

self.avg_quat = quat
if len(self.quat_history) == QUEUE_LEN:
self.quat_history = self.quat_history[1:]
self.quat_history.append(quat)

if self.__moving:
if self.__reading_diff < self.__moving_threshold[1]:
self.__moving = False
else:
if self.__reading_diff > self.__moving_threshold[0]:
self.__moving = True

def get_euler(self):
return list(self.quat_to_euler(self.avg_quat))

def __str__(self):
return (
f"IMU Information:\n"
f"Calibration Status: {self.calibration}\n"
f"Quaternion History: {self.quat_history}\n"
f"Average Quaternion: {self.avg_quat}\n"
f"Moving: {self.moving()}\n"
f"Reading Difference: {self.__reading_diff}\n"
f"Flip Count: {self._flip_count}\n"
f"Last Sample Time: {self.last_sample_time}\n"
f"IMU Sample Frequency: {self.imu_sample_frequency}\n"
f"Moving Threshold: {self.__moving_threshold}\n"
)


def imu_monitor(shared_state, console_queue, log_queue):
MultiprocLogging.configurer(log_queue)
logger.debug("Starting IMU")
imu = None
try:
imu = Imu()
except Exception as e:
logger.error(f"Error starting phyiscal IMU : {e}")
logger.error("Falling back to fake IMU")
console_queue.put("IMU: Error starting physical IMU, using fake IMU")
console_queue.put("DEGRADED_OPS IMU")
from PiFinder.imu_fake import Imu as ImuFake

imu = ImuFake()

imu = Imu()
imu_calibrated = False
imu_data = {
"moving": False,
"move_start": None,
"move_end": None,
"pos": [0, 0, 0],
"quat": quaternion.quaternion(0, 0, 0, 0),
"start_pos": [0, 0, 0],
"status": 0,
}
while True:
imu.update()
imu_data["status"] = imu.calibration
if imu.moving():
if not imu_data["moving"]:
logger.debug("IMU: move start")
imu_data["moving"] = True
imu_data["start_pos"] = imu_data["pos"]
imu_data["move_start"] = time.time()
imu_data["pos"] = imu.get_euler()
imu_data["quat"] = quaternion.from_float_array(imu.avg_quat)

else:
if imu_data["moving"]:
# If we were moving and we now stopped
logger.debug("IMU: move end")
imu_data["moving"] = False
imu_data["pos"] = imu.get_euler()
imu_data["quat"] = quaternion.from_float_array(imu.avg_quat)
imu_data["move_end"] = time.time()

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

if shared_state is not None and imu_calibrated:
shared_state.set_imu(imu_data)


if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
logger.info("Trying to read state from IMU")
imu = None
try:
imu = Imu()
for i in range(10):
imu.update()
time.sleep(0.5)
except Exception as e:
logger.exception("Error starting phyiscal IMU", e)
17 changes: 6 additions & 11 deletions python/PiFinder/integrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,22 +111,18 @@ def integrator(shared_state, solver_queue, console_queue, log_queue, is_debug=Fa
)
)
shared_state.set_solve_state(True)
# We have a new image solve: Use plate-solving for RA/Dec
update_plate_solve_and_imu(imu_dead_reckoning, solved)
else:
# Failed solve - clear constellation
solved["solve_source"] = "CAM_FAILED"
solved["constellation"] = ""
shared_state.set_solve_state(False)

# Push all camera solves (success and failure) immediately
# This ensures auto-exposure sees Matches=0 for failed solves
shared_state.set_solution(solved)
shared_state.set_solve_state(True)

# We have a new image solve: Use plate-solving for RA/Dec
update_plate_solve_and_imu(imu_dead_reckoning, solved)
# Push failed solved immediately
# This ensures auto-exposure sees Matches=0 for failed solves
shared_state.set_solution(solved)
shared_state.set_solve_state(False)

# TODO: main also calculates (alt, az) for target & camera center.
# Don't think this is needed because they are done by the update functions?
elif imu_dead_reckoning.tracking:
# Previous plate-solve exists so use IMU dead-reckoning from
# the last plate solved coordinates.
Expand All @@ -135,7 +131,6 @@ def integrator(shared_state, solver_queue, console_queue, log_queue, is_debug=Fa
update_imu(imu_dead_reckoning, solved, last_image_solve, imu)

# Push IMU updates only if newer than last push
# (Camera solves already pushed above at line ~185) # TODO: Line numbers may have changed in merge
if (
solved["RA"] and solved["solve_time"] > last_solve_time
# and solved["solve_source"] == "IMU"
Expand Down
Loading