Util

Drone HITL 환경 구축

Limetime 2025. 1. 20. 23:26
반응형
 

우분투 개발 환경 | PX4 Guide (main)

 

docs.px4.io

This include : Gazebo, Gazebo Classic, jMAVSim, Pixhawk and other NuttX-based hardware

Simulation and NuttX (Pixhawk) Targets

git clone https://github.com/PX4/PX4-Autopilot.git --recursive

bash ./PX4-Autopilot/Tools/setup/ubuntu.sh
  • 최초 빌드 (jMAVSim 시뮬레이션 활용)
cd PX4-Autopilot
make px4_sitl jmavsim
  • gazebo-classic
make px4_sitl gazebo-classic

 

HITL

px4 autopilot 설치하고 QGC도 설치하고..

$ sudo usermod -a -G dialout $USER
$ sudo apt-get remove modemmanager -y
$ sudo apt-get install gstreamer1.0-plugins-bad gstreamer1.0-libav gstreamer1.0-gl -y
$ sudo apt-get install libfuse2 -y
$ sudo apt-get install libxcb-xinerama0 libxkbcommon-x11-0 libxcb-cursor0 -y

wget "https://d176tv9ibo4jno.cloudfront.net/latest/QGroundControl.AppImage"

$ chmod +x ./QGroundControl.AppImage
(or) $ chmod 777 ./QGroundControl.AppImage

$ ./QGroundControl.AppImage (or Double Click)

QGC

 

Hardware in the Loop Simulation (HITL) | PX4 Guide (main)

 

docs.px4.io

cd PX4-Autopilot/
DONT_RUN=1 make px4_sitl_default gazebo
  • Gazebo로 할 때
source Tools/simulation/gazebo-classic/setup_gazebo.bash $(pwd) $(pwd)/build/px4_sitl_default
gazebo Tools/simulation/gazebo-classic/sitl_gazebo-classic/worlds/hitl_iris.world
  • jmavsim으로 할 때
./Tools/simulation/jmavsim/jmavsim_run.sh -q -s -d /dev/ttyACM0 -b 921600 -r 250
  • test.py
#!/usr/bin/env python3
import asyncio
from mavsdk import System

async def run():
		#드론 객체 정의
    drone = System()

		#드론 연결
    #await drone.connect(system_address="udp://:14540")
    await drone.connect(system_address="serial:///dev/ttyACM0:57600")

    print("Waiting for drone to connect...")
    async for state in drone.core.connection_state():
        if state.is_connected:
            print(f"-- Connected to drone!")
            break

		#드론 위치 초기화
    print("Waiting for drone to have a global position estimate...")
    async for health in drone.telemetry.health():
    
        if health.is_global_position_ok and health.is_home_position_ok:
            print("-- Global position estimate OK")
            break

		#드론을 사용하기 위한 Arm 수행
    print("-- Arming")
    await drone.action.arm()

		#드론 이륙
    print("-- Taking off")
    await drone.action.takeoff()

		#이륙 후 잠시 대기
    await asyncio.sleep(20)

		#드론 착륙
    print("-- Landing")
    await drone.action.land()

if __name__ == "__main__":
    # Run the asyncio loop
    asyncio.run(run())
  • test2.py
from mavsdk import System
import asyncio

async def run():
    drone = System()
    await drone.connect(system_address="serial:///dev/ttyACM0:921600")  # 실제 하드웨어 포트로 수정

    print("Waiting for drone to connect...")
    async for state in drone.core.connection_state():
        if state.is_connected:
            print(f"Drone discovered with UUID: {state.uuid}")
            break

    print("-- Arming")
    await drone.action.arm()

    # 추가: 드론 상태 확인 및 초기화
    async for health in drone.telemetry.health():
        if health.is_global_position_ok and health.is_home_position_ok:
            print("Drone health checks passed")
            break
        print("Waiting for health checks to pass...")
        await asyncio.sleep(1)

    print("-- Taking off")
    try:
        await drone.action.takeoff()
    except Exception as e:
        print(f"Takeoff failed: {e}")

    await asyncio.sleep(10)

    print("-- Landing")
    await drone.action.land()

if __name__ == "__main__":
    asyncio.run(run())

 

드론 위치 이동 문제 해결

안되는 이유 : Failsafe mode가 작동 중이어서…

뭔 소린가?

우린 드론과 jmavsim 단 둘이 통신하기 때문에 조종기가 없다.

그런데, RC(Remote Controller??)가 없을 때, Failsafe가 enable되고 Return mode라는 액션을 취해서 걍 자기 혼자 집으로 돌아가버리는 것.

그럼 어케 해야되느냐

RC를 쓰지말고 오직 조이스틱으로 설정을 바꿔주게 되면 ‘Radio’항목의 빨간색도 안뜨고 잘된다.

그럼 이제 드론은 집에 안간다.

근데,, 문제는 QGC를 켰을 땐, joystick이 작동해서 코드가 잘 작동하지만

