Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
261 commits
Select commit Hold shift + click to select a range
9361d13
Resolve merge conflict
Jun 22, 2025
ab1ba5c
Add comments to clarify that it should scalar-first quaternion
Jun 9, 2025
450a2e3
Disable rotating the IMU axes - use its native axes
Jun 9, 2025
7648c38
Remove calls to using Euler angles
Jun 9, 2025
96d052c
imu_pi: Disable "pos" (Euler angles)
Jun 9, 2025
ca5cbd8
imu_pi: Convert avg_quat to numpy quaternion to avoid ambiguity over …
Jun 9, 2025
996d937
integrator: Change over from using imu_pos to quaternions. Still in p…
Jun 9, 2025
28e64ba
Rename --> imu_print_measurements.py. Add usage in README_IMU.md
Jun 21, 2025
5cd93c4
Initial commit of pointing_model.py
Jun 21, 2025
07ba1e1
Add comments
Jun 21, 2025
150dc89
pointing_model.py - remove unused funcs for now
Jun 21, 2025
001b2d1
pointing_model: Add func
Jun 21, 2025
64fadc1
pointing_model: Rename func
Jun 21, 2025
756c5be
Modify integrator.py to use quaternion-based IMU dead-reckoning
Jun 21, 2025
77b1b88
Add comments
Jun 21, 2025
e7b50ea
Fix typo
Jun 21, 2025
e96b71b
Edit comment
Jun 21, 2025
983476f
Change usages of imu["pos"] to imu["quat"]
Jun 21, 2025
08d3004
Fix so that it's '..' inside "..."
Jun 21, 2025
44f12b2
Removed astro_data/comets.txt that was mistakenly committed
Jun 22, 2025
4de737a
Remove PiFinder/python/tetra3 that was mistakenly added.
Jun 22, 2025
7f61c7e
Update README
Jun 22, 2025
0ad8b44
Initialize imu["quat"] and imu["avg_quat"] to None rather than np.qua…
Jun 22, 2025
921d2da
Move to pointing_model/README.md
Jun 24, 2025
8177b6b
Update README with theory
Jun 24, 2025
968e65f
Add pointing_model.get_quat_angular_diff()
Jun 25, 2025
5ceb464
Use quaternion-based difference for deciding if the camera was still …
Jun 25, 2025
f718879
solver.py: Disable "imu_pos"
Jun 25, 2025
d4f012f
camera_interface: Convert pointing_diff radians to degrees to be comp…
Jun 25, 2025
d011b5b
Fix missing/incorrect import of pointing_model
Jun 25, 2025
3e9e0d2
pointing_model: Fix np.arctan2 in this version rather than np.atan2
Jun 25, 2025
b45056f
Define max_imu_ang_during_exposure in solver.py; a threshold for last…
Jun 25, 2025
877361e
Temporarily disable printing IMU quaternions to status.py
Jun 25, 2025
ebfa023
Restored the old IMU code blocks --> Camera now works in Focus mode
Jun 26, 2025
54618e7
camera_interface.py: Reverted to pointing_diff calculation using quat…
Jun 26, 2025
51cf757
Store quaternion measurements as np.quaternion type in state --> Came…
Jun 26, 2025
c753be1
Shared state: imu["quat"] stores numpy.quaternion --> Camera runs in …
Jun 26, 2025
3011269
integrator.py: Use quaternion ang. diff to switch to IMU tracking in …
Jun 27, 2025
12cb497
integrator.py: Refactor
Jun 27, 2025
95c0e82
integrator.py: Disable old calculation of Altaz
Jun 27, 2025
91eab69
Add comments
Jun 27, 2025
b957209
Need to change dictionary solve in both integrator.py and solver.py -…
Jun 27, 2025
5917e79
Fix at scope: Missing name space pointing.
Jun 27, 2025
a01bb0a
Edit comment
Jun 27, 2025
9b9ddf8
Fix at scope: Typo
Jun 27, 2025
d04d17b
Debug at scope: Increased threshold for using IMU tracking to 0.1 deg…
Jun 27, 2025
8fd5ef1
imu_pi.py: Disable BNO055 config to rotate the IMU data
Jun 27, 2025
f7e194b
Disable using the old method to calculate Euler angles (imu["pos"])
Jun 28, 2025
5b9441c
Update comments
Jun 28, 2025
752d3b1
Remove debug logging that was added that was dumping too much to the …
Jun 28, 2025
4eb04d5
Additional logging printing for debugging
Jul 5, 2025
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
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
6 changes: 3 additions & 3 deletions docs/source/dev_arch.rst
Original file line number Diff line number Diff line change
Expand Up @@ -219,12 +219,12 @@ There are three types of shared state in PiFinder
SharedStateObj(
power_state=1,
solve_state=True,
solution={'RA': 22.86683471463411, 'Dec': 15.347716050003328, 'imu_pos': [171.39798541261814, 202.7646132036331, 358.2794741322842],
solution={'RA': 22.86683471463411, 'Dec': 15.347716050003328,
'solve_time': 1695297930.5532792, 'cam_solve_time': 1695297930.5532837, 'Roll': 306.2951794424281, 'FOV': 10.200729425086111,
RMSE': 21.995567413046142, 'Matches': 12, 'Prob': 6.987725483613384e-13, 'T_solve': 15.00384000246413, 'RA_target': 22.86683471463411,
'Dec_target': 15.347716050003328, 'T_extract': 75.79255499877036, 'Alt': None, 'Az': None, 'solve_source': 'CAM', 'constellation': 'Psc'},
imu={'moving': False, 'move_start': 1695297928.69749, 'move_end': 1695297928.764207, 'pos': [171.39798541261814, 202.7646132036331, 358.2794741322842],
'start_pos': [171.4009455613444, 202.76321535004726, 358.2587208386012], 'status': 3},
imu={'moving': False, 'move_start': 1695297928.69749, 'move_end': 1695297928.764207,
'status': 3},
location={'lat': 59.05139745, 'lon': 7.987654, 'altitude': 151.4, 'gps_lock': False, 'timezone': 'Europe/Stockholm', 'last_gps_lock': None},
datetime=None,
screen=<PIL.Image.Image image mode=RGB size=128x128 at 0xE693C910>,
Expand Down
8 changes: 6 additions & 2 deletions python/PiFinder/calc_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ 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
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 All @@ -168,8 +168,11 @@ def aim_degrees(shared_state, mount_type, screen_direction, target):
else:
# EQ Mount type
ra_diff = target.ra - solution["RA"]
ra_diff = (ra_diff + 180) % 360 - 180 # Convert to -180 to +180

dec_diff = target.dec - solution["Dec"]
dec_diff = (dec_diff + 180) % 360 - 180

return ra_diff, dec_diff
return None, None

Expand Down Expand Up @@ -247,7 +250,8 @@ def hadec_to_roll(ha_deg, dec_deg, lat_deg):
if dec_deg <= lat_deg:
roll_deg = -pa_deg
else:
roll_deg = -pa_deg + np.sign(ha_deg) * 180
roll_deg = -pa_deg
#roll_deg = -pa_deg + np.sign(ha_deg) * 180 # Disable for testing TODO: Check this

return roll_deg

Expand Down
30 changes: 17 additions & 13 deletions python/PiFinder/camera_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@
* Takes full res images on demand

"""

import datetime
import logging
import os
import queue
import time
from typing import Tuple, Optional

from PIL import Image
import os
import time
import datetime
import numpy as np
import queue
import logging

from PiFinder import state_utils, utils
import PiFinder.pointing_model.quaternion_transforms as qt
from PiFinder.auto_exposure import (
ExposurePIDController,
SweepZeroStarHandler,
Expand All @@ -28,6 +28,7 @@
generate_exposure_sweep,
)


logger = logging.getLogger("Camera.Interface")


Expand Down Expand Up @@ -164,20 +165,23 @@ def get_image_loop(
imu_end = shared_state.imu()

# see if we moved during exposure
reading_diff = 0
if imu_start and imu_end:
reading_diff = (
abs(imu_start["pos"][0] - imu_end["pos"][0])
+ abs(imu_start["pos"][1] - imu_end["pos"][1])
+ abs(imu_start["pos"][2] - imu_end["pos"][2])
# Returns the pointing difference between successive IMU quaternions as
# an angle (radians). Note that this also accounts for rotation around the
# scope axis. Returns an angle in radians.
pointing_diff = qt.get_quat_angular_diff(
imu_start["quat"], imu_end["quat"]
)
else:
pointing_diff = 0.0

camera_image.paste(base_image)

image_metadata = {
"exposure_start": image_start_time,
"exposure_end": image_end_time,
"imu": imu_end,
"imu_delta": reading_diff,
"imu_delta": np.rad2deg(pointing_diff),
"exposure_time": self.exposure_time,
"gain": self.gain,
}
Expand Down
99 changes: 36 additions & 63 deletions python/PiFinder/imu_pi.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,65 +6,40 @@
"""

import time
from PiFinder import config
from PiFinder.multiproclogging import MultiprocLogging
import board
import adafruit_bno055
import logging

from scipy.spatial.transform import Rotation

from PiFinder import config
import numpy as np
import quaternion # Numpy quaternion

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

QUEUE_LEN = 10
MOVE_CHECK_LEN = 2


class Imu:
"""
Previous version modified the IMU axes but the IMU now outputs the
measurements using its native axes and the transformation from the IMU
axes to the camera frame is done by the IMU dead-reckonig functionality.
"""

def __init__(self):
i2c = board.I2C()
self.sensor = adafruit_bno055.BNO055_I2C(i2c)
# IMPLUS mode: Accelerometer + Gyro + Fusion data
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.avg_quat = (0, 0, 0, 0) # Scalar-first quaternion: (w, x, y, z)
self.__moving = False

self.__reading_diff = 0.0

self.last_sample_time = time.time()

# Calibration settings
Expand All @@ -74,23 +49,12 @@ def __init__(self):
# to start moving, second is threshold to fall below
# to stop moving.

cfg = config.Config()
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
Expand All @@ -110,6 +74,7 @@ def update(self):
if self.calibration == 0:
logger.warning("NOIMU CAL")
return True
# adafruit_bno055 uses quaternion convention (w, x, y, z)
quat = self.sensor.quaternion
if quat[0] is None:
logger.warning("IMU: Failed to get sensor values")
Expand All @@ -132,6 +97,9 @@ def update(self):
# 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
#
# NOTE: This is probably due to the double-cover property of quaternions
# where +q and -q describe the same rotation?
if self.__reading_diff > 1.5:
self._flip_count += 1
if self._flip_count > 10:
Expand All @@ -148,7 +116,9 @@ def update(self):
# no flip
self._flip_count = 0

# avg_quat is the latest quaternion measurement, not the average
self.avg_quat = quat
# Write over the quat_hisotry queue FIFO:
if len(self.quat_history) == QUEUE_LEN:
self.quat_history = self.quat_history[1:]
self.quat_history.append(quat)
Expand All @@ -160,9 +130,6 @@ def update(self):
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"
Expand Down Expand Up @@ -195,35 +162,40 @@ def imu_monitor(shared_state, console_queue, log_queue):

imu = Imu()
imu_calibrated = False
# TODO: Remove move_start, move_end
imu_data = {
"moving": False,
"move_start": None,
"move_end": None,
"pos": [0, 0, 0],
"quat": [0, 0, 0, 0],
"start_pos": [0, 0, 0],
"quat": quaternion.quaternion(
0, 0, 0, 0
), # Scalar-first numpy quaternion(w, x, y, z) - Init to invalid quaternion
"status": 0,
}

while True:
imu.update()
imu_data["status"] = imu.calibration

# TODO: move_start and move_end don't seem to be used?
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"] = imu.avg_quat

# DISABLE old method
imu_data["quat"] = quaternion.from_float_array(
imu.avg_quat
) # Scalar-first (w, x, y, z)
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"] = imu.avg_quat
imu_data["move_end"] = time.time()
imu_data["quat"] = quaternion.from_float_array(
imu.avg_quat
) # Scalar-first (w, x, y, z)

if not imu_calibrated:
if imu_data["status"] == 3:
Expand All @@ -242,6 +214,7 @@ def imu_monitor(shared_state, console_queue, log_queue):
imu = Imu()
for i in range(10):
imu.update()
print(imu)
time.sleep(0.5)
except Exception as e:
logger.exception("Error starting phyiscal IMU", e)
Loading
Loading