Skip to content

Commit 3235fb9

Browse files
authored
Adds basic hitl module (#83)
* Adds basic hitl module * Fixes unused variable issue * Adds more clear create method naming * Fixes hitl submodules create and init methods
1 parent b66262e commit 3235fb9

File tree

4 files changed

+141
-0
lines changed

4 files changed

+141
-0
lines changed

modules/hitl/__init__.py

Whitespace-only changes.

modules/hitl/camera_emulator.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""
2+
Emulates camera input to PI.
3+
"""
4+
5+
6+
class CameraEmulator:
7+
"""
8+
Setup for camera emulator.
9+
"""
10+
11+
__create_key = object()
12+
13+
@classmethod
14+
def create(cls, images_path: str) -> "tuple[True, CameraEmulator] | tuple[False, None]":
15+
"""
16+
Setup camera emulator.
17+
18+
Args:
19+
images_path: Path to the directory containing images for the camera emulator. Cycles through these images to simulate camera input (every 1 second).
20+
21+
Returns:
22+
Success, CameraEmulator instance.
23+
"""
24+
25+
if not isinstance(images_path, str):
26+
return False, None
27+
28+
return True, CameraEmulator(cls.__create_key, images_path)
29+
30+
def __init__(self, class_private_create_key: object, images_path: str) -> None:
31+
"""
32+
Private constructor, use create() method.
33+
"""
34+
assert class_private_create_key is CameraEmulator.__create_key, "Use create() method"
35+
36+
self._images_path = images_path

modules/hitl/hitl_base.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
"""
2+
Setup for HITL modules.
3+
"""
4+
5+
from modules.mavlink.flight_controller import FlightController
6+
7+
from modules.hitl.position_emulator import PositionEmulator
8+
from modules.hitl.camera_emulator import CameraEmulator
9+
10+
11+
class HITL:
12+
"""
13+
Hardware In The Loop (HITL) setup for emulating drone hardware.
14+
Provides a way to emulate the drone's position and camera input
15+
for testing purposes without needing actual hardware.
16+
"""
17+
18+
__create_key = object()
19+
20+
@classmethod
21+
def create(
22+
cls, drone: FlightController, camera_module: bool, images_path: str | None = None
23+
) -> "tuple[True, HITL] | tuple[False, None]":
24+
"""
25+
Factory method to create a HITL instance.
26+
27+
Args:
28+
drone: The FlightController instance for the drone.
29+
camera_module: Boolean indicating if the camera module is enabled.
30+
images_path: Optional path to the images directory for the camera emulator.
31+
32+
Returns:
33+
Success, HITL instance | None.
34+
"""
35+
if not isinstance(drone, FlightController):
36+
return False, None
37+
38+
result, position_emulator = PositionEmulator.create(drone)
39+
if not result:
40+
return False, None
41+
42+
if camera_module:
43+
result, camera_emulator = CameraEmulator.create(images_path)
44+
if not result:
45+
return False, None
46+
47+
hitl = HITL(
48+
cls.__create_key, drone, position_emulator, camera_emulator if camera_module else None
49+
)
50+
51+
return True, hitl
52+
53+
def __init__(
54+
self,
55+
class_private_create_key: object,
56+
drone: FlightController,
57+
position_emulator: "PositionEmulator",
58+
camera_emulator: "CameraEmulator | None" = None,
59+
) -> None:
60+
"""
61+
Private constructor, use create() method.
62+
"""
63+
assert class_private_create_key is HITL.__create_key, "Use create() method"
64+
65+
self.drone = drone
66+
67+
self.position_emulator = position_emulator
68+
self.camera_emulator = camera_emulator

modules/hitl/position_emulator.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"""
2+
Emulates position and attitude to Pixhawk.
3+
"""
4+
5+
from modules.mavlink.flight_controller import FlightController
6+
7+
8+
class PositionEmulator:
9+
"""
10+
Setup for position emulator.
11+
"""
12+
13+
__create_key = object()
14+
15+
@classmethod
16+
def create(
17+
cls, drone: FlightController
18+
) -> "tuple[True, PositionEmulator] | tuple[False, None]":
19+
"""
20+
Setup position emulator.
21+
22+
Returns:
23+
Success, PositionEmulator instance.
24+
"""
25+
26+
if not isinstance(drone, FlightController):
27+
return False, None
28+
29+
return True, PositionEmulator(cls.__create_key, drone)
30+
31+
def __init__(self, class_private_create_key: object, drone: FlightController) -> None:
32+
"""
33+
Private constructor, use create() method.
34+
"""
35+
assert class_private_create_key is PositionEmulator.__create_key, "Use create() method"
36+
37+
self._drone = drone

0 commit comments

Comments
 (0)