raddo 0.1.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of raddo might be problematic. Click here for more details.
- raddo-0.1.3/.gitignore +9 -0
- raddo-0.1.3/LICENSE +21 -0
- raddo-0.1.3/PKG-INFO +142 -0
- raddo-0.1.3/README.md +111 -0
- raddo-0.1.3/docker/README.md +46 -0
- raddo-0.1.3/pyproject.toml +54 -0
- raddo-0.1.3/src/raddo/__init__.py +0 -0
- raddo-0.1.3/src/raddo/controllers/__init__.py +7 -0
- raddo-0.1.3/src/raddo/controllers/acados_controller.py +356 -0
- raddo-0.1.3/src/raddo/controllers/base_controller.py +18 -0
- raddo-0.1.3/src/raddo/controllers/cem_controller.py +198 -0
- raddo-0.1.3/src/raddo/controllers/feedback_controller.py +95 -0
- raddo-0.1.3/src/raddo/controllers/mppi_controller.py +187 -0
- raddo-0.1.3/src/raddo/controllers/pid_controller.py +72 -0
- raddo-0.1.3/src/raddo/controllers/qp_controller.py +369 -0
- raddo-0.1.3/src/raddo/controllers/sqp_controller.py +383 -0
- raddo-0.1.3/src/raddo/controllers/tvlqr_controller.py +108 -0
- raddo-0.1.3/src/raddo/dynamics/__init__.py +7 -0
- raddo-0.1.3/src/raddo/dynamics/base_dynamics.py +213 -0
- raddo-0.1.3/src/raddo/dynamics/double_integrator_dynamics.py +93 -0
- raddo-0.1.3/src/raddo/dynamics/magnetic_field.py +208 -0
- raddo-0.1.3/src/raddo/dynamics/magnetorquer_dynamics.py +189 -0
- raddo-0.1.3/src/raddo/dynamics/orbit_dynamics.py +162 -0
- raddo-0.1.3/src/raddo/dynamics/planetary_params.py +164 -0
- raddo-0.1.3/src/raddo/dynamics/quadrotor_dynamics.py +163 -0
- raddo-0.1.3/src/raddo/dynamics/quaternion_functions.py +81 -0
- raddo-0.1.3/src/raddo/dynamics/spacecraft_dynamics.py +262 -0
- raddo-0.1.3/src/raddo/utils/__init__.py +12 -0
- raddo-0.1.3/src/raddo/utils/adaptation.py +78 -0
- raddo-0.1.3/src/raddo/utils/coord_transforms.py +148 -0
- raddo-0.1.3/src/raddo/utils/learned_model_implementation.py +161 -0
- raddo-0.1.3/src/raddo/utils/learning.py +459 -0
- raddo-0.1.3/src/raddo/utils/models.py +118 -0
- raddo-0.1.3/src/raddo/utils/plotting.py +674 -0
- raddo-0.1.3/src/raddo/utils/propagate.py +629 -0
- raddo-0.1.3/src/raddo/utils/save_df.py +92 -0
raddo-0.1.3/.gitignore
ADDED
raddo-0.1.3/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Patrick Schwartz
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
raddo-0.1.3/PKG-INFO
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: raddo
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: RApidly Adapting Data-Driven Opimization (RADDO). JAX-based trajectory generator with Moreau-based QP solver with an emphasis on adaptation and attitude dynamics
|
|
5
|
+
Project-URL: Homepage, https://github.com/JHU-ACEL/raddo
|
|
6
|
+
Author-email: Patrick Schwartz <pschwa24@jh.edu>
|
|
7
|
+
Maintainer-email: Patrick Schwartz <pschwa24@jh.edu>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Programming Language :: Python
|
|
11
|
+
Requires-Python: >=3.12
|
|
12
|
+
Requires-Dist: equinox>=0.13.8
|
|
13
|
+
Requires-Dist: jax>=0.11.2
|
|
14
|
+
Requires-Dist: moreau>=0.4.1
|
|
15
|
+
Requires-Dist: numpy>=2.5.3
|
|
16
|
+
Requires-Dist: optax>=0.2.8
|
|
17
|
+
Provides-Extra: cuda12
|
|
18
|
+
Requires-Dist: jax[cuda12]>=0.11.2; extra == 'cuda12'
|
|
19
|
+
Requires-Dist: moreau[cuda12]>=0.4.1; extra == 'cuda12'
|
|
20
|
+
Provides-Extra: cuda13
|
|
21
|
+
Requires-Dist: jax[cuda13]>=0.11.2; extra == 'cuda13'
|
|
22
|
+
Requires-Dist: moreau[cuda13]>=0.4.1; extra == 'cuda13'
|
|
23
|
+
Provides-Extra: extras
|
|
24
|
+
Requires-Dist: marimo>=0.24.2; extra == 'extras'
|
|
25
|
+
Requires-Dist: matplotlib>=3.11.2; extra == 'extras'
|
|
26
|
+
Requires-Dist: pandas>=3.0.6; extra == 'extras'
|
|
27
|
+
Requires-Dist: planetmagfields>=1.7.0; extra == 'extras'
|
|
28
|
+
Requires-Dist: seaborn>=0.13.2; extra == 'extras'
|
|
29
|
+
Requires-Dist: wandb>=0.30.0; extra == 'extras'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# Learning-Based Adaptive MPC for Magnetorquer-Only Satellite Attitude Control
|
|
33
|
+
<img width="867" height="492" alt="hero_white_background" src="https://github.com/user-attachments/assets/659210b3-bb81-446d-8291-b291ccb81eb3" />
|
|
34
|
+
|
|
35
|
+
## Prerequisites
|
|
36
|
+
1. [Docker](https://docker-curriculum.com/)
|
|
37
|
+
2. GPU Access
|
|
38
|
+
3. [Moreau](https://docs.moreau.so/index.html#) (requires license)
|
|
39
|
+
|
|
40
|
+
## Startup
|
|
41
|
+
1. In workstation's bash shell, in desired directory, clone this repo
|
|
42
|
+
```bash
|
|
43
|
+
git clone git@github.com:JHU-ACEL/uranus-mpc.git
|
|
44
|
+
```
|
|
45
|
+
2. In the directory you just cloned, follow the steps in `docker/README.md` to modify the `Dockerfile` to include your Moreau License Key and build the docker image.
|
|
46
|
+
4. To verify that the image built properly, run
|
|
47
|
+
```bash
|
|
48
|
+
docker images
|
|
49
|
+
```
|
|
50
|
+
4. To run a container, run
|
|
51
|
+
```bash
|
|
52
|
+
./docker/docker_run.sh <image_repository:tag> <PORT> # example: "./docker/docker_run.sh uranus-mpc:v1 8888"
|
|
53
|
+
```
|
|
54
|
+
5. To start marimo, run
|
|
55
|
+
```bash
|
|
56
|
+
marimo edit --headless --host 0.0.0.0 --port=$PORT
|
|
57
|
+
```
|
|
58
|
+
6. If you are accessing a workstation with a GPU virtually, you will need to port forward to your local machine. In your local command line, run
|
|
59
|
+
```bash
|
|
60
|
+
ssh -L localhost:${PORT}:localhost:${PORT} -N -f ${UID}@{remote} # ex: "ssh -L localhost:8888:localhost:8888 -N -f pschwa24@enceladus.wse.jhu.edu"
|
|
61
|
+
```
|
|
62
|
+
7. On your browser on your local machine you can go to URL given in marimo (e.g. https://0.0.0.0:8888) and copy and paste the access token to access marimo.
|
|
63
|
+
|
|
64
|
+
## Examples
|
|
65
|
+
- `Spacecraft_Control.py` demonstrates the full functionality of the library and controller with online adaptation.
|
|
66
|
+
- `B_field_Learning.py` shows the training pipeline for training the magnetic field models offline.
|
|
67
|
+
|
|
68
|
+
## Working with the library
|
|
69
|
+
The library is set-up to be fully compatible with JAX, and thus everything is parallelized and JIT-compatible. It makes use of [Equinox](https://docs.kidger.site/equinox/all-of-equinox/) to make this easy and set-up with Object-Oriented Programming.
|
|
70
|
+
|
|
71
|
+
### Base functions
|
|
72
|
+
First, set the `dynamics` class. The spacecraft attitude dynamics with magnetorquer-attitude control is initialized as follows:
|
|
73
|
+
```bash
|
|
74
|
+
spacecraft_dynamics = SpacecraftDynamics(mag_model=model_s,planet=planet)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Most of the primary functionality is built into the `TrajectoryGenerator` class, which is initialized by providing it with dynamics and a time-step.
|
|
78
|
+
```bash
|
|
79
|
+
system = TrajectoryGenerator(dynamics=spacecraft_dynamics, dt=dt)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
After initializing the class, you can generate a trajectory. If the only thing provided is the initial state, key, and number of steps, the initial states are just propagated according to the dynamics.
|
|
83
|
+
```bash
|
|
84
|
+
trajectory, controls = system.generate_trajectory(initial_state=initial_state, key=key, num_steps=num_steps)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Alternatively, you could provide a fixed control sequence that it will propagate.
|
|
88
|
+
```bash
|
|
89
|
+
trajectory, controls = system.generate_trajectory(initial_state=initial_state, key=key, num_steps=num_steps, control_sequence=control_sequence)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
If your dynamics require and external dynamics parameter (e.g. magnetic field values), then those must also be provided to the `external_dynamics_params` field. Additionally, a random disturbance force/torque is applied at each step if a standard deviation for it is provided.
|
|
93
|
+
```bash
|
|
94
|
+
trajectory, controls = system.generate_trajectory(initial_state=init_state, target_state=target_state, key=key1, external_dynamics_params=b_field_values, control_sequence=control_sequence, num_steps=num_steps, noise_std=noise_std_dyn)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
You can also propagate controlled trajectories. First, initialize the controllers
|
|
98
|
+
```bash
|
|
99
|
+
qp_controller = QPController(system, Q_qp, Qf_qp, R_qp, state_limits, control_limits, horizon_qp) # high_level_controller
|
|
100
|
+
fb_controller = FeedbackController(system,Q_fb,Qf_fb,R_fb,control_limits) # low_level_controller
|
|
101
|
+
```
|
|
102
|
+
and then provide them to the `generate_trajectory` function along with a target state and how frequently the `high_level_controller` should replan. The `high_level_controller` is called every `replan_freq` timesteps, and the `low_level_controller` is called every timestep and tracks the nominal trajectory produced by the `high_level_controller`. If no `low_level_controller` is provided, the nominal control inputs produced by the `high_level_controller` are just used at each timestep. If no `high_level_controller` is provided, then the `low_level_controlller` just works by itself trying to reach the target state provided.
|
|
103
|
+
```bash
|
|
104
|
+
trajectory, controls = system.generate_trajectory(initial_state=init_state, target_state=target_state, key=key, external_dynamics_params=b_field_values, high_level_controller=qp_controller, low_level_controller=fb_controller, replan_freq=replan_freq_qp, num_steps=num_steps, noise_std=noise_std_dyn)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
A full batch of trajectories can just as easily be generated. If an arrays of `batch_size` are provided, then it will use all of them, but if you only want to change some things for each trajectory (e.g. have the same initial state for all of them, but different target states), that works too. The following example just provides one initial state, but `batch_size` different target states and b field values. The noise always changes for each trajectory.
|
|
108
|
+
```bash
|
|
109
|
+
traj_batch, cntrl_batch = system.generate_trajectory_batch(initial_states=init_state, target_states=target_states, key=key, batch_size=batch_size, external_dynamics_params=b_batch, external_dynamics_params_est=None, high_level_controller=qp_controller, low_level_controller=fb_controller, replan_freq=replan_freq_qp, chunk_size=None, num_steps=num_steps_batch, noise_std=noise_std_dyn)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Using learned b-field models and online-adaptation
|
|
113
|
+
In order to use the learned b-field model in the controller instead of the true values, provide the cartesian coordinates in the PCI frame of the orbit to `external_dynamics_params_est`
|
|
114
|
+
Online adaptation is performed if the frequency that adaptation is performed `adapt_freq` and the size of the history buffer `history` are provided.
|
|
115
|
+
```bash
|
|
116
|
+
traj_adapt, cntrl_adapt = system_coarse.generate_trajectory(initial_state=init_state, target_state=target_state, key=key, external_dynamics_params=b, external_dynamics_params_est=orbit_xyz, high_level_controller=qp_controller, low_level_controller=fb_controller, replan_freq=replan_freq_qp, num_steps=num_steps, noise_std=noise_std_dyn, adapt_freq=adapt_freq_qp, history=history_qp)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Plotting
|
|
120
|
+
The trajectories for all states can be plotted using
|
|
121
|
+
```bash
|
|
122
|
+
system.plot_traj(trajectory, controls)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Multiple trajectories can be plotted for comparison, and you can provide additional arguments to plot the target state as a dotted line and include a legend.
|
|
126
|
+
```bash
|
|
127
|
+
system.plot_traj(jnp.array([traj_true, traj_full, traj_low, traj_adapt]), jnp.array([cntrl_true, cntrl_full, cntrl_low, cntrl_adapt]), target_state=target_state, legend=["Full-order", "Low-order", "Low-order w/ Adaptation"])
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
You can also plot the costs over time using
|
|
131
|
+
```bash
|
|
132
|
+
system.plot_costs(jnp.array([traj_true, traj_full, traj_low, traj_adapt]), target_state,legend=["True","Full", "Dipole", "Adapt"])
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
If you want to visualize statistics for a batch of trajectories, you can use
|
|
136
|
+
```bash
|
|
137
|
+
system.plot_costs(traj_batch, target_states, plot_stats=True)
|
|
138
|
+
```
|
|
139
|
+
and
|
|
140
|
+
```bash
|
|
141
|
+
system.plot_violin_and_bar(trajs_batch, target_states, angle_threshold=angle_threshold, omega_threshold=omega_threshold, angle_stability_tol=angle_tol, omega_stability_tol=omega_tol, tail_length=tail_length, verbose=True)
|
|
142
|
+
```
|
raddo-0.1.3/README.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Learning-Based Adaptive MPC for Magnetorquer-Only Satellite Attitude Control
|
|
2
|
+
<img width="867" height="492" alt="hero_white_background" src="https://github.com/user-attachments/assets/659210b3-bb81-446d-8291-b291ccb81eb3" />
|
|
3
|
+
|
|
4
|
+
## Prerequisites
|
|
5
|
+
1. [Docker](https://docker-curriculum.com/)
|
|
6
|
+
2. GPU Access
|
|
7
|
+
3. [Moreau](https://docs.moreau.so/index.html#) (requires license)
|
|
8
|
+
|
|
9
|
+
## Startup
|
|
10
|
+
1. In workstation's bash shell, in desired directory, clone this repo
|
|
11
|
+
```bash
|
|
12
|
+
git clone git@github.com:JHU-ACEL/uranus-mpc.git
|
|
13
|
+
```
|
|
14
|
+
2. In the directory you just cloned, follow the steps in `docker/README.md` to modify the `Dockerfile` to include your Moreau License Key and build the docker image.
|
|
15
|
+
4. To verify that the image built properly, run
|
|
16
|
+
```bash
|
|
17
|
+
docker images
|
|
18
|
+
```
|
|
19
|
+
4. To run a container, run
|
|
20
|
+
```bash
|
|
21
|
+
./docker/docker_run.sh <image_repository:tag> <PORT> # example: "./docker/docker_run.sh uranus-mpc:v1 8888"
|
|
22
|
+
```
|
|
23
|
+
5. To start marimo, run
|
|
24
|
+
```bash
|
|
25
|
+
marimo edit --headless --host 0.0.0.0 --port=$PORT
|
|
26
|
+
```
|
|
27
|
+
6. If you are accessing a workstation with a GPU virtually, you will need to port forward to your local machine. In your local command line, run
|
|
28
|
+
```bash
|
|
29
|
+
ssh -L localhost:${PORT}:localhost:${PORT} -N -f ${UID}@{remote} # ex: "ssh -L localhost:8888:localhost:8888 -N -f pschwa24@enceladus.wse.jhu.edu"
|
|
30
|
+
```
|
|
31
|
+
7. On your browser on your local machine you can go to URL given in marimo (e.g. https://0.0.0.0:8888) and copy and paste the access token to access marimo.
|
|
32
|
+
|
|
33
|
+
## Examples
|
|
34
|
+
- `Spacecraft_Control.py` demonstrates the full functionality of the library and controller with online adaptation.
|
|
35
|
+
- `B_field_Learning.py` shows the training pipeline for training the magnetic field models offline.
|
|
36
|
+
|
|
37
|
+
## Working with the library
|
|
38
|
+
The library is set-up to be fully compatible with JAX, and thus everything is parallelized and JIT-compatible. It makes use of [Equinox](https://docs.kidger.site/equinox/all-of-equinox/) to make this easy and set-up with Object-Oriented Programming.
|
|
39
|
+
|
|
40
|
+
### Base functions
|
|
41
|
+
First, set the `dynamics` class. The spacecraft attitude dynamics with magnetorquer-attitude control is initialized as follows:
|
|
42
|
+
```bash
|
|
43
|
+
spacecraft_dynamics = SpacecraftDynamics(mag_model=model_s,planet=planet)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Most of the primary functionality is built into the `TrajectoryGenerator` class, which is initialized by providing it with dynamics and a time-step.
|
|
47
|
+
```bash
|
|
48
|
+
system = TrajectoryGenerator(dynamics=spacecraft_dynamics, dt=dt)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
After initializing the class, you can generate a trajectory. If the only thing provided is the initial state, key, and number of steps, the initial states are just propagated according to the dynamics.
|
|
52
|
+
```bash
|
|
53
|
+
trajectory, controls = system.generate_trajectory(initial_state=initial_state, key=key, num_steps=num_steps)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Alternatively, you could provide a fixed control sequence that it will propagate.
|
|
57
|
+
```bash
|
|
58
|
+
trajectory, controls = system.generate_trajectory(initial_state=initial_state, key=key, num_steps=num_steps, control_sequence=control_sequence)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
If your dynamics require and external dynamics parameter (e.g. magnetic field values), then those must also be provided to the `external_dynamics_params` field. Additionally, a random disturbance force/torque is applied at each step if a standard deviation for it is provided.
|
|
62
|
+
```bash
|
|
63
|
+
trajectory, controls = system.generate_trajectory(initial_state=init_state, target_state=target_state, key=key1, external_dynamics_params=b_field_values, control_sequence=control_sequence, num_steps=num_steps, noise_std=noise_std_dyn)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
You can also propagate controlled trajectories. First, initialize the controllers
|
|
67
|
+
```bash
|
|
68
|
+
qp_controller = QPController(system, Q_qp, Qf_qp, R_qp, state_limits, control_limits, horizon_qp) # high_level_controller
|
|
69
|
+
fb_controller = FeedbackController(system,Q_fb,Qf_fb,R_fb,control_limits) # low_level_controller
|
|
70
|
+
```
|
|
71
|
+
and then provide them to the `generate_trajectory` function along with a target state and how frequently the `high_level_controller` should replan. The `high_level_controller` is called every `replan_freq` timesteps, and the `low_level_controller` is called every timestep and tracks the nominal trajectory produced by the `high_level_controller`. If no `low_level_controller` is provided, the nominal control inputs produced by the `high_level_controller` are just used at each timestep. If no `high_level_controller` is provided, then the `low_level_controlller` just works by itself trying to reach the target state provided.
|
|
72
|
+
```bash
|
|
73
|
+
trajectory, controls = system.generate_trajectory(initial_state=init_state, target_state=target_state, key=key, external_dynamics_params=b_field_values, high_level_controller=qp_controller, low_level_controller=fb_controller, replan_freq=replan_freq_qp, num_steps=num_steps, noise_std=noise_std_dyn)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
A full batch of trajectories can just as easily be generated. If an arrays of `batch_size` are provided, then it will use all of them, but if you only want to change some things for each trajectory (e.g. have the same initial state for all of them, but different target states), that works too. The following example just provides one initial state, but `batch_size` different target states and b field values. The noise always changes for each trajectory.
|
|
77
|
+
```bash
|
|
78
|
+
traj_batch, cntrl_batch = system.generate_trajectory_batch(initial_states=init_state, target_states=target_states, key=key, batch_size=batch_size, external_dynamics_params=b_batch, external_dynamics_params_est=None, high_level_controller=qp_controller, low_level_controller=fb_controller, replan_freq=replan_freq_qp, chunk_size=None, num_steps=num_steps_batch, noise_std=noise_std_dyn)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Using learned b-field models and online-adaptation
|
|
82
|
+
In order to use the learned b-field model in the controller instead of the true values, provide the cartesian coordinates in the PCI frame of the orbit to `external_dynamics_params_est`
|
|
83
|
+
Online adaptation is performed if the frequency that adaptation is performed `adapt_freq` and the size of the history buffer `history` are provided.
|
|
84
|
+
```bash
|
|
85
|
+
traj_adapt, cntrl_adapt = system_coarse.generate_trajectory(initial_state=init_state, target_state=target_state, key=key, external_dynamics_params=b, external_dynamics_params_est=orbit_xyz, high_level_controller=qp_controller, low_level_controller=fb_controller, replan_freq=replan_freq_qp, num_steps=num_steps, noise_std=noise_std_dyn, adapt_freq=adapt_freq_qp, history=history_qp)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Plotting
|
|
89
|
+
The trajectories for all states can be plotted using
|
|
90
|
+
```bash
|
|
91
|
+
system.plot_traj(trajectory, controls)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Multiple trajectories can be plotted for comparison, and you can provide additional arguments to plot the target state as a dotted line and include a legend.
|
|
95
|
+
```bash
|
|
96
|
+
system.plot_traj(jnp.array([traj_true, traj_full, traj_low, traj_adapt]), jnp.array([cntrl_true, cntrl_full, cntrl_low, cntrl_adapt]), target_state=target_state, legend=["Full-order", "Low-order", "Low-order w/ Adaptation"])
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
You can also plot the costs over time using
|
|
100
|
+
```bash
|
|
101
|
+
system.plot_costs(jnp.array([traj_true, traj_full, traj_low, traj_adapt]), target_state,legend=["True","Full", "Dipole", "Adapt"])
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
If you want to visualize statistics for a batch of trajectories, you can use
|
|
105
|
+
```bash
|
|
106
|
+
system.plot_costs(traj_batch, target_states, plot_stats=True)
|
|
107
|
+
```
|
|
108
|
+
and
|
|
109
|
+
```bash
|
|
110
|
+
system.plot_violin_and_bar(trajs_batch, target_states, angle_threshold=angle_threshold, omega_threshold=omega_threshold, angle_stability_tol=angle_tol, omega_stability_tol=omega_tol, tail_length=tail_length, verbose=True)
|
|
111
|
+
```
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Docker
|
|
2
|
+
|
|
3
|
+
### Modify Dockerfile
|
|
4
|
+
You must modify the docker file to include your Moreau License Key.
|
|
5
|
+
|
|
6
|
+
### Build the Docker Container
|
|
7
|
+
Use the `docker_build.sh` script to build the Docker image:
|
|
8
|
+
```bash
|
|
9
|
+
./docker/docker_build.sh docker/Dockerfile uranus-mpc:v1
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
**Arguments:**
|
|
13
|
+
- `dockerfile`: Path to the Dockerfile (e.g., `docker/Dockerfile`)
|
|
14
|
+
- `tag_name`: Docker image tag (e.g., `uranus-mpc:v1`)
|
|
15
|
+
|
|
16
|
+
The build script automatically:
|
|
17
|
+
- Sets the user ID and group ID to match your current user
|
|
18
|
+
- Sets the username to your current username
|
|
19
|
+
- Builds the image with the specified tag
|
|
20
|
+
|
|
21
|
+
### Run the Docker Container
|
|
22
|
+
Use the `docker_run.sh` script to run the Docker container:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
./docker/docker_run.sh uranus-mpc:v1
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Arguments:**
|
|
29
|
+
- `tag_name`: The Docker image tag to run (e.g., `uranus-mpc:v1`)
|
|
30
|
+
- `ssh_port` (optional): The port forwarding between host machine and Docker container (e.g., `8888`)
|
|
31
|
+
|
|
32
|
+
### Run Jupyter Lab (from inside the container):
|
|
33
|
+
```bash
|
|
34
|
+
jupyter lab --ip=0.0.0.0 --port=$PORT --no-browser --allow-root
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Run marimo (from inside the container):
|
|
38
|
+
```bash
|
|
39
|
+
marimo edit --headless --host 0.0.0.0 --port=$PORT
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Use SSH port forwarding to run a notebook remotely
|
|
43
|
+
```bash
|
|
44
|
+
ssh -L localhost:${PORT}:localhost:${PORT} -N -f ${UID}@{remote}
|
|
45
|
+
```
|
|
46
|
+
where `${PORT}` is the port designated when you `docker run` and `${UID}@{remote}` is the remote instance (e.g., `cauligi@enceladus.wse.jhu`).
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.27"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "raddo"
|
|
7
|
+
version = "0.1.3"
|
|
8
|
+
dependencies = [
|
|
9
|
+
"numpy>=2.5.3",
|
|
10
|
+
"jax>=0.11.2",
|
|
11
|
+
"equinox>=0.13.8",
|
|
12
|
+
"moreau>=0.4.1",
|
|
13
|
+
"optax>=0.2.8",
|
|
14
|
+
]
|
|
15
|
+
requires-python = ">=3.12"
|
|
16
|
+
authors = [
|
|
17
|
+
{name = "Patrick Schwartz", email = "pschwa24@jh.edu"},
|
|
18
|
+
]
|
|
19
|
+
maintainers = [
|
|
20
|
+
{name = "Patrick Schwartz", email = "pschwa24@jh.edu"}
|
|
21
|
+
]
|
|
22
|
+
description = "RApidly Adapting Data-Driven Opimization (RADDO). JAX-based trajectory generator with Moreau-based QP solver with an emphasis on adaptation and attitude dynamics"
|
|
23
|
+
readme = "README.md"
|
|
24
|
+
classifiers = [
|
|
25
|
+
"Programming Language :: Python"
|
|
26
|
+
]
|
|
27
|
+
license = "MIT"
|
|
28
|
+
license-files = ["LICEN[CS]E*"]
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Homepage = "https://github.com/JHU-ACEL/raddo"
|
|
32
|
+
|
|
33
|
+
[project.optional-dependencies]
|
|
34
|
+
cuda12 = [ "jax[cuda12]>=0.11.2", "moreau[cuda12]>=0.4.1"]
|
|
35
|
+
cuda13 = [ "jax[cuda13]>=0.11.2", "moreau[cuda13]>=0.4.1"]
|
|
36
|
+
extras =[
|
|
37
|
+
"matplotlib>=3.11.2",
|
|
38
|
+
"pandas>=3.0.6",
|
|
39
|
+
"seaborn>=0.13.2",
|
|
40
|
+
"marimo>=0.24.2",
|
|
41
|
+
"wandb>=0.30.0",
|
|
42
|
+
"planetMagFields>=1.7.0"
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
[tool.hatch.build.targets.sdist]
|
|
46
|
+
include = [
|
|
47
|
+
"src/raddo",
|
|
48
|
+
"README.md",
|
|
49
|
+
"LICENSE*",
|
|
50
|
+
"pyproject.toml",
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
[tool.hatch.build.targets.wheel]
|
|
54
|
+
packages = ["src/raddo"]
|
|
File without changes
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
from .base_controller import Controller
|
|
2
|
+
from .cem_controller import CEMController
|
|
3
|
+
from .feedback_controller import FeedbackController
|
|
4
|
+
from .mppi_controller import MPPIController
|
|
5
|
+
from .qp_controller import QPController
|
|
6
|
+
from .sqp_controller import SQPController
|
|
7
|
+
from .tvlqr_controller import TVLQRController
|