Skip to content

Commit 10db1e4

Browse files
authored
Merge pull request #83 from JayshKhan/master
Feature: Added Dead Reckoning (DR) Module
2 parents cf7250c + 8bec291 commit 10db1e4

3 files changed

Lines changed: 635 additions & 0 deletions

File tree

examples/dis_dead_reckoning.py

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
#! /usr/bin/python
2+
3+
"""
4+
Example of using the Dead Reckoning module to extrapolate entity position.
5+
6+
This script simulates receiving an EntityStatePdu with velocity and acceleration,
7+
and then uses the DeadReckoning module to predict the entity's position
8+
over a period of time.
9+
"""
10+
11+
import time
12+
import numpy as np
13+
from opendis.dis7 import EntityStatePdu, Vector3Float
14+
from opendis import DeadReckoning
15+
16+
def run_demo():
17+
# 1. Create a mock PDU (as if received from the network)
18+
pdu = EntityStatePdu()
19+
20+
# Initial State (t=0)
21+
# Position: Origin (0, 0, 0)
22+
pdu.entityLocation.x = 0.0
23+
pdu.entityLocation.y = 0.0
24+
pdu.entityLocation.z = 0.0
25+
26+
# Velocity: 10 m/s in X direction
27+
pdu.entityLinearVelocity.x = 10.0
28+
pdu.entityLinearVelocity.y = 0.0
29+
pdu.entityLinearVelocity.z = 0.0
30+
31+
# Acceleration: 1 m/s^2 in X direction
32+
pdu.deadReckoningParameters.entityLinearAcceleration.x = 1.0
33+
pdu.deadReckoningParameters.entityLinearAcceleration.y = 0.0
34+
pdu.deadReckoningParameters.entityLinearAcceleration.z = 0.0
35+
36+
# Orientation: Facing East (0, 0, 0)
37+
pdu.entityOrientation.psi = 0.0
38+
pdu.entityOrientation.theta = 0.0
39+
pdu.entityOrientation.phi = 0.0
40+
41+
# Angular Velocity: None
42+
pdu.deadReckoningParameters.entityAngularVelocity.x = 0.0
43+
pdu.deadReckoningParameters.entityAngularVelocity.y = 0.0
44+
pdu.deadReckoningParameters.entityAngularVelocity.z = 0.0
45+
46+
# Extract numpy arrays for the DR function
47+
# Note: With the new API, we can pass lists or tuples directly if we wanted to,
48+
# but since we are extracting from PDU objects, we'll stick with what we have or use lists.
49+
# The API will convert them to numpy arrays internally.
50+
51+
initial_pos = [pdu.entityLocation.x, pdu.entityLocation.y, pdu.entityLocation.z]
52+
velocity = [pdu.entityLinearVelocity.x, pdu.entityLinearVelocity.y, pdu.entityLinearVelocity.z]
53+
acceleration = [
54+
pdu.deadReckoningParameters.entityLinearAcceleration.x,
55+
pdu.deadReckoningParameters.entityLinearAcceleration.y,
56+
pdu.deadReckoningParameters.entityLinearAcceleration.z
57+
]
58+
orientation = [pdu.entityOrientation.psi, pdu.entityOrientation.theta, pdu.entityOrientation.phi]
59+
angular_velocity = [
60+
pdu.deadReckoningParameters.entityAngularVelocity.x,
61+
pdu.deadReckoningParameters.entityAngularVelocity.y,
62+
pdu.deadReckoningParameters.entityAngularVelocity.z
63+
]
64+
65+
print("--- Dead Reckoning Demonstration ---")
66+
print(f"Initial Position: {initial_pos}")
67+
print(f"Velocity: {velocity} m/s")
68+
print(f"Acceleration: {acceleration} m/s^2")
69+
print("Simulating 5 seconds of movement using RVW (Rotation, Velocity, World) algorithm...\n")
70+
71+
# 2. Simulate extrapolation loop
72+
start_time = time.time()
73+
simulation_duration = 5.0 # seconds
74+
75+
# We will simulate 'frames'
76+
current_sim_time = 0.0
77+
step = 0.5 # Update every 0.5 seconds
78+
79+
while current_sim_time <= simulation_duration:
80+
# Calculate new position using RVW algorithm
81+
# Position = P0 + V0*t + 0.5*A0*t^2
82+
new_pos, new_ori = DeadReckoning.drm_rvw(
83+
initial_pos,
84+
velocity,
85+
acceleration,
86+
current_sim_time,
87+
orientation,
88+
angular_velocity
89+
)
90+
91+
print(f"Time: {current_sim_time:.1f}s | Extrapolated Pos: {new_pos}")
92+
93+
current_sim_time += step
94+
# time.sleep(0.1) # Uncomment to run in real-time
95+
96+
print("\n--- End of Demonstration ---")
97+
print("Notice how the X position increases quadratically due to acceleration.")
98+
print("T=0: 0.0")
99+
print("T=1: 10*1 + 0.5*1*1^2 = 10.5")
100+
print("T=2: 10*2 + 0.5*1*2^2 = 22.0")
101+
# 3. Demonstrate integration with RangeCoordinates (GPS)
102+
# The Dead Reckoning module returns ECEF coordinates (Earth-Centered, Earth-Fixed).
103+
# Usually, users want Latitude/Longitude/Altitude.
104+
from opendis.RangeCoordinates import GPS, deg2rad, rad2deg
105+
106+
gps = GPS()
107+
108+
print("\n--- Integration Verification ---")
109+
print("Converting extrapolated ECEF coordinates to Lat/Lon/Alt using opendis.RangeCoordinates...")
110+
111+
# Let's take the final position from the simulation
112+
final_pos_ecef = (new_pos[0], new_pos[1], new_pos[2])
113+
114+
# Convert ECEF to LLA
115+
# Note: Our example started at 0,0,0 which is the center of the earth (invalid for LLA usually),
116+
# but let's assume the initial position was actually on the surface for this part of the demo
117+
# or just show the conversion call structure.
118+
119+
# To make this realistic, let's restart with a real-world location.
120+
# Monterey, CA: 36.6 N, 121.9 W
121+
print("\nRestarting simulation at Monterey, CA...")
122+
start_lat = 36.6
123+
start_lon = -121.9
124+
start_alt = 100.0 # meters
125+
126+
start_ecef = gps.lla2ecef((start_lat, start_lon, start_alt))
127+
print(f"Start LLA: ({start_lat}, {start_lon}, {start_alt})")
128+
print(f"Start ECEF: {start_ecef}")
129+
130+
# Move East (Velocity in Y in ECEF is roughly East at this location? No, it's complex in ECEF.)
131+
# For simplicity, let's just add the displacement we calculated earlier to this valid ECEF point.
132+
# This isn't physically perfect (earth is curved), but demonstrates the API integration.
133+
134+
displacement = new_pos # The 62.5m displacement from the previous run
135+
final_ecef_real = (
136+
start_ecef[0] + displacement[0],
137+
start_ecef[1] + displacement[1],
138+
start_ecef[2] + displacement[2]
139+
)
140+
141+
final_lla = gps.ecef2lla(final_ecef_real)
142+
print(f"Final ECEF: {final_ecef_real}")
143+
print(f"Final LLA: ({final_lla[0]:.6f}, {final_lla[1]:.6f}, {final_lla[2]:.2f})")
144+
145+
print("\nIntegration Successful: Dead Reckoning output was successfully fed into RangeCoordinates.")
146+
147+
if __name__ == "__main__":
148+
run_demo()

0 commit comments

Comments
 (0)