Skip to content

Commit a6dda6a

Browse files
authored
Merge pull request #9 from ARRC-Rocket/enh/fix_pytest
Fix pytest
2 parents 7d1843a + 1d48998 commit a6dda6a

6 files changed

Lines changed: 45 additions & 79 deletions

File tree

README.md

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,18 @@
33
ActiveRocketPy is the enhanced version of [RocketPy](https://github.com/RocketPy-Team/RocketPy), a powerful Python package for simulating the trajectories of high-power rockets. This fork introduces a range of active control and guidance, navigation, and control (GNC) features.
44

55
## Main features (ActiveRocketPy)
6-
1. **Thrust Vector Control (TVC)**
7-
- Implementation of TVC control class
8-
- Feed X & Y gimbal angles through a control function
9-
- Actuator dynamics and limits for realistic TVC simulations (WIP)
10-
11-
2. **Roll Control**
12-
- Implementation of roll control class
13-
- Feed ideal roll torque through a control function
14-
- Actuator dynamics and limits for realistic roll control simulations (WIP)
15-
16-
3. **Throttle Control**
17-
- Implementation of throttle control class
18-
- Feed throttle percentage through a control function
19-
- Actuator dynamics and limits for realistic throttle control simulations (WIP)
20-
21-
4. **Step simulation**
6+
7+
1. **Actuator Classes for active control**
8+
- Actuator dynamics and limits for realistic active flight simulations
9+
- **Thrust Vector Control (TVC)**
10+
- Feed X & Y gimbal angles through a control function
11+
- **Roll Control**
12+
- Feed ideal roll torque through a control function
13+
- **Throttle Control**
14+
- Feed throttle percentage through a control function
15+
- Known limitation: The mass properties are pre-calculated before flight according to max flow rate and burn time. Throttle commands does not affect the change of the mass properties in-flight. It is equivalent to throttling the Isp of rocket engine while the flow rate remains constant. The engine is cut off when burn time is reached
16+
17+
2. **Step simulation**
2218
- Step through the simulation one time step at a time
2319
- Update control inputs and step simulations in loop
2420

@@ -76,7 +72,6 @@ Check out documentation details using the links below:
7672
- [RocketPy Technical Documentation](https://docs.rocketpy.org/en/latest/technical/index.html)
7773
- [RocketPy Flight Examples](https://docs.rocketpy.org/en/latest/examples/index.html)
7874

79-
8075
<br>
8176

8277
# Getting Started
@@ -100,7 +95,6 @@ pip install -r requirements-tests.txt # install test/dev requirements
10095
10196
ActiveRocketPy is forked and maintained by [ZuoRen Chen](https://github.com/zuorenchen), along with the team from [Advanced Rocket Research Center (ARRC)](https://github.com/ARRC-Rocket).
10297

103-
10498
## Citation
10599

106100
If you run ActiveRocketPy in your research, please consider citing:
@@ -114,4 +108,5 @@ If you run ActiveRocketPy in your research, please consider citing:
114108
url = {https://github.com/ARRC-Rocket/ActiveRocketPy}
115109
}
116110
```
117-
To cite RocketPy, please check its repository for the latest citation information: [RocketPy](https://github.com/RocketPy-Team/RocketPy)
111+
112+
To cite RocketPy, please check its repository for the latest citation information: [RocketPy](https://github.com/RocketPy-Team/RocketPy)

rocketpy/rocket/aero_surface/linear_generic_surface.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ def __init__(
169169
# Populate the coefficients from the list of constants if they are not defined
170170
if coefficients is None:
171171
coefficients = self._get_default_coefficients()
172-
if coefficient_constants is not None:
172+
if coefficient_constants:
173173
assert len(coefficient_constants) == len(
174174
self._get_default_coefficients()
175175
), (

rocketpy/utilities.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,7 @@ def save_to_rpy(flight: Flight, filename: str, include_outputs=False):
626626
file = Path(filename).with_suffix(".rpy")
627627

628628
with open(file, "w") as f:
629-
data = {"date": str(date.today()), "version": version("rocketpy")}
629+
data = {"date": str(date.today()), "version": version("activerocketpy")}
630630
data["simulation"] = flight
631631
json.dump(
632632
data,
@@ -650,7 +650,7 @@ def load_from_rpy(filename: str, resimulate=False):
650650
651651
Returns
652652
-------
653-
rocketpy.Flight
653+
activerocketpy.Flight
654654
Flight object containing simulation information from the .rpy file
655655
"""
656656
ext = os.path.splitext(os.path.basename(filename))[1]
@@ -660,12 +660,12 @@ def load_from_rpy(filename: str, resimulate=False):
660660
with open(filename, "r") as f:
661661
data = json.load(f)
662662
if packaging_version.parse(data["version"]) > packaging_version.parse(
663-
version("rocketpy")
663+
version("activerocketpy")
664664
):
665665
warnings.warn(
666666
"The file was saved in an updated version of",
667-
f"RocketPy (v{data['version']}), the current",
668-
f"imported module is v{version('rocketpy')}",
667+
f"ActiveRocketPy (v{data['version']}), the current",
668+
f"imported module is v{version('activerocketpy')}",
669669
)
670670
simulation = json.dumps(data["simulation"])
671671
flight = json.loads(simulation, cls=RocketPyDecoder, resimulate=resimulate)

tests/integration/test_sensor.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,19 @@ def test_barometer(self):
8282
def test_gnss_receiver(self):
8383
"""Test an ideal GnssReceiver."""
8484
gnss = self.flight.rocket.sensors[4].component
85-
time, latitude, longitude, altitude = zip(*gnss.measured_data)
86-
sim_latitude = self.flight.latitude(time)
87-
sim_longitude = self.flight.longitude(time)
88-
sim_altitude = self.flight.altitude(time)
89-
assert np.allclose(np.array(latitude), sim_latitude, atol=1e-12)
90-
assert np.allclose(np.array(longitude), sim_longitude, atol=1e-12)
91-
assert np.allclose(np.array(altitude), sim_altitude, atol=1e-12)
85+
time, x, y, z, vx, vy, vz = zip(*gnss.measured_data)
86+
sim_x = self.flight.x(time)
87+
sim_y = self.flight.y(time)
88+
sim_z = self.flight.z(time)
89+
sim_vx = self.flight.vx(time)
90+
sim_vy = self.flight.vy(time)
91+
sim_vz = self.flight.vz(time)
92+
assert np.allclose(np.array(x), sim_x, atol=1e-12)
93+
assert np.allclose(np.array(y), sim_y, atol=1e-12)
94+
assert np.allclose(np.array(z), sim_z, atol=1e-12)
95+
assert np.allclose(np.array(vx), sim_vx, atol=1e-12)
96+
assert np.allclose(np.array(vy), sim_vy, atol=1e-12)
97+
assert np.allclose(np.array(vz), sim_vz, atol=1e-12)
9298

9399

94100
@pytest.mark.parametrize("plane", ["xz", "yz"])

tests/unit/sensors/test_sensor.py

Lines changed: 10 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -381,70 +381,35 @@ def test_noisy_barometer(noisy_barometer, example_plain_env):
381381

382382
def test_noisy_gnss(noisy_gnss, example_plain_env):
383383
"""Test the measure method of the GnssReceiver class. Checks if saved
384-
measurement is (latitude, longitude, altitude) and if measured_data is [(t, (latitude, longitude, altitude)), ...]
384+
measurement is (x, y, z, vx, vy, vz) and if measured_data is [(t, x, y, z, vx, vy, vz), ...]
385385
"""
386386
# expected measurement without noise
387387
relative_position = Vector([0.4, 0.4, 1])
388-
lat, lon = example_plain_env.latitude, example_plain_env.longitude
389-
earth_radius = example_plain_env.earth_radius
390388
x, y, z = (Matrix.transformation(U[6:10]) @ relative_position) + Vector(U[0:3])
391-
drift = (x**2 + y**2) ** 0.5
392-
bearing = (2 * np.pi - np.arctan2(-x, y)) * (180 / np.pi)
393-
latitude = np.degrees(
394-
np.arcsin(
395-
np.sin(np.radians(lat)) * np.cos(drift / earth_radius)
396-
+ np.cos(np.radians(lat))
397-
* np.sin(drift / earth_radius)
398-
* np.cos(np.radians(bearing))
399-
)
400-
)
401-
longitude = np.degrees(
402-
np.radians(lon)
403-
+ np.arctan2(
404-
np.sin(np.radians(bearing))
405-
* np.sin(drift / earth_radius)
406-
* np.cos(np.radians(lat)),
407-
np.cos(drift / earth_radius)
408-
- np.sin(np.radians(lat)) * np.sin(np.radians(latitude)),
409-
)
410-
)
411-
altitude = z
389+
vx, vy, vz = (
390+
Matrix.transformation(U[6:10])
391+
@ Vector.cross(Vector(U[10:13]), relative_position)
392+
) + Vector(U[3:6])
412393

413394
noisy_gnss.measure(
414395
time=TIME,
415396
u=U,
416397
relative_position=relative_position,
417398
environment=example_plain_env,
418399
)
419-
assert noisy_gnss.measurement == approx([latitude, longitude, altitude], abs=3.2)
420-
assert len(noisy_gnss.measurement) == 3
421-
assert noisy_gnss.measured_data[0][1:] == approx(
422-
[latitude, longitude, altitude], abs=3.2
423-
)
400+
assert noisy_gnss.measurement == approx([x, y, z, vx, vy, vz], abs=3.0)
401+
assert len(noisy_gnss.measurement) == 6
402+
assert noisy_gnss.measured_data[0][1:] == approx([x, y, z, vx, vy, vz], abs=3.0)
424403
assert noisy_gnss.measured_data[0][0] == TIME
425404

426-
# check last measurement considering noise error bounds
427-
noisy_gnss.measure(
428-
time=TIME,
429-
u=U,
430-
relative_position=relative_position,
431-
environment=example_plain_env,
432-
)
433-
assert noisy_gnss.measurement == approx([latitude, longitude, altitude], abs=3.2)
434-
assert len(noisy_gnss.measurement) == 3
435-
assert noisy_gnss.measured_data[1][1:] == approx(
436-
[latitude, longitude, altitude], abs=3.2
437-
)
438-
assert noisy_gnss.measured_data[1][0] == TIME
439-
440405

441406
@pytest.mark.parametrize(
442407
"sensor, file_format, expected_header",
443408
[
444409
("ideal_accelerometer", "csv", "t,ax,ay,az\n"),
445410
("ideal_gyroscope", "csv", "t,wx,wy,wz\n"),
446411
("ideal_barometer", "csv", "t,pressure\n"),
447-
("ideal_gnss", "csv", "t,latitude,longitude,altitude\n"),
412+
("ideal_gnss", "csv", "t,x,y,z,vx,vy,vz\n"),
448413
],
449414
)
450415
def test_export_data_csv(
@@ -485,7 +450,7 @@ def test_export_data_csv(
485450
("ideal_accelerometer", "json", ("ax", "ay", "az")),
486451
("ideal_gyroscope", "json", ("wx", "wy", "wz")),
487452
("ideal_barometer", "json", ("pressure",)),
488-
("ideal_gnss", "json", ("latitude", "longitude", "altitude")),
453+
("ideal_gnss", "json", ("x", "y", "z", "vx", "vy", "vz")),
489454
],
490455
)
491456
def test_export_data_json(

tests/unit/simulation/test_flight.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ def test_export_sensor_data(flight_calisto_with_sensors):
210210
@pytest.mark.parametrize(
211211
"flight_time, expected_values",
212212
[
213-
("t_initial", (0.25886, -0.649623, 0)),
213+
("t_initial", (0.05072660158631715, -0.12730092240875748, 0)),
214214
("out_of_rail_time", (0.792028, -1.987634, 0)),
215215
("apogee_time", (-0.509420, -0.732933, -2.089120e-14)),
216216
("t_final", (0, 0, 0)),
@@ -249,7 +249,7 @@ def test_aerodynamic_moments(flight_calisto_custom_wind, flight_time, expected_v
249249
@pytest.mark.parametrize(
250250
"flight_time, expected_values",
251251
[
252-
("t_initial", (1.654150, 0.659142, -0.067103)),
252+
("t_initial", (0.32414923451082056, 0.12916629952407094, -0.067103)),
253253
("out_of_rail_time", (5.052628, 2.013361, -1.75370)),
254254
("apogee_time", (2.321838, -1.613641, -0.962108)),
255255
("t_final", (-0.019802, 0.012030, 159.051604)),

0 commit comments

Comments
 (0)