pip install pynput

Cloud_ Ghost·2025년 1월 6일

Genesis

목록 보기
2/5

Genesis Error 수정하기

import argparse
import numpy as np
import genesis as gs
import time
import threading
from pynput import keyboard

# 아래는 추가함 / 마우스휠을 통해서 조작하기 위해서
from pynput import mouse


class DroneController:
    def __init__(self):
        self.thrust = 14468.429183500699  # Base hover RPM - constant hover
        self.rotation_delta = 200  # Differential RPM for rotation
        self.thrust_delta = 10  # Amount to change thrust by when accelerating/decelerating
        self.running = True
        self.rpms = [self.thrust] * 4
        self.pressed_keys = set()

        # mouse listener for scrolling
        self.mouse_listener = mouse.Listener(on_scroll=self.on_scroll)
        self.mouse_listener.start()
        # 여기는 마우스 휠 조작을 통해서 카메라 줌인, 줌아웃을 위한 코드

    def on_press(self, key):
        try:
            if key == keyboard.Key.esc:
                self.running = False
                return False
            self.pressed_keys.add(key)
            print(f"Key pressed: {key}")
        except AttributeError:
            pass

    def on_release(self, key):
        try:
            self.pressed_keys.discard(key)
        except KeyError:
            pass

    def update_thrust(self):
        # Store previous RPMs for debugging
        prev_rpms = self.rpms.copy()

        # Reset RPMs to hover thrust
        self.rpms = [self.thrust] * 4

        # Acceleration (Spacebar) - All rotors spin faster
        if keyboard.Key.space in self.pressed_keys:
            self.thrust += self.thrust_delta
            self.rpms = [self.thrust] * 4
            print("Accelerating")

        # Deceleration (Left Shift) - All rotors spin slower
        if keyboard.Key.shift in self.pressed_keys:
            self.thrust -= self.thrust_delta
            self.rpms = [self.thrust] * 4
            print("Decelerating")

        # Forward (North) - Front rotors spin faster
        if keyboard.Key.up in self.pressed_keys:
            self.rpms[0] += self.rotation_delta  # Front left
            self.rpms[1] += self.rotation_delta  # Front right
            self.rpms[2] -= self.rotation_delta  # Back left
            self.rpms[3] -= self.rotation_delta  # Back right
            print("Moving Forward")

        # Backward (South) - Back rotors spin faster
        if keyboard.Key.down in self.pressed_keys:
            self.rpms[0] -= self.rotation_delta  # Front left
            self.rpms[1] -= self.rotation_delta  # Front right
            self.rpms[2] += self.rotation_delta  # Back left
            self.rpms[3] += self.rotation_delta  # Back right
            print("Moving Backward")

        # Left (West) - Left rotors spin faster
        if keyboard.Key.left in self.pressed_keys:
            self.rpms[0] -= self.rotation_delta  # Front left
            self.rpms[2] -= self.rotation_delta  # Back left
            self.rpms[1] += self.rotation_delta  # Front right
            self.rpms[3] += self.rotation_delta  # Back right
            print("Moving Left")

        # Right (East) - Right rotors spin faster
        if keyboard.Key.right in self.pressed_keys:
            self.rpms[0] += self.rotation_delta  # Front left
            self.rpms[2] += self.rotation_delta  # Back left
            self.rpms[1] -= self.rotation_delta  # Front right
            self.rpms[3] -= self.rotation_delta  # Back right
            print("Moving Right")

        self.rpms = np.clip(self.rpms, 0, 25000)

        # Debug print if any RPMs changed
        if not np.array_equal(prev_rpms, self.rpms):
            print(f"RPMs changed from {prev_rpms} to {self.rpms}")

        return self.rpms

    # 여기는 마우스 휠 조작을 통해 카메라 줌인, 줌아웃을 위한 코드
    def on_scroll(self, x, y, dx, dy):
        """Handle mouse wheel scroll to zoom in/out."""
        current_fov = self.scene.viewer.camera_fov
        if dy > 0:  # Scroll up (zoom in)
            new_fov = max(5, current_fov - 1)
        elif dy < 0:  # Scroll down (zoom out)
            new_fov = min(90, current_fov + 1)
        else:
            return

        self.scene.viewer.set_camera_fov(new_fov)
        print(f"Updated FOV: {new_fov}")
    


