-
Notifications
You must be signed in to change notification settings - Fork 8
hitl emulator integration test #88
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 17 commits
9060698
5af546e
7670062
2bf98af
0f606b1
af59f0f
0cb60ab
b2af852
c0d4331
da74d86
a25cbc9
528dbd4
68686d5
11ae5ba
bf6924e
a6fed7f
37c30bb
aaae816
f19b1f9
42d3395
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -319,6 +319,23 @@ def get_odometry(self) -> "tuple[bool, drone_odometry_global.DroneOdometryGlobal | |
|
|
||
| return True, odometry_data | ||
|
|
||
| def get_location(self) -> "tuple[bool, tuple[float, float, float] | None]": | ||
| """Return (lat, lon, alt) if available via the drone, otherwise (False, None).""" | ||
| try: | ||
| loc = self.drone.location | ||
| except Exception: # pylint: disable=broad-except | ||
| print("HITL get_location error") | ||
|
||
| return False, None | ||
|
|
||
| if loc is None or loc.global_frame is None: | ||
| return False, None | ||
|
|
||
| gf = loc.global_frame | ||
| if gf.lat is None or gf.lon is None or gf.alt is None: | ||
| return False, None | ||
|
|
||
| return True, (gf.lat, gf.lon, gf.alt) | ||
|
|
||
| def get_home_position( | ||
| self, timeout: float | ||
| ) -> "tuple[bool, position_global.PositionGlobal | None]": | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,129 @@ | ||
| """ | ||
| HITL Test - GPS + Camera Feed Verification | ||
|
|
||
| """ | ||
|
|
||
| import cv2 | ||
| import os | ||
| import time | ||
|
|
||
| from modules.mavlink import flight_controller | ||
|
|
||
|
|
||
| # Physical connection to Pixhawk: /dev/ttyAMA0 | ||
| # Simulated connection to Pixhawk: tcp:localhost:5762 | ||
| PIXHAWK_ADDRESS = "/dev/ttyAMA0" | ||
| TEST_DURATION = 10 | ||
|
|
||
|
|
||
| def test_camera_feed() -> bool: | ||
| """ | ||
| Returns True if camera feed is available, False otherwise. | ||
| """ | ||
| try: | ||
| camera = cv2.VideoCapture(2) | ||
|
|
||
| if not camera.isOpened(): | ||
| camera.release() | ||
| return False | ||
|
|
||
| ret, frame = camera.read() | ||
| camera.release() | ||
|
|
||
| if ret and frame is not None and frame.size > 0: | ||
| return True | ||
|
|
||
| return False | ||
|
|
||
| except Exception: | ||
| return False | ||
|
|
||
|
|
||
| def main() -> int: | ||
| """ | ||
| GPS data reading + camera feed check. | ||
| Returns 0 on success, non-zero on failure. | ||
| """ | ||
| images_path = os.path.join("tests", "integration", "camera_emulator", "images") | ||
|
|
||
| print("HITL Test") | ||
| print("=============") | ||
|
|
||
| # Create FlightController with HITL enabled | ||
| result, controller = flight_controller.FlightController.create( | ||
| PIXHAWK_ADDRESS, 57600, True, True, True, images_path | ||
| ) | ||
|
|
||
| if not result or controller is None: | ||
| print("ERROR: FlightController creation failed") | ||
| return -1 | ||
|
|
||
| print("FlightController created") | ||
|
|
||
| # Start HITL emulators | ||
| if controller.hitl_instance is not None: | ||
| controller.hitl_instance.start() | ||
| print("HITL emulators started") | ||
|
|
||
| print("Waiting for camera creation...") | ||
| time.sleep(5) | ||
|
|
||
| print("Checking for camera...") | ||
| camera_available = test_camera_feed() | ||
| if camera_available: | ||
| print("Camera: detected") | ||
| else: | ||
| print("Camera: not detected") | ||
|
|
||
| else: | ||
| print("ERROR: HITL instance not created") | ||
| return -1 | ||
|
|
||
| try: | ||
| print(f"\nRunning test for {TEST_DURATION}s...") | ||
| start_time = time.time() | ||
| gps_count = 0 | ||
| camera_count = 0 | ||
|
|
||
| while time.time() - start_time < TEST_DURATION: | ||
| current_time = time.time() - start_time | ||
|
|
||
| # Test GPS data every 2 seconds | ||
| if int(current_time) % 2 == 0 and current_time > 0: | ||
| success, location = controller.get_location() | ||
| if success and location is not None: | ||
| lat, lon, alt = location | ||
| gps_count += 1 | ||
| print(f"GPS: {lat:.6f}, {lon:.6f}, {alt:.1f}m") | ||
| else: | ||
| print("GPS: No data") | ||
|
|
||
| # Test camera feed every 3 seconds | ||
| if int(current_time) % 3 == 0 and current_time > 1: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The camera test should be assuming no access to the emulators, try creating a video stream using cv2 and checking if it's receiving video. |
||
| if test_camera_feed(): | ||
| camera_count += 1 | ||
| print("Camera: Feed available") | ||
| else: | ||
| print("Camera: No feed") | ||
|
|
||
| time.sleep(0.5) | ||
|
|
||
| # Results | ||
| print(f"\nResults:") | ||
| print(f"GPS readings: {gps_count}") | ||
| print(f"Camera frames: {camera_count}") | ||
|
|
||
| success = gps_count > 0 and camera_count > 0 | ||
| print("PASS" if success else "FAIL") | ||
| return 0 if success else 1 | ||
|
|
||
| except Exception as exc: | ||
| print(f"Test error: {exc}") | ||
| return 1 | ||
| finally: | ||
| if controller.hitl_instance is not None: | ||
| controller.hitl_instance.shutdown() | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| exit(main()) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Depending on how your test goes, you might have to replace this with receiving the "GLOBAL_POSITION_INT" mavlink message