QGC를 켜지 않았을 경우 Failsafe enabled: No manual control stick input 에러가 뜨기 때문에 코드가 작동하지 않음..

 

히히.. 해결책을 갖고 돌아왔다구

해결책

 

Parameter Reference | PX4 Guide (main)

 

docs.px4.io

  1. QGC를 켠다
  2. COM_RC_IN_MODE 파라미터를 다시 원상복구 한다. (사실 RC Transmit만 되면 된다.)
    1. RC Transmit only
    2. RC or joystic
    3. 근데 사실.. 별로 중요하지 않은 것 같다.
  3. 이제 당연히 RC 조종기가 없으니 Radio 항목에는 빨간색이 들어오고 failsafe trigger가 작동할거다.
  4. 하지만 우리에겐 해결책이 있지..

  • COM_RCL_EXCEPT 파라미터의 값을 0으로 강제로 바꿔준다.
  • Advanced settings → Manual Entry를 체크하고 4를 입력한다.
  • 그러고 save
  1. 잘될거다.
  2. failsafe는 동작하지만, RC Loss에 대한 failsafe action은 none으로 작동하지 않는다. (무시)

그렇다. failsafe action이 문제였던 것이다.

  • test3.py
import asyncio
from mavsdk import System
from mavsdk.offboard import OffboardError, PositionNedYaw

async def run():
    drone = System()
    await drone.connect(system_address="udp://:14540")

    print("Waiting for drone to connect...")
    async for state in drone.core.connection_state():
        if state.is_connected:
            print("Drone discovered!")
            break

    print("-- Arming")
    await drone.action.arm()

    print("-- Taking off")
    await drone.action.takeoff()
    await asyncio.sleep(5)  # 드론이 이륙하는 시간을 충분히 대기

    print("-- Setting initial setpoint")
    await drone.offboard.set_position_ned(PositionNedYaw(0.0, 0.0, -2.0, 0.0))

    print("-- Starting offboard")
    try:
        await drone.offboard.start()
    except OffboardError as error:
        print(f"Starting offboard mode failed with error code: {error._result.result}")
        print("-- Disarming")
        await drone.action.disarm()
        return

    await asyncio.sleep(2)  # Offboard 모드 전환 전에 일정 시간 대기

    print("-- Go 10m North, 10m East, 5m Down within local coordinate system")

    # 이동 명령을 지속적으로 보내는 task를 생성합니다.
    async def send_move_setpoint():
        while True:
            await drone.offboard.set_position_ned(PositionNedYaw(10.0, 10.0, -7.0, 0.0))
            await asyncio.sleep(0.1)

    move_setpoint_task = asyncio.create_task(send_move_setpoint())

    await asyncio.sleep(10)  # 드론이 목표 위치로 이동할 시간을 충분히 대기

    # Move setpoint task를 종료합니다.
    move_setpoint_task.cancel()
    try:
        await move_setpoint_task
    except asyncio.CancelledError:
        pass

    print("-- Stopping offboard")
    try:
        await drone.offboard.stop()
    except OffboardError as error:
        print(f"Stopping offboard mode failed with error code: {error._result.result}")

    print("-- Landing")
    await drone.action.land()

    # 드론이 착륙할 때까지 대기
    print("Waiting for drone to land...")
    async for in_air in drone.telemetry.in_air():
        if not in_air:
            print("Drone has landed")
            break

    print("-- Disarming")
    try:
        await drone.action.disarm()
    except Exception as e:
        print(f"Disarming failed: {e}")

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(run())

내용 정리

QGC없이 jmavsim이랑 연결해서 진행되어야 함.
단, 펌웨어 설치 및 파라미터를 건드려야 하므로 QGC 개입이 필수다.

  1. QGC에 가면 Firmware를 설치할 수 있다. (PX4 Pro를 설치하면 된다.)
    1. 단, PX4 Pro 1.4.3은 Landoff detect 후 아무일도 일어나지 않는 이슈가 있다.
    2. 그래서 1.3.3으로 다운받아야 한다. (orange_cube버전으로)
  2. QGC에서 HITL을 설정하고 air frame도 simulation의 quadroater?로 설정한다.
  3. offboard 관련 명령어 특히, ned 좌표 이동 관련 함수가 작동하지 않는 이슈가 있었다.
    1. 이유는 RC(Remote Controller?)의 부재로 인한 failsafe action 작동이다.
    2. 이 경우 RC Loss로 인한 failsafe action을 무시하는 파라미터를 설정하면 된다.
      1. QGC→ parameters → COM_RCL_EXCEPT=4
    여담) QGC에서 COM_RC_IN_MODE = joystick_only 를 하면 QGC가 켜져 있는 동안은 failsafe가 disable된다. QGC가 꺼지면 또 수동 조종 스틱 못 찾았다고 failsafe가 뜬다.
  4. 끝.
반응형