def update_camera(scene, drone):
    """Updates the camera position to follow the drone"""
    if not scene.viewer:
        return

    drone_pos = drone.get_pos()

    # Camera position relative to drone
    offset_x = 0.0  # centered horizontally
    offset_y = -4.0  # 4 units behind (in Y axis)
    offset_z = 2.0  # 2 units above

    camera_pos = (float(drone_pos[0] + offset_x), float(drone_pos[1] + offset_y), float(drone_pos[2] + offset_z))

    # Update camera position and look target
    scene.viewer.set_camera_pose(pos=camera_pos, lookat=tuple(float(x) for x in drone_pos))


def run_sim(scene, drone, controller):
    while controller.running:
        try:
            # Update drone with current RPMs
            rpms = controller.update_thrust()
            drone.set_propellels_rpm(rpms)

            # Update physics
            scene.step()

            # Update camera position to follow drone
            update_camera(scene, drone)

            time.sleep(1 / 60)  # Limit simulation rate
        except Exception as e:
            print(f"Error in simulation loop: {e}")

    if scene.viewer:
        scene.viewer.stop()


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("-v", "--vis", action="store_true", default=True, help="Enable visualization (default: True)")
    parser.add_argument("-m", "--mac", action="store_true", default=False, help="Running on MacOS (default: False)")
    args = parser.parse_args()

    # Initialize Genesis
    gs.init(backend=gs.gpu)

    # Create scene with initial camera view
    viewer_options = gs.options.ViewerOptions(
        camera_pos=(0.0, -4.0, 2.0),  # Now behind the drone (negative Y)
        camera_lookat=(0.0, 0.0, 0.5),
        camera_fov=30,
        max_FPS=60,
    )

    scene = gs.Scene(
        sim_options=gs.options.SimOptions(
            dt=0.01,
            gravity=(0, 0, -9.81),
        ),
        viewer_options=viewer_options,
        show_viewer=args.vis,
    )

    # Add entities
    plane = scene.add_entity(gs.morphs.Plane())
    drone = scene.add_entity(
        morph=gs.morphs.Drone(
            file="urdf/drones/cf2x.urdf",
            pos=(0.0, 0, 0.5),  # Start a bit higher
        ),
    )

    # Build scene
    scene.build()

    # Initialize controller
    controller = DroneController()

    # Print control instructions
    print("\nDrone Controls:")
    print("↑ - Move Forward (North)")
    print("↓ - Move Backward (South)")
    print("← - Move Left (West)")
    print("→ - Move Right (East)")
    print("ESC - Quit\n")
    print("Initial hover RPM:", controller.thrust)

    # Start keyboard listener
    listener = keyboard.Listener(on_press=controller.on_press, on_release=controller.on_release)
    listener.start()

    if args.mac:
        # Run simulation in another thread
        sim_thread = threading.Thread(target=run_sim, args=(scene, drone, controller))
        sim_thread.start()

        if args.vis:
            scene.viewer.start()

        # Wait for threads to finish
        sim_thread.join()
    else:
        # Run simulation in main thread
        run_sim(scene, drone, controller)
    listener.stop()


if __name__ == "__main__":
    main()

위 코드를 동작시키려고 하자 에러가 발생했습니다.
에러의 내용인 즉 pynput이 존재하지 않는다는것!
그래서 이를 수정하고자 당연하게도 pip install pynput을 진행했지만, 에러가 발생했습니다.


위 사진과 같이 굉장한 에러가 발생했습니다.
이 에러는 evdev 패키지를 빌드하는 과정에서 Python C 헤더 파일이 없어서 발생합니다. 이 문제를 해결하려면 Python의 개발 헤더 파일과 관련 도구를 설치해야 합니다.

먼저 가상환경이 실행되고 있고, sudo apt update를 했습니다.

이후 pip install --upgrade pip를 통해서 pip를 업그레이드 했습니다.
(물론 이미 업그레이드가 된 상태였습니다.)

다음으로 python --version을 통해 파이썬 버전을 확인하고, 파이썬3.12에 맞도록
sudo apt install python3-dev python3.12-dev build-essential을 진행했습니다.
(Linux 시스템에서는 Python C 확장을 컴파일하려면 python3-dev 또는 python3.x-dev 패키지가 필요합니다.)

그 다음으로 sudo apt install build-essential을 통해 build-essential 패키지를 설치합니다. 이를 통해서 컴파일러 및 관련 도구도 함께 설치됩니다.

그 다음 pip install evdev를 다시 설치합니다.

그 다음 다시 pip install pynput을 시도하면

짠~! 제대로 설치되는 것을 확인할 수 있습니다!

profile
행복합시다~

0개의 댓글