Target Tracking (With Yaw Compensation)¶
This tutorial demonstrates how to generate a target tracking profile, aligning with the target velocity direction
Setup¶
!pip install cesiumpy@git+https://github.com/open-space-collective/cesiumpy
Collecting cesiumpy@ git+https://github.com/open-space-collective/cesiumpy
Cloning https://github.com/open-space-collective/cesiumpy to /tmp/pip-install-ixu6tl0k/cesiumpy_9ada6a2397f843cf93a2cce86479e06b
Running command git clone --filter=blob:none --quiet https://github.com/open-space-collective/cesiumpy /tmp/pip-install-ixu6tl0k/cesiumpy_9ada6a2397f843cf93a2cce86479e06b
Resolved https://github.com/open-space-collective/cesiumpy to commit 7b01ce8826db0a694c3f9b271832e77dcf171923
Running command git submodule update --init --recursive -q
Preparing metadata (setup.py) ... ?25l-
done
?25hRequirement already satisfied: traitlets in /usr/local/lib/python3.11/dist-packages (from cesiumpy@ git+https://github.com/open-space-collective/cesiumpy) (5.14.3)
Requirement already satisfied: geopy>=1.11.0 in /usr/local/lib/python3.11/dist-packages (from cesiumpy@ git+https://github.com/open-space-collective/cesiumpy) (2.4.1)
Requirement already satisfied: geographiclib<3,>=1.52 in /usr/local/lib/python3.11/dist-packages (from geopy>=1.11.0->cesiumpy@ git+https://github.com/open-space-collective/cesiumpy) (2.1)
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager, possibly rendering your system unusable. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv. Use the --root-user-action option if you know what you are doing and want to suppress this warning.
[notice] A new release of pip is available: 25.0.1 -> 25.3
[notice] To update, run: python3.11 -m pip install --upgrade pip
import os
import cesiumpy
from ostk.mathematics.object import RealInterval
from ostk.physics import Environment
from ostk.physics.unit import Length
from ostk.physics.unit import Angle
from ostk.physics.time import Scale
from ostk.physics.time import Instant
from ostk.physics.time import Duration
from ostk.physics.time import Interval
from ostk.physics.time import DateTime
from ostk.physics.time import Time
from ostk.physics.coordinate import Position
from ostk.physics.coordinate.spherical import LLA
from ostk.astrodynamics import Trajectory
from ostk.astrodynamics.trajectory import Orbit
from ostk.astrodynamics.flight import Profile
from ostk.astrodynamics.access import Generator as AccessGenerator
from ostk.astrodynamics.access import AccessTarget
from ostk.astrodynamics.access import VisibilityCriterion
from ostk.astrodynamics.viewer import Viewer
from ostk.astrodynamics.viewer import ConicSensor
Computation¶
Initialize an environment:
environment = Environment.default(True)
earth = environment.access_celestial_object_with_name("Earth")
Construct an orbit:
orbit = Orbit.sun_synchronous(
epoch=Instant.date_time(DateTime(2024, 1, 1, 0, 0, 0), Scale.UTC),
altitude=Length.kilometers(550.0),
local_time_at_descending_node=Time(14, 30, 0),
celestial_object=earth,
)
Define an interval of interest:
interval = Interval.closed(
start_instant=Instant.date_time(DateTime(2024, 2, 9, 0, 0, 0), Scale.UTC),
end_instant=Instant.date_time(DateTime(2024, 2, 10, 0, 0, 0), Scale.UTC),
)
Define the coordinates of the target to track:
start_lla = LLA(
latitude=Angle.degrees(0.0),
longitude=Angle.degrees(0.0),
altitude=Length.meters(0.0),
)
end_lla = LLA(
latitude=Angle.degrees(0.5),
longitude=Angle.degrees(0.1),
altitude=Length.meters(0.0),
)
mid_lla = start_lla.calculate_intermediate_to(end_lla, 0.5)
Find one access during which the satellite is over the target:
visibility_criterion = VisibilityCriterion.from_aer_interval(
azimuth_interval=RealInterval.closed(0.0, 360.0),
elevation_interval=RealInterval.closed(60.0, 90.0),
range_interval=RealInterval.closed(0.0, 10000e3),
)
access_target = AccessTarget.from_lla(
visibility_criterion=visibility_criterion,
lla=mid_lla,
celestial=earth,
)
access_generator = AccessGenerator(
environment=environment,
)
accesses = access_generator.compute_accesses(
interval=interval,
access_target=access_target,
to_trajectory=orbit,
)
access = accesses[0]
instants = access.get_interval().generate_grid(Duration.seconds(1.0))
Construct a Vehicle Velocity, Local Horizontal (VVLH) frame from the orbit:
vvlh_frame = orbit.get_orbital_frame(Orbit.FrameType.VVLH)
Generate a flight profile:
line_scan_trajectory = Trajectory.ground_strip(
start_lla=start_lla,
end_lla=end_lla,
instants=instants,
)
/tmp/ipykernel_2824/2653645553.py:1: DeprecationWarning: Use Trajectory(model=TargetScan(...)) instead.
line_scan_trajectory = Trajectory.ground_strip(
uncompensated_profile = Profile.custom_pointing(
orbit=orbit,
alignment_target=Profile.TrajectoryTarget.target_position(
trajectory=line_scan_trajectory,
axis=Profile.Axis.Z,
),
clocking_target=Profile.Target(
type=Profile.TargetType.VelocityECI,
axis=Profile.Axis.X,
),
)
yaw_compensated_profile = Profile.custom_pointing(
orbit=orbit,
alignment_target=Profile.TrajectoryTarget.target_position(
trajectory=line_scan_trajectory,
axis=Profile.Axis.Z,
),
clocking_target=Profile.TrajectoryTarget.target_velocity(
trajectory=line_scan_trajectory,
axis=Profile.Axis.X,
),
)
Visualize the scene in 3D:
# Get a token from https://cesium.com/learn/ion/cesium-ion-access-tokens/
viewer = Viewer(
interval=access.get_interval(),
cesium_token=os.environ.get("CESIUM_TOKEN"),
)
viewer.add_profile(
profile=yaw_compensated_profile,
step=Duration.seconds(10.0),
show_orbital_track=True,
cesium_asset_id=669199,
sensors=[
ConicSensor(
"Boresight",
[0.0, 0.0, 1.0],
cesiumpy.color.RED.with_alpha(0.5),
Angle.degrees(0.5),
Length.meters(6913000.0),
)
],
)
viewer.add_line(
positions=[Position.from_lla(lla) for lla in LLA.linspace(start_lla, end_lla, 100)]
)
with open("render.html", "w") as f:
f.write(viewer.render())