-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: yaw control basics are added (WIP)
- Loading branch information
1 parent
f62f975
commit 41bb9bd
Showing
8 changed files
with
397 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,13 @@ | ||
from typing import Tuple | ||
|
||
__all__ = ("Coordinate3D", "RGBAColor") | ||
__all__ = ("Coordinate3D", "RGBAColor", "Rotation3D") | ||
|
||
|
||
#: Type alias for simple 3D coordinates | ||
Coordinate3D = Tuple[float, float, float] | ||
|
||
#: Type alias for RGBA color tuples used by Blender | ||
RGBAColor = Tuple[float, float, float, float] | ||
|
||
#: Type alias for simple 3D rotations | ||
Rotation3D = Tuple[float, float, float] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
from dataclasses import dataclass | ||
from operator import attrgetter | ||
from typing import ( | ||
Sequence, | ||
TypeVar, | ||
) | ||
|
||
__all__ = ( | ||
"YawSetpointList", | ||
"YawSetpoint", | ||
) | ||
|
||
|
||
C = TypeVar("C", bound="YawSetpointList") | ||
|
||
|
||
@dataclass | ||
class YawSetpoint: | ||
"""The simplest representation of a yaw setpoint.""" | ||
|
||
time: float | ||
"""The timestamp associated to the yaw setpoint, in seconds.""" | ||
|
||
angle: float | ||
"""The yaw angle associated to the yaw setpoint, in degrees.""" | ||
|
||
|
||
class YawSetpointList: | ||
"""Simplest representation of a causal yaw setpoint list in time. | ||
Setpoints are assumed to be linear, i.e. yaw rate is constant | ||
between setpoints. | ||
""" | ||
|
||
def __init__(self, setpoints: Sequence[YawSetpoint] = []): | ||
self.setpoints = sorted(setpoints, key=attrgetter("time")) | ||
|
||
def append(self, setpoint: YawSetpoint) -> None: | ||
"""Add a setpoint to the end of the setpoint list.""" | ||
if self.setpoints and self.setpoints[-1].time >= setpoint.time: | ||
raise ValueError("New setpoint must come after existing setpoints in time") | ||
self.setpoints.append(setpoint) | ||
|
||
def as_dict(self, ndigits: int = 3): | ||
"""Create a Skybrush-compatible dictionary representation of this | ||
instance. | ||
Parameters: | ||
ndigits: round floats to this precision | ||
Return: | ||
dictionary of this instance, to be converted to JSON later | ||
""" | ||
return { | ||
"setpoints": [ | ||
[ | ||
round(setpoint.time, ndigits=ndigits), | ||
round(setpoint.angle, ndigits=ndigits), | ||
] | ||
for setpoint in self.setpoints | ||
], | ||
"version": 1, | ||
} | ||
|
||
def shift( | ||
self: C, | ||
delta: float, | ||
) -> C: | ||
"""Translates the yaw setpoints with the given delta angle. The | ||
setpoint list will be manipulated in-place. | ||
Args: | ||
delta: the translation angle | ||
Returns: | ||
The shifted yaw setpoint list | ||
""" | ||
|
||
self.setpoints = [YawSetpoint(p.time, p.angle + delta) for p in self.setpoints] | ||
|
||
return self | ||
|
||
def simplify(self: C) -> C: | ||
"""Simplify yaw setpoints in place. | ||
Returns: | ||
the simplified yaw setpoint list | ||
""" | ||
if not self.setpoints: | ||
return self | ||
|
||
# set first yaw in the [0, 360) range and shift entire list accordingly | ||
angle = self.setpoints[0].angle % 360 | ||
delta = angle - self.setpoints[0].angle | ||
if delta: | ||
self.shift(delta) | ||
|
||
# remove intermediate points on constant angular speed segments | ||
new_setpoints: list[YawSetpoint] = [] | ||
last_angular_speed = -1e12 | ||
for setpoint in self.setpoints: | ||
if not new_setpoints: | ||
new_setpoints.append(setpoint) | ||
else: | ||
dt = setpoint.time - new_setpoints[-1].time | ||
if dt <= 0: | ||
raise RuntimeError( | ||
f"Yaw timestamps are not causal ({setpoint.time} <= {new_setpoints[-1].time})" | ||
) | ||
angular_speed = (setpoint.angle - new_setpoints[-1].angle) / dt | ||
if abs(angular_speed - last_angular_speed) < 1e-6: | ||
new_setpoints[-1] = setpoint | ||
else: | ||
new_setpoints.append(setpoint) | ||
last_angular_speed = angular_speed | ||
|
||
self.setpoints = new_setpoints | ||
|
||
return self |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.