직선 경로는 단순하면서도 가장 효율적인 이동 방법을 제공하며, 경로 계획과 유도 알고리즘의 기본 단위로 사용된다. 또한 직선은 다양한 경로 생성 기법의 기본 빌딩 블록이 된다. 다각형 경로나 꺾이는 경로는 직선 구간들의 집합으로 구성되며, 원형이나 타원 같은 곡선 경로 역시 직선 접선과의 관계 속에서 이해된다. 즉, 직선을 이해하고 정의하는 것은 복잡한 경로를 다루기 전에 반드시 거쳐야 할 출발점이다. 이번 포스팅에서는 항법의 기본이 되는 직선 경로를 구현한 내용을 다룬다. 

 

  1. 직선 경로 생성 함수
    - 시작점, 끝점 활용
    직선 경로는 시작점과 끝점을 지정하는 것만으로도 정의된다. 두 점 \(P_{start} = (x_{s}, y_{s})\) ,  \(P_{end} = (x_{e}, y_{e})\)가 주어지면, 이들을 잇는 직선 위의 점은 다음과 같이 나타낼 수 있다.

    $$P(t) = (1-t) P_{start} + t P_{end} \;,\;\;(0 \leq t \leq 1)$$
    여기서 매개변수 \(t\)가 0일 때는 시작점, 1일 때는 끝점이 되고, 그 사이의 값은 모두 직선 위의 점을 의미한다. 이 단순한 식은 경로점을 일정 간격으로 생성할 때 매우 유용하다. 예를 들어 \(N\)개의 점을 얻고 싶다면 \(t\)를 \(\frac{0}{N-1},\frac{1}{N-1},...,\frac{N-1}{N-1}\) 로 구성하면 된다. 이 방식으로 경로점 집합을 만들면, 무인기가 따라야 할 기준선을 손쉽게 정의할 수 있다.



    - 시작점, 방위각, 길이 활용
    직선의 또 다른 정의 방법은 시작점과 방위각(bearing), 그리고 길이로 설정하는 것이다. 항공기의 현재 위치가 \(P_{start} = (x_{s}, y_{s})\) 이동해야 할 거리 \(L\), 비행해야 할 방위각 \(\psi\)가 주어지면 끝점은 다음과 같이 계산된다.

    $$P_{end} = P_{start} + L [sin(\psi), cos(\psi)]^T$$
    이때 방위각은 북위 기준 시계방향으로 (+)인 각도를 의미한다. 이 방식은 경로점이 미리 주어지지 않은 상황에서 특히 유용하다. 예를 들어 “현재 위치에서 북동쪽 30도 방향으로 2km 직진하라”는 명령을 단순한 벡터 연산으로 표현할 수 있기 때문이다.


    import numpy as np
    import matplotlib.pyplot as plt
    
    def generate_straight_bearing(start, bearing, length, num_points):
        start = np.array(start)
        psi = np.deg2rad(bearing)
        
        end = start + length * np.array([np.sin(psi), np.cos(psi)])
        Path_Straight, is_loop = generate_straight_p2p(start, end, num_points)
        
        return Path_Straight, is_loop
    
    def generate_straight_p2p(start, end, num_points):
        is_loop=False
    
        start = np.array(start)
        end = np.array(end)
        t = np.linspace(0, 1, num_points)
        
        # Interpolate start to end
        Path_Straight = np.outer(1 - t, start) + np.outer(t, end)
        
        return Path_Straight, is_loop
    
    if __name__ == "__main__":
        # 시작점, 끝점 활용 직선 경로 생성
        #P_start = [0, 0]
        #P_end = [2000, 1000]
        #WP_num_points = 200
        #
        #WP_gen, is_loop = generate_straight_p2p(P_start, P_end, WP_num_points)
        
        #or
        
        # 시작점, 베어링, 거리 활용 직선 경로 생성
        P_start = [0, 0]
        bearing = 240
        length = 3000
        WP_num_points = 200
        
        WP_gen, is_loop = generate_straight_bearing(P_start, bearing, length, WP_num_points)
        
        # 시각화
        fig, ax = plt.subplots()
        ax.set_aspect('equal', adjustable='box')
        ax.grid(True, linestyle=':', alpha=0.3)
        ax.scatter([WP_gen[0,0], WP_gen[-1,0]], [WP_gen[0,1], WP_gen[-1,1]], c='r', marker='o', label="Start/End")
        ax.plot(WP_gen[:,0], WP_gen[:,1], 'k:', linewidth=2, label="Path")
        
        plt.show()


  2. 직선 경로 생성 결과
    아래 그림은 직선 경로 시작점 [0, 0], 끝점 [3000, 4500] 을 입력하여 도출된 경로점을 가시화한 결과이다. 지난번 포스팅한 장주선회 경로와는 다르게 loop형태의 끝점에서 시작점으로 연결되는 형태의 경로가 아님으로 마지막 경로점을 지나친 이후의 추가적인 처리를 해줘야 한다. 일반적으로는 hold 선회 명령으로 마무리하는것이 일반적이다.

 



직선 경로는 가장 단순한 형태이지만, 항공기 시뮬레이션과 제어 알고리즘 설계에서는 반드시 거쳐야 하는 기본기다. 시작점과 끝점을 잇는 직선은 효율적인 이동 수단일 뿐 아니라, 다양한 알고리즘 성능을 검증하는 기준선이 된다. 더 나아가 직선 구간을 조합하면 다각형이나 복잡한 임무 경로도 만들 수 있다. 최종 구성된 파일은 아래 깃허브 주소에 업로드하였다. 추후의 업데이트 내용들도 해당 깃허브 레포에 업데이트할 예정이다. 이로서 포스팅을 마무리하겠다.

https://github.com/Piggymode/UAV_2D_Simulation.git

 

GitHub - Piggymode/UAV_2D_Simulation: 2D 3-dof UAV simulation framework for experimenting with guidance, navigation, and control

2D 3-dof UAV simulation framework for experimenting with guidance, navigation, and control algorithms. Includes modular components for testing aircraft dynamics, control strategies, and mission sce...

github.com

 

 

 

 

이전 포스팅에서는 비선형 경로 추종 기법인 NLPF (Nonlinear Path Following)에 관한 논문을 리뷰하였으며 Racetrack 형태의 장주 선회 경로 생성 기능을 모듈로 구성한 내용을 다루었다. 이번 포스팅에서는 2차원 평면 운동을 하는 Unicycle 모델을 적용한 초단순 무인기 시뮬레이터에 비선형 경로 추종 기법인 NLPF 기법을 적용한 내용을 다루어 보겠다. 그럼 시작해보겠다.

2025.08.12-[알쓸신잡 연구노트 Guidance 1편] 논문 리뷰 Nonlinear Path-Following Guidance Method

 

[알쓸신잡 연구노트 Guidance 1편] 논문 리뷰 Nonlinear Path-Following Guidance Method

비행체가 정해진 경로를 안정적이고 정확하게 따라간다는 것은 항공기, 드론, 미사일 등 다양한 분야에서 필수적인 요구사항이다. 하지만 경로가 직선이 아니라 곡선이거나 원형일 경우, 그리

piggymode.tistory.com

 

2025.08.15-[알쓸신잡 연구노트 M&S 8편] 장주선회(Traffic Pattern) 경로 생성 함수 구현

 

[알쓸신잡 연구노트 M&S 8편] Nonlinear Path-Following Guidance Method 구현(1/2), 장주선회 경로 생성

지난번 포스팅에서는 비선형 경로 추종 기법인 NLPF (Nonlinear Path Following)에 관한 논문을 리뷰하며, 이 방법의 원리와 수식을 깊이 들여다보았다. 이와 관하여 2번의 포스팅을 통해 NLPF를 초단순 무

piggymode.tistory.com

 

 

  1. 비선형 경로추종 유도기법
    비선형 경로추종 유도기법 (Nonlinear Path-Following, NLPF)를 구현한 간결한 코드입니다. NLPF 유도기법의 핵심은 항공기의 현재 위치로 부터 경로상에  \(L1\) 거리에 있는 참조점을 찾고 이 점을 추종하기 위한 횡가속도 명령을 도출해내는 것이다.

    - find_target 함수 : 참조점 찾기
    참조점을 찾기 위한 find_target 함수는 경로 배열과 현재 위치를 받아 각 경로점까지의 거리를 계산하고, 그중에서 \(L1\)  거리(설정값) 이하에 들어오는 지점들의 인덱스를 구해 그 중 가장 멀리 있는(인덱스가 큰) 경로점을 참조점으로 선택하게 된다. \(L1\) 거리 내에 경로점이 존재하지 않는다면 경로점 중 가장 가까운 점을 참조점으로 선택하도록 구성하였다. 경로가 폐곡선인 경우 인덱스가 앞뒤로 이어지는 특성 때문에, 경로점 중 0번 인덱스가 섞이는 경우엔 반바퀴를 기준으로 큰 인덱스들을 과감히 버리고 인덱스가 작은 경로점 중에서 최댓값을 택한다. 이렇게 하면 경로의 연결부 근처에서 기체가 갑자기 뒤쪽 점을 집어 들며 U턴하듯 비정상적으로 움직이는 일을 방지할 수 있다.

    def find_target(position, path, L1, is_loop):
        P   = np.asarray(path, dtype=float)
        pos = np.asarray(position, dtype=float)
        N   = P.shape[0]
    
        d = np.sqrt((P[:,0] - pos[0])**2 + (P[:,1] - pos[1])**2)
        i0 = int(np.argmin(d))
    
        cand = np.where(d <= L1)[0]  
        if cand.size == 0:
            target_Idx = i0
            return P[target_Idx, :]
        else:
            half = N // 2
            if 0 in cand: 
                cand_wrapped = cand[cand <= half]
                if cand_wrapped.size > 0:
                    target_Idx = int(np.max(cand_wrapped))
                else:
                    target_Idx = int(np.max(cand))
            else:
                target_Idx = int(np.max(cand))
        return P[target_Idx, :]


    - NLPF_Guidance : 비선형 경로추종 유도기법
    참조점이 정해지면 횡가속도를 정하는 NLPF_Guidance 함수가 동작한다. 여기서 쓰는 식은 \(L1\) 유도 법칙의 수식으로 현재 속도 \(V\), 표적점까지의 거리 \(L1\), 그리고 현재 기수방향과 표적점 방위의 차 \(\eta\)를 써서 아래의 수식으로 계산한다. 또한 논문에서 제시한 수식은 경로 추종을 위한 횡가속도의 수식이고 코드에서 활용되는 입력은 선회율 \(\omega\)이므로 횡가속도와 선회율간 공식을 활용하여 계산할 수 있다.

    $$a_{s_{cmd}}=2 \frac{V^2}{L_{1}} sin{\eta }\; , \;\; \omega = \frac{a_{s_{cmd}}}{V}$$
    $$\omega=2 \frac{V}{L_{1}} sin{\eta }$$
    def NLPF_Guidance(state, target_wp):
        n,e,psi,v = state
        L1 = np.linalg.norm(target_wp - np.array([n, e]))
        #print(L1)
        eta = np.arctan2(target_wp[1] - e, target_wp[0] - n) -psi
        eta = np.arctan2(np.sin(eta), np.cos(eta))
        omega = (2 * v / L1) * np.sin(eta)
        return omega


  2. 경로 추종 시뮬레이션 실행 결과
    UAV_Sim_ver1.py를 실행시키게 되면 시뮬레이션의 결과가 애니메이션의 형태로 출력된다. 시뮬레이션에서는 총 시간은 300초로 설정했고, 경로는 중심 좌표 [1000, 3000]에 반경 600m의 반원과 길이 2000m의 직선 구간을 결합한 장주선회 경로 30도의 bearing 회전 적용하여 구성한다.
    무인기의 초기 위치는 북방향 900m, 동방향 2000m 지점에서 기수방위각 0rad(북쪽 향), 속도 50m/s로 비행을 시작하며 시뮬레이션을 실행하면, 기체는 초기 직선 비행 후 장주선회 경로의 상단 직선 부분에 부드럽게 진입하며 경로를 따라 안정적으로 주행한다. 경로에 접근한 후 약간의 overshoot가 발생하여 경로를 살짝 넘어가지만 감쇠율이 0.707로 고정인 NLPF의 특성이 잘 드러다는 결과이며 이내 안정적으로 경로에 안착, 수렴한다. 





  3. 추가
    - import 경로 설정
    UAV_Sim_ver1.py의 상단에 import 코드를 살펴보면 아래의 코드를 확인할 수 있다.
    from Mission_Planning.Path_Racetrack import generate_racetrack
    from Guidance.NLPF import find_target, NLPF_Guidance
     앞서 설명한 모듈을 불러오기 위한 코드이다. 이는 각자의 디렉터리 구성에 따라 코드를 변경해줘야 한다. 필자는 UAV_Sim_ver1.py와 동일한 디렉터리에 Mission_Planning폴더와 Guidance폴더를 만들어 각 폴더 내부에 각 함수 파일들을 위치하였으며 추후 살펴볼 유도법칙과 임무계획 코드들을 모듈형태로 구현하여 채워넣기 위하여 이런식으로 구성해보았으나 더 좋은 방법이 있을지도 모르겠다. 독자님들의 소중한 조언 기다리겠다..

    - 모듈형 유도법칙 구현
    시뮬레이션을 실행시키기 위한 main함수,UAV_Sim_ver1.py의 메인 부분에는 아래와 같이 함수 형태로 된 코드를 추가하였다. 이는 추후에 추가적으로 유도 법칙들을 구현하고 모듈형으로 손쉽게 적용하기 위한 코드이다. 이런식으로 구성하게 되면 시뮬레이터 내부에 구성된 함수들을 별도로 건드리지 않고도 유도법칙을 추가/변경 적용할 수 있다.
        def Guidance_Method(state, L1=200, cmd_range=[-1, 1]):
            pos = state[:2]
            tgt_wp = find_target(pos, WP_gen, L1, is_loop)
            cmd = np.clip(NLPF_Guidance(state, tgt_wp), cmd_range[0], cmd_range[1])
            return cmd


이상으로 초단순 무인기 시뮬레이터와 NLPF 유도 법칙을 결합한 UAV 경로 추종 시뮬레이션을 구현하고, 장주선회 경로 유도 과정을 살펴보았다. 최종 구성된 파일은 아래 깃허브 주소에 업로드하였다. 우측 상단에 초록색 code 버튼을 통해서 clone을 위한 링크를 얻거나 zip파일로 다운로드 할 수 있다. 추후에 업데이트 내용들도 해당 깃허브 레포에 업데이트할 예정이니 많은 관심을 부탁한다. 이로서 오늘의 포스팅을 마무리하겠다. 

https://github.com/Piggymode/UAV_2D_Simulation.git

 

GitHub - Piggymode/UAV_2D_Simulation: 2D 3-dof UAV simulation framework for experimenting with guidance, navigation, and control

2D 3-dof UAV simulation framework for experimenting with guidance, navigation, and control algorithms. Includes modular components for testing aircraft dynamics, control strategies, and mission sce...

github.com

 

 

 

지난번 포스팅에서는 비선형 경로 추종 기법인 NLPF (Nonlinear Path Following)에 관한 논문을 리뷰하며, 이 방법의 원리와 수식을 깊이 들여다보았다. NLPF와 같은 유도기법을 적용하기 위해서는 무인기가 추종해야할 참조점을 얻기 위한 경로점을 정의해야한다. 본 포스팅에서는 Racetrack 형태의 장주 선회 경로 생성 기능을 모듈로 구성한 내용을 다룬다. 그럼 시작해보겠다.

2025.08.12-[알쓸신잡 연구노트 Guidance 1편] 논문 리뷰 Nonlinear Path-Following Guidance Method

 

[알쓸신잡 연구노트 Guidance 1편] 논문 리뷰 Nonlinear Path-Following Guidance Method

비행체가 정해진 경로를 안정적이고 정확하게 따라간다는 것은 항공기, 드론, 미사일 등 다양한 분야에서 필수적인 요구사항이다. 하지만 경로가 직선이 아니라 곡선이거나 원형일 경우, 그리

piggymode.tistory.com

 

 

  1. 장주선회란?
    장주선회는 다른 말로는 Traffic Pattern이라고도 불리며 두 개의 평행 직선 구간과 두 개의 반원형 선회 구간으로 구성된 형태의 폐곡선을 따라 비행하는 선회 비행을 의미한다. 항공기나 무인기는 직선 구간에서는 일정 방향으로 비행하며, 반원 구간에서는 지정된 회전 방향(시계방향 또는 반시계방향)으로 선회한다. 장주선회는 반복 경로의 형태가 단순하고 예측 가능해 다중 기체 운용과 임무 계획이 안전하고 효율적으로 이루어진다. 또한 항공기의 최소 선회반경, 속도, 센서 운용 조건 등 비행체와 환경 제약을 손쉽게 반영할 수 있어 다양한 임무에 유연하게 적용된다. 이러한 특징을 가지는 장주 선회는 비행기가 공항 주변에서 대기(Holding)할 때, 무인기가 특정 구역을 반복 감시할 때, 심지어는 해상·지상 차량의 순찰 경로에서도 활용된다. 직관적으로는 간단해 보이지만, 경로 설계 시에는 중심점 위치, 직선 구간의 길이, 반원의 반지름, 회전 방향, 속도 프로파일, 고도 변화 여부 등 다양한 설계 변수를 고려해야 한다. 이 변수들은 비행체의 운동 성능, 임무 목표, 그리고 주변 환경(바람, 지형)에 따라 달라진다.


  2. 장주선회 경로 생성 함수
    유도법칙의 테스트를 위하여 가장 직관적인 장주선회 경로를 구성하였다. 장주선회 경로는 직선과 반원으로 이루어진 네 구간을 일정 거리로 샘플링해서 하나의 폐곡선 배열로 잇는다. 얻은 x–y 평면상의 경로를 요구되는 회전 방향에 따라 배열의 순서를 지정하며 최종적으로 회전 행렬을 적용하여 베어링을 적용, 중심 좌표를 평행 이동해 목표 위치를 지정한다.

    입력 : 장주선회 중심점(n,e), 반경, 길이, 점 갯수, 베어링, 선회 방향
    출력 : 경로점 배열 (n,e), 폐루프 경로 여부
    import numpy as np
    import matplotlib.pyplot as plt
    
    def generate_racetrack(WP_center, radius, straight_length, num_points, bearing_deg, direction):
        waypoints = []
        is_loop=True
    
        # Bottom straight
        for i in range(num_points):
            x = -straight_length / 2 + i * (straight_length / num_points); y = -radius
            waypoints.append([x, y])
    
        # Right semicircle (bottom to top)
        for i in range(num_points):
            angle = np.pi * (i / num_points)
            x = radius * np.sin(angle) + straight_length / 2; y = -radius * np.cos(angle)
            waypoints.append([x, y])
    
        # Top straight
        for i in range(num_points):
            x = straight_length / 2 - i * (straight_length / num_points); y = radius
            waypoints.append([x, y])
    
        # Left semicircle (top to bottom)
        for i in range(num_points):
            angle = np.pi * (i / num_points) + np.pi
            x = radius * np.sin(angle) - straight_length / 2; y = -radius * np.cos(angle)
            waypoints.append([x, y])
    
        waypoints = np.array(waypoints)
    
        # CW/CCW
        if direction == -1:
            waypoints = waypoints[::-1]
    
        # Rotate by bearing
        bearing_rad = np.deg2rad(bearing_deg)
        rotation_matrix = np.array([
            [np.cos(bearing_rad), -np.sin(bearing_rad)],
            [np.sin(bearing_rad),  np.cos(bearing_rad)]
        ])
        Path_Racetrack = waypoints @ rotation_matrix.T + WP_center
    
        return Path_Racetrack, is_loop
    
    if __name__ == "__main__":
        WP_center = [1000, 3000]
        WP_radius = 600
        WP_length = 2000
        WP_num_points = 200
        WP_bearing_deg = 70
        WP_direction = -1
        WP_gen, is_loop = generate_racetrack(WP_center, WP_radius, WP_length, WP_num_points, WP_bearing_deg, WP_direction)
        
        
        fig, ax = plt.subplots()
        pad = 200.0
        ax.set_xlim(-1000, 3000)
        ax.set_ylim(1000, 5000)
        ax.set_aspect('equal', adjustable='box')
        ax.grid(True, linestyle=':', alpha=0.3)
        ax.plot(WP_gen[:, 0], WP_gen[:, 1], 'k:', lw=1.2, label="Path")
        
        plt.show()


  3. 장주선회 경로 생성 결과
    아래 그림은 장주선회 중심 (1000, 3000), 반경 600m, 길이 2000m, 베어링 70 \(\deg\) 를 입력하여 도출된 경로점을 가시화한 결과이다. 유의할 점은 항공기의 최서 선회 반경을 항공기의 속도와 최대 뱅크각도를 활용하여 아래의 수식과 같이 정의할 수 있는데 이때 장주선회의 양옆에 구성된 반원의 반경이 이를 넘지 않도록 설계하면 안정적인 장주선회 비행이 가능하다.

    $$ R_{min} = \frac{V^2}{g tan(\phi_{max})}$$

    또한  직선길이, 반지름, 지상속도등을 활용하여 장주 시간을 아래의 식으로 계산할 수 있다. 그래서 특정 구역에 필요한 체공 비율, 재방문 주기, 목표 dwell time을 역산하여 장주선회 경로를 설계로 맞출 수 있다. 이런 정량적 설계 가능성이 장주선회가 널리 사용되는 이유 중 하나이겠다.

    $$ T=\frac{2(L+\pi R)}{V}$$



이번 포스팅에서는 장주선회 경로의 개념과 설계 요소를 살펴보았다. 장주선회는 임무 효율성과 안전성, 그리고 제어 안정성을 모두 확보할 수 있는 매우 실용적인 경로 구조이다. 최종 구성된 파일은 아래 깃허브 주소에 업로드하였다. 추후의 업데이트 내용들도 해당 깃허브 레포에 업데이트할 예정이다. 이 글이 비슷한 시도를 하려는 분들께 작은 참고와 영감이 되길 바라며, 이로서 오늘의 포스팅을 마무리하겠다. 

https://github.com/Piggymode/UAV_2D_Simulation.git

 

GitHub - Piggymode/UAV_2D_Simulation: 2D 3-dof UAV simulation framework for experimenting with guidance, navigation, and control

2D 3-dof UAV simulation framework for experimenting with guidance, navigation, and control algorithms. Includes modular components for testing aircraft dynamics, control strategies, and mission sce...

github.com

 

 

비행체가 정해진 경로를 안정적이고 정확하게 따라간다는 것은 항공기, 드론, 미사일 등 다양한 분야에서 필수적인 요구사항이다. 하지만 경로가 직선이 아니라 곡선이거나 원형일 경우, 그리고 외란이나 속도 변화가 발생하는 환경에서는 경로 추종 성능을 안정적으로 유지하는 것은 매우 까다로운 작업이다. 이번에 살펴볼 논문 Performance and Lyapunov Stability of a Nonlinear Path Following Guidance Method는 다양한 경로 조건에서 안정적인 추종 성능을 보장하는 간결하고 직관적인 유도법을 제시한다. 이 방법은 지상 로봇 분야에서 널리 알려진 pure pursuit 기법을 기반으로 하되, 항공기 환경에 맞게 L1 참조점 개념과 비선형 가속도 명령식을 적용한 것이 핵심이다. 그럼 포스팅을 시작해보겠다.

논문 제목 : Performance and Lyapunov Stability of a Nonlinear Path-Following Guidance Method

논문 저자 : Sanghyuk Park, John Deyst and Jonathan P. How

저널 정보 : Journal of Guidance, Control, and Dynamics Vol.30, No.6, 2007

DOI         : https://doi.org/10.2514/1.28957

 

 

  1. L1 참조점 기반 비선형 경로추종 유도법칙
    이 논문에서 제안하는 비선형 유도법은 기존에 알려진 pure pursuit(순수 추종) 기법을 변형한 형태로, 기체가 목표 경로를 따라가도록 하는 데 필요한 측방향 가속도를 산출하는 방식이다. 원리는 단순하다. 먼저 경로 상에 기체 전방 L1 거리만큼 떨어진 지점을 참조점(reference point)으로 설정한다. 이 참조점과 기체 속도 벡터 방향이 이루는 각을 \(\eta\) 할 때, 가속도 명령은 다음과 같이 주어진다. 여기서 \(V\)는 기체의 지상속도이다. 이 식은 기하학적으로, 참조점과 기체를 잇는 선분(L1 라인)과 속도 벡터가 만드는 각도 \( \eta\)를 기준으로, 기체의 횡가속도 명령을 도출해낸다.
    $$a_{s_{cmd}}=2 \frac{V^2}{L_{1}} sin{\eta }$$



  2. 핵심 특징
    - 경로 추종을 위한 가속도의 방향 생성
    가속도의 방향은 L1 라인과 속도 벡터 사이의 각도 부호에 의해 결정된다. 예를 들어, 참조점이 속도 벡터의 오른쪽에 있다면 기체는 오른쪽으로 선회하도록 양(+)의 가속도가 명령된다. 반대로 참조점이 왼쪽에 있다면 음(-)의 가속도가 명령되어 왼쪽으로 선회하게 된다. 결국 이 방법은 속도 방향을 L1 라인과 일치시키도록 가속도가 발생하게 된다.

    - 거리기반 진입 각도
    기체가 경로로부터 멀리 떨어져 있을 경우에는 경로로 크게 진입하도록 큰 횡가속도 명령을 반대로 경로에 가까울수록 작은 횡가속도 명령을 만든다. 이 덕분에 멀리서 접근할 때는 과감한 진입을, 가까이에서는 부드러운 수렴을 가능하게 한다.

    - 기하학적 곡률 추종
    기체의 위치와 참조점을 지나는 원(instantaneous circle)을 생각해 보면, 이 원의 반경 \(R\)은 \(L_{1} / (2sin(\eta))\)로 주어지고, 그때의 구심가속도는 \(V^2/R\)이다. 이를 변형하면 \(a_{c}=(2V^2/L_{1})sin{\eta}\)가 되어, 이는 제안된 횡가속도식과 정확히 일치한다. 따라서 이 기법은 반경 \(R\)이 기체가 낼 수 있는 최소 선회반경 이상이면 어떤 곡률의 경로라도 따라갈 수 있다. 이는 곡률이 크든 작든, 물리적으로 가능한 범위 내에서는 동일한 원리로 적용된다는 의미다. 

    - 위상 선행 효과
    참조점을 현재 위치보다 \(L_{1}\)만큼 앞에 두기 때문에 기체는 곡선이나 방향 전환 구간에 들어가기 전에 선제적으로 조향을 시작한다. 수학적으로는 참조점 입력이 기체 위치 입력보다 시간만큼 앞서 들어오므로 대략적으로 \(\tau=L_{1}/V\)의 선행이 생긴다. 즉 참조점 위치가 기체 위치 입력에 \(\tau\) 만큼의 시간이 선행되어 들어간다는 뜻이다. 이 효과를 더 직관적으로 분석하기 위해, 경로 횡위치 입력 \(d\)가 파장 \(L_{p}\)의 정현파라고 가정한다.
    $$d^*=A sin{\frac{2 \pi x}{L_{p}}}$$
    여기서 \(x \approx V_{t}\)로 둔다면 입력 주파수는 \(\frac{2 \pi V_{t}}{L_{p}}\)가 된다. 이때 아래 3. 단원에서 도출될 유도 법칙의 고유 주파수 응답 특성 관계 \(\omega_{n}=\frac{\sqrt{2}V_{t}}{L_{1}}\) 를 적용하면 
    $$\frac{2 \pi V_{t}}{L_{p}}=\frac{\sqrt{2}V_{t}}{L_{1}} \;, \;\;L_{p}\approx 4.4 L_{1}$$
    일 때 입력 주파수에서의 위상 지연이 약 \(90\deg\)가 된다. 동시에 참조점 선행에 의한 위상 선행이 약 (90\deg\) 발생하므로, 두 효과가 서로 상쇄되어 전체 시스템 위상은 거의 0° 근처로 복구된다.
    이러한 위상 회복 특성 덕분에, 곡률 변화가 잦거나 파장이 \(L_{p} \approx 4.4L_{1}\)인 경로에서도 추종 응답의 진폭과 위상은 거의 평탄하게 유지된다. 반대로 \(L1/Lp\) 비율이 이 범위를 벗어나면, 위상 지연이 충분히 상쇄되지 못하거나 오히려 과보상(overcompensation)될 수 있다.



  3. 선형 분석
    비선형 유도법에서 가장 중요한 설계 선택 중 하나는 기체와 참조점 사이의 **전방 거리(L1)**를 어떻게 설정하느냐이다. L1은 단순히 기체가 앞을 바라보는 거리만 의미하는 것이 아니라, 제어계의 동특성과 안정성에 직접적인 영향을 주는 설계 파라미터이므로, 선형 시스템 해석을 통해 합리적으로 선정할 수 있다.


    우선 직선 경로를 추종하는 경우를 가정하면, 제안된 유도 기법은 비례-미분(PD) 제어기 형태로 근사된다. 경로와 기체 위치 간 횡방향 오차를 \(d\)라 하고, 참조점의 횡위치를 \(d^*_{ref,pt}\)라 할 때, 작은 각도 근사를 적용하면
    $$ sin{\eta}\approx \eta=\eta_{1}+\eta_{2}$$
    이때 
    $$ \eta_{1}\approx \frac{d-d^*_{ref,pt}}{L_{1}}\;,\;\;\eta_{2}\approx\frac{\dot{d}}{V}$$
    따라서 이를 논문에서 제안하는 아래 유도식
    $$a_{s_{cmd}}=2 \frac{V^2}{L_{1}} sin{\eta }$$
    에 대입하게 된다면
    $$a_{s_{cmd}}\approx\frac{2V}{L_{1}}\dot{d} + \frac{2V^2}{L^2_{1}}d$$
    이는 경로와의 횡방향 오차에 대한 비례항 \(d\)와 미분항\(dot{d}\)를 모두 포함하는 전형적인 PD제어의 구조가 된다. 이를 참조점의 위치에 대하여 더욱 일반화하여 나타내면 횡방향 동역학 방정식을
    $$\ddot{d}+\frac{2V}{L_{1}}\dot{d}+\frac{2V^2}{L^2_{1}}d=\frac{2V^2}{L^2_{1}}d^*_{ref,pt} $$ 
    로 나타낼 수 있으며, 이를 라플라스 변환하면 입력-출력 전달함수는 아래와 같이 나타낼 수 있다
    $$\frac{d(s)}{d^*_{ref,pt}(s)}=\frac{\omega^2_{n}}{s^2+2\zeta\omega_{n}s+\omega^2_{n}}$$
    즉, 제안된 유도 기법은 고유진동수와 감쇠비가 아래와 같이 명확하게 정의된 2차 시스템과 동일하게 작동한다.
    $$\zeta=0.707\;,\;\;\omega_{n}=\frac{\sqrt{2}V}{L_{1}}$$

 

이번 글에서는 비선형 경로추종 유도기법의 원리와 주요 특징을 살펴보았다. 단일 변수 \(L_{1}\)만으로 경로 추종 성능과 위상 특성을 조정할 수 있다는 점은 구현과 튜닝 모두에서 장점이 크다. 특히 속도 변화에 자동 대응하고, 위상 선행 효과로 곡률 변화 구간에서도 안정적인 추종이 가능하다는 점이 인상적이다. 이상으로 비선형 경로추종 유도기법과 관련된 논문 리뷰를 마치도록 하겠다.

무인기의 평면 운동을 시뮬레이션하는 방법은 매우 다양하다. 실제 기체의 공력, 중량, 자세 변화까지 모두 포함하는 복잡하면서 정확도가 높은 6자유도(6-DOF) 비행역학 모델을 사용할 수도 있고, 이를 단순화한 고정고도 3자유도(3-DOF) 모델을 적용할 수도 있다. 그러나 이렇게 복잡한 모델은 방정식이 많고 계산량이 커, 경로 계획이나 제어 알고리즘의 초기 검증 단계에서는 불필요하게 무거울 수 있다. 이때 자주 쓰이는 것이 바로 유니사이클(Unicycle) 모델이다. 유니사이클 모델은 기체를 단순한 한 점 질량과 진행 방향(헤딩)을 가진 물체로 가정해, 북(N), 동(E) 평면에서의 위치, 헤딩각, 속도만으로 상태를 정의한다. 제어 입력은 요 레이트(ω)와 가속도(a) 두 가지뿐이어서 수학적으로 간단하고, 직관적으로 경로를 예측할 수 있다. UAV의 방향 전환, 직진, 선회 같은 기본 기동을 재현하기에 충분하면서도 계산량이 적어 빠른 시뮬레이션이 가능하다는 점 때문에 학술 연구, 유도/제어 알고리즘 개발, 로봇 시뮬레이션 등에서 매우 널리 쓰인다.

 

$$\dot{N}_{\mathrm{pos}} = V \cos(\psi)$$
$$\dot{E}_{\mathrm{pos}} = V \sin(\psi)$$

 

이러한 유니사이클 모델을 활용하여 우리의 실험에 활용될 첫 시뮬레이터, UAV_Sim_ver1을 개발해본다. 이 코드는 매우 간단하면서도 널리 사용되는 유니사이클(Unicycle) 모델을 기반으로 UAV의 2차원 평면 상 운동을 시뮬레이션하고 시각화하는 구조로 작성되어 있다. 구현된 전체 코드는 포스팅의 최하단에 첨부하였다. 유용히 사용하길 바란다.

 

  1. 패키지 설치
    우선 이번 시뮬레이터에 필요한 패키지는 다음과 같다. 간단한 코드로 필요한 패키지도 그렇게 많지 않다. 가상환경 진입 후 아래 코드를 활용해 각종 패키지들을 설치하도록 한다. 
    pip install -r requirements.txt

    # requirements.txt
    
    contourpy==1.3.3
    cycler==0.12.1
    fonttools==4.59.0
    kiwisolver==1.4.8
    matplotlib==3.10.5
    numpy==2.3.2
    packaging==25.0
    pillow==11.3.0
    pyparsing==3.2.3
    python-dateutil==2.9.0.post0
    six==1.17.0


  2. Integrate_step : 수치적분 함수
    이제 코드의 구성 함수들을 하나한 파해치도록 하겠다. 코드의 첫 부분인 integrate_step 함수는 주어진 운동방정식을 수치적으로 적분해 다음 상태를 계산하는 역할을 한다. 적분 방식으로는 간단한 오일러(Euler)법과 보다 정확한 4차 Runge-Kutta (RK4)법을 구현하였으며, 제어 입력과 현재 상태, 그리고 시간 간격을 받아 한 스텝 동안의 상태 변화를 계산한다. 이렇게 구성해두면 나중에 운동 모델이 바뀌더라도 적분 함수만 호출하면 되므로 코드 재사용성이 높아진다.

    def integrate_step(f, state, control, dt, method="rk4", t=0.0, params=None):
        m = method.lower()
        if m == "rk4":
            k1 = f(t, state, control, params)
            k2 = f(t + 0.5*dt, state + 0.5*dt*k1, control, params)
            k3 = f(t + 0.5*dt, state + 0.5*dt*k2, control, params)
            k4 = f(t + dt, state + dt*k3, control, params)
            return state + (dt/6.0)*(k1 + 2*k2 + 2*k3 + k4)
        elif m == "euler":
            k1 = f(t, state, control, params)
            return state + dt * k1
        else:
            raise ValueError(f"Unknown method: {method}")


  3. unicycle_dynamics : 유니사이클 모델 상태방정식
    unicycle_dynamics 함수는 유니사이클 모델의 상태 방정식을 정의한다. 상태 벡터는 북쪽 위치 n, 동쪽 위치 e, 방위각 ψ, 속도 v로 구성되며, 제어 입력은 요각속도와 가속도이다. 속도와 방위각으로부터 북쪽과 동쪽 위치 변화율을 계산하고, 요각속도는 방위각 변화율, 가속도는 속도 변화율로 직접 연결된다. 이 결과를 이용하면 적분 함수에서 시간에 따른 상태 변화를 계산할 수 있다.

    def unicycle_dynamics(t, state, control, params=None):
        n, e, psi, v = state
        omega, acc = control  # control = [yaw rate, acceleration]
    
        n_dot     = v * np.cos(psi)
        e_dot     = v * np.sin(psi)
        psi_dot = omega
        v_dot     = acc
    
        return np.array([n_dot, e_dot, psi_dot, v_dot], dtype=float)


  4. simulate_unicycle : 시뮬레이션 수행 함수
    simulate_unicycle 함수는 주어진 제어 입력 시퀀스를 기반으로 전체 시뮬레이션을 수행한다. 시뮬레이션 시간과 적분 시간 간격, 제어 입력 갱신 주기 등을 받아 매 시간 스텝마다 제어 입력을 갱신하고, integrate_step을 호출하여 새로운 상태를 계산한다. 이렇게 하면 일정 시간마다 제어 입력이 바뀌는 실제 상황을 모사할 수 있고, 결과로는 전체 시뮬레이션 시간 벡터와 상태 이력을 얻을 수 있다.

    def simulate_unicycle(u_seq, x0, T_tot=100, sim_dt=0.01, ctrl_dt=0.1, method="rk4"):
        u_seq = np.asarray(u_seq, dtype=float)
        total_steps = int(T_tot/sim_dt)
    
        T = np.linspace(0.0, T_tot, total_steps+1)
        X = np.zeros((total_steps+1, 4), dtype=float)
        X[0] = np.asarray(x0, dtype=float)
    
        i = 0
        u = u_seq[i, 1:3]
        ctrl_chk= ctrl_dt
        
        t = 0.0
        for k in range(total_steps):
            if t >= ctrl_chk - 1e-12: 
                while (i + 1) < len(u_seq) and t >= u_seq[i+1, 0] - 1e-12:
                    i += 1
                u=u_seq[i, 1:3]
                ctrl_chk += ctrl_dt
            
            X[k+1] = integrate_step(unicycle_dynamics, X[k], u, sim_dt, method, t)
            t += sim_dt
    
        return T, X


  5. animate_simulation : 가시화 함수
    animate_simulation 함수는 시뮬레이션 결과를 시각적으로 보여준다. matplotlib의 애니메이션 기능을 사용하여 UAV의 궤적과 현재 위치·방위각을 나타내는 삼각형 기체 모양을 시간에 따라 그린다. 내부적으로 _triangle_points 함수를 이용해 주어진 위치와 방위각에 맞춰 삼각형 좌표를 계산하고 회전·이동시킨 뒤, trail(궤적)과 함께 화면에 표시한다. 이렇게 하면 UAV가 이동하며 방향을 바꾸는 모습을 직관적으로 확인할 수 있다.

    def animate_simulation(hist, interval_ms, stride=1, tri_len=80.0, tri_w=40.0, trail_style='k--'):
        ns, es, psis = hist[:,0], hist[:,1], hist[:,2]
    
        fig, ax = plt.subplots()
        ax.set_xlim(np.min(es)-200, np.max(es)+200)
        ax.set_ylim(np.min(ns)-200, np.max(ns)+200)
        ax.set_aspect('equal', adjustable='box')
        ax.grid(True, linestyle=':', alpha=0.3)
    
        trail_line, = ax.plot([], [], trail_style, lw=1.8, alpha=0.8, label="Trail")
    
        tri_pts = _triangle_points(es[0], ns[0], psis[0], L=tri_len, W=tri_w)
        aircraft = patches.Polygon(tri_pts, closed=True, ec='k', fc='g', alpha=0.9, zorder=5, label="UAV")
    
        ax.add_patch(aircraft)
        ax.legend(loc='best')
    
        def init():
            trail_line.set_data([], [])
            aircraft.set_xy(_triangle_points(es[0], ns[0], psis[0], L=tri_len, W=tri_w))
            return trail_line, aircraft
    
        def update(frame):
            trail_line.set_data(es[:frame+1], ns[:frame+1])
    
            tri = _triangle_points(es[frame], ns[frame], psis[frame], L=tri_len, W=tri_w)
            aircraft.set_xy(tri)
            return trail_line, aircraft
    
        frames = range(0, len(hist), max(10, int(stride)))
        ani = animation.FuncAnimation(fig, update, frames=frames,
                                      init_func=init, interval=interval_ms,
                                      blit=False, repeat=False)
        return ani, fig
    
    
    def _triangle_points(x, y, theta, L=80.0, W=40.0):
        base = np.array([
            [ L/2,   0.0   ],
            [-L/2,  W/2   ],
            [-L/2, -W/2   ] 
        ])
    
        c, s = np.cos(np.pi/2-theta), np.sin(np.pi/2-theta)
        R = np.array([[c, -s],[s, c]])
        rot = (R @ base.T).T
        rot[:, 0] += x
        rot[:, 1] += y
        return rot


  6. main : 메인 블록
    마지막 메인 블록에서는 시뮬레이션 환경을 설정하고 초기 상태와 제어 입력 시퀀스를 정의한다. 제어 입력은 특정 시각마다 요각속도와 가속도를 변경하는 방식으로 구성되어 있으며, 예를 들어 10~20초에는 양의 요각속도를 주어 우선회, 30~40초에는 음의 요각속도로 좌선회하도록 설정했다. 초기 상태를 지정한 뒤 simulate_unicycle로 시뮬레이션을 수행하고, 그 결과를 animate_simulation으로 시각화한다.

    if __name__ == "__main__":
        total_time = 50.0
        sim_dt  = 0.01
        ctrl_dt = 0.1
        interval_ms=1
        
        # Input Setting, time, omega, acc
        uav1_u = np.zeros((6, 3), dtype=float)
        uav1_u[0, :] = [0.0 ,   0.0,  0.0]
        uav1_u[1, :] = [10.0,   0.2,  0.0]
        uav1_u[2, :] = [20.0,   0.0,  0.0]
        uav1_u[3, :] = [30.0,  -0.2,  0.0]
        uav1_u[4, :] = [40.0,   0.0,  0.0]
        uav1_u[5, :] = [101.0,  0.0,  0.0]
    
        # Initialize [n, e, psi(rad), v(m/s)]
        x0 = [-100.0, -900.0, 0.0, 50.0]
    
        # Simulation
        T, X = simulate_unicycle(uav1_u, x0, total_time, sim_dt, ctrl_dt, method="rk4")
    
        # Visualize
        ani, fig = animate_simulation(X, interval_ms)
        ani.save("uav_simulation.mp4", writer=animation.FFMpegWriter(fps=30))
        
        plt.show(block=False) 
        plt.pause(5)          
        plt.close(fig)


  7. 코드 실행 결과
    전체 코드를 실행시키게 되면 시뮬레이션의 결과가 애니메이션의 형태로 출력된다. 시뮬레이션에서는 50초 동안 직진, 우선회, 직진, 좌선회, 직진의 기동이 시간표 기반 제어 입력에 따라 이루어지며, 각 프레임에서 UAV의 위치, 방향, 궤적이 시각적으로 업데이트되어 비행 경로를 직관적으로 확인할 수 있다.



이번에 구현한 유니사이클 기반 UAV 시뮬레이션과 애니메이션 저장 코드는 단순한 기동 재현을 넘어, 향후 다양한 제어 알고리즘 적용, 경로 계획 등으로 공학 문제로 확장해 실험할 수 있는 기반이 된다. 이를 토대로 보다 복잡한 환경과 제약 조건 속에서 UAV의 거동을 시뮬레이션하며, 다양한 시도와 응용을 이어갈 예정이다. 질문이나 오류가 발생한다면 얼마든지 댓글을 달아주기 바란다. 이로써 오늘의 포스팅을 마무리하도록 하겠다.

 

UAV_Sim_ver1.py
0.00MB
  1. pip이란 무엇인가?
    파이썬을 이용해 실제로 무언가를 개발하거나 분석하려 하면 거의 반드시 외부 패키지를 설치하는 단계가 필요하다. 순수한 Python만으로 가능한 작업은 한계가 있기 때문이다. 이미 만들어져 있는 수많은 라이브러리를 가져다 쓰면 개발 속도가 비약적으로 빨라지고, 복잡한 수학 연산이나 머신러닝 알고리즘, 웹 서비스 구현 등도 쉽게 접근할 수 있다. 이러한 외부 라이브러리를 설치할 수 있도록 해주는 도구가 바로 pip이다. pip은 Python Package Installer의 줄임말로, 파이썬의 공식 패키지 저장소인 PyPI(Python Package Index)에서 원하는 라이브러리를 다운로드하고 설치할 수 있게 해준다. 요즘은 대부분의 Python 배포판에 pip이 기본으로 포함되어 있어서 따로 설치할 필요가 없지만, 아주 오래된 버전을 사용 중이라면 수동으로 설치해야 하는 경우도 있다. pip은 단순한 설치 도구 그 이상의 역할을 한다. 라이브러리의 버전 관리를 돕고, 특정 조건을 만족하는 버전만 설치하거나, 이미 설치된 패키지를 제거하거나 최신 버전으로 업데이트하는 등 개발 과정에서 유용한 다양한 기능을 제공한다.


  2. pip 기본 사용 방법
    가장 일반적인 명령어는 pip install 패키지명이다. 이전 포스팅에서 가상환경을 설정하는것과 관련된 내용을 다루며 사용한 예로 pip install numpy는 과학 계산용 패키지인 numpy를 설치한다. 만약 특정 버전을 설치하고 싶다면 pip install numpy==1.25.2처럼 명시할 수 있으며, 최소 버전 이상을 요구하는 경우 pip install "pandas>=1.3"처럼 조건을 줄 수도 있다. 이미 설치된 패키지를 최신 버전으로 업그레이드하려면 pip install --upgrade 패키지명을 사용하면 된다. 만약 설치된 패키지를 강제로 재설치하고 싶다면 pip install --force-reinstall 패키지명으로 처리하면 된다. 이렇게 pip의 기본적인 명령어만 잘 숙지해도 대부분의 패키지 설치 및 관리는 어렵지 않게 할 수 있다.


  3. requirements.txt로 여러 패키지 한 번에 설치하기
    하나의 프로젝트에 여러 패키지를 사용하는 경우, 각 개발자가 패키지를 일일이 설치하는 것은 비효율적이다. 또한 동일한 개발 환경을 여러 컴퓨터에서 재현하려면 패키지 목록을 명확히 기록해두는 것이 중요하다. 이를 위해 사용하는 것이 바로 requirements.txt이다. 이 파일은 프로젝트에서 사용하는 모든 패키지와 그 버전을 기록해 놓은 텍스트 파일이다. pip install -r requirements.txt 명령어를 실행하면 이 파일에 정의된 모든 패키지가 한 번에 설치된다. 예를 들어 numpy==1.25.0, matplotlib>=3.5, scikit-learn 같은 내용을 담고 있는 requirements.txt 파일은 매우 직관적이며, 버전 충돌을 방지하고 협업 환경을 통일시키는 데 유용하다. 현재 내 개발 환경에서 설치된 모든 패키지를 리스트로 뽑아내고 싶다면 pip freeze > requirements.txt 명령어를 사용하면 된다. 이 방법은 내가 지금 작업하고 있는 환경을 다른 사람에게 그대로 넘기고 싶을 때 특히 유용하다. 한마디로 requirements.txt는 ‘개발 환경의 스냅샷’이라 할 수 있다.

    # requirements.txt에 pip 목록을 설치하기
    pip install -r requirements.txt
    
    # 설치된 pip 목록을 requirements.txt로 뽑아내기
    pip freeze > requirements.txt

    # requirement.txt 예시
    
    numpy==1.25.2
    torch==2.1.0
    gym==0.26.2
    matplotlib==3.7.1
    tensorboard==2.14.0
    scipy==1.11.2
    stable-baselines3==2.1.0
    optuna==3.2.0
    pyyaml==6.0

    아래 그림은 pip freeze > requirements.txt를 활용하여 pip 목록을 requirements.txt로 만들어낸 상태이다. requirements.txt를 확인하면 지난번 설치해둔 numpy가 목록으로 출력된 상태인것을 확인할 수 있다.



  4. pip로 설치된 패키지 관리하기
    pip은 단순히 설치만 하는 도구가 아니다. 이미 설치된 패키지들을 확인하거나 제거하거나, 업데이트할 수도 있다. pip list 명령어는 현재 환경에 설치된 모든 패키지 목록을 보여준다. 특정 패키지의 정보를 알고 싶다면 pip show 패키지명으로 버전, 의존성, 설치 위치 등을 확인할 수 있다. 필요 없는 패키지를 제거하려면 pip uninstall 패키지명을 사용하면 된다. 또한 pip list --outdated 명령어로 현재 설치된 패키지들 중 업데이트가 가능한 항목들을 확인할 수 있고, 이를 기반으로 선택적으로 업그레이드할 수 있다. 패키지를 잘 관리하면 환경이 깔끔해지고, 예상치 못한 충돌도 예방할 수 있다. 관련된 명령어들을 아래 표에 정리해놓았다.


    명령어 설명 예시
    pip install 패키지 설치 pip install numpy
    pip install 패키지==버전 특정 버전 설치 pip install pandas==1.3.5
    pip install --upgrade 최신 버전으로 업그레이드 pip install --upgrade matplotlib
    pip install -r 파일명.txt 여러 패키지를 한 번에 설치 pip install -r requirements.txt
    pip uninstall 패키지 제거 pip uninstall requests
    pip list 현재 설치된 패키지 목록 출력 pip list
    pip show 특정 패키지의 상세 정보 확인 (버전, 위치, 의존성 등) pip show flask
    pip list --outdated 업데이트 가능한 패키지 확인 pip list --outdated
    pip freeze 설치된 패키지 목록을 requirements.txt 형식으로 출력 pip freeze > requirements.txt
    pip check 설치된 패키지 간 의존성 문제 확인 pip check
    pip cache dir pip 캐시 저장 경로 확인 pip cache dir
    pip cache purge pip 다운로드 캐시 전체 삭제 pip cache purge
    pip help pip 명령어 전체 목록 및 사용법 확인 pip help
    pip install --user 현재 사용자 계정으로만 설치 pip install --user rich
    pip install --no-cache-dir 캐시 없이 설치 (문제 해결 시 유용) pip install somepackage --no-cache-dir
    pip install --force-reinstall 이미 설치된 패키지를 강제로 다시 설치 pip install --force-reinstall numpy


  5. 가상환경과 pip의 관계
    pip을 사용할 때 반드시 함께 고려해야 하는 것이 바로 가상환경이다. 이전 포스팅에서 언급하였듯 가상환경이란, 각 프로젝트마다 독립된 Python 환경을 만들어주는 기능이다. 이를 통해 프로젝트마다 다른 버전의 패키지를 사용할 수 있으며, 시스템 전체에 영향을 주지 않기 때문에 매우 안전하고 유연한 개발이 가능해진다. 예를 들어 프로젝트 A는 numpy 1.XX 버전을, 프로젝트 B는 numpy 2.XX 버전을 사용할 경우, 가상환경이 없다면 충돌이 일어난다. 하지만 각 프로젝트마다 venv를 만들어 사용한다면 이러한 문제를 말끔히 피할 수 있다. 가상환경과 관련된 내용은 아래 포스팅을 참고 바란다.

    2025.08.04-[알쓸신잡 연구노트 M&S 5편] VS Code 활용 Python 개발을 위한 가상 환경 설정
     

    [알쓸신잡 연구노트 M&S 5편] VS Code 활용 Python 개발을 위한 가상 환경 설정

    가상환경 개요파이썬 개발 환경을 구축할 때 가장 중요한 요소 중 하나가 바로 '가상 환경(Virtual Environment)'이다. 가상 환경이란, 각각의 파이썬 프로젝트를 독립적으로 운영하기 위해 사용하는

    piggymode.tistory.com

 

이번 포스텡에서는 pip의 개념부터 설치와 활용, 가상환경과의 연계, 패키지 관리에 이르기까지 pip install을 둘러싼 전반적인 내용을 정리해보았다. 파이썬 프로젝트를 진행할 때 pip install은 단순한 명령어 그 이상으로, 여러분의 환경을 구성하고 오류를 방지하며, 효율적인 협업을 가능하게 해주는 중요한 도구가 될 것이다. 이로써 포스팅을 마치도록 하겠다.

  1. 가상환경 개요
    파이썬 개발 환경을 구축할 때 가장 중요한 요소 중 하나가 바로 '가상 환경(Virtual Environment)'이다. 가상 환경이란, 각각의 파이썬 프로젝트를 독립적으로 운영하기 위해 사용하는 격리된 환경을 말한다. 가상 환경을 사용하지 않으면 모든 프로젝트가 시스템의 공통 파이썬 환경을 공유하게 되어, 패키지 버전 충돌 문제나 의존성 충돌로 인한 문제를 겪을 가능성이 높아진다. 혹시나 아직 VS Code를 설치하지 않았거나 Python 패키지를 못했다면 아래의 글을 참고하기 바란다.

    2025.07.29-[알쓸신잡 연구노트 3편] MS Visual Studio Code 설치
     


    [알쓸신잡 연구노트 3편] MS Visual Studio Code 설치

    프로그래밍을 시작하거나 본격적인 개발 환경을 구축할 때, 가장 먼저 떠오르는 도구 중 하나가 바로 Visual Studio Code (VS Code)이다. Microsoft에서 개발한 이 경량 IDE는 무료이면서도 강력한 확장성,

    piggymode.tistory.com



    2025.08.01-[알쓸신잡 연구노트 4편] MS Visual Studio Code 활용 Python 개발 환경 설정
     

    [알쓸신잡 연구노트 4편] MS Visual Studio Code 활용 Python 개발 환경 설정

    파이썬을 본격적으로 배우기 시작하면서 중요한 것 중 하나는 나만의 개발 환경을 구성하는 일이다. 특히 초보자들에게는 복잡한 설정보다는 직관적이고 쉽게 다룰 수 있는 도구가 필요하다.

    piggymode.tistory.com



  2. 가상환경 필요성
    가상환경이 필요한 이유는 이렇다. 예를 들어, 하나의 프로젝트는 TensorFlow 2.6을 필요로 하고, 또 다른 프로젝트는 TensorFlow 1.15를 필요로 한다고 가정한다. 이러한 경우 시스템 전역에 두 버전의 TensorFlow를 동시에 설치하는 것은 불가능하거나 매우 복잡하다. 이때 가상 환경을 사용하면 각 프로젝트마다 독립적인 환경을 만들어 원하는 버전의 패키지를 설치하고 충돌 없이 운영할 수 있다.

    또한, 새로운 기능을 추가하거나 기존 기능을 수정할 때는 여러가지 패키지를 실험적으로 설치하거나 제거해보는 과정이 빈번하게 발생한다. 만약 모든 프로젝트가 같은 환경을 공유한다면, 하나의 프로젝트에서 패키지를 추가하거나 제거했을 때 다른 프로젝트가 원치 않는 영향을 받을 수 있다. 예를 들어 프로젝트 A에서 최신 버전의 패키지를 테스트하기 위해 업그레이드를 진행하면 패키지 의존성이 서로 얽혀있던 프로젝트 B는 버전 호환성 등의 문제로 인해 작동하지 않게 될 수도 있다.

    이런 문제를 방지하기 위해 각 프로젝트를 위한 독립적인 가상 환경을 설정하고 운영하면 특정 프로젝트의 패키지 변경 사항이 다른 프로젝트에 전혀 영향을 미치지 않도록 할 수 있다. 이러한 격리 환경을 구성하여 자유롭게 새로운 기능을 시도하고 다양한 라이브러리를 실험해볼 수 있는 유연성을 가지게 된다.


  3. 가상환경 설정 방법
    가상환경을 설정하는 절차는 매우 간단하다. 절차는 아래와 같다.

    - 가상환경 패키지 설치
    다음의 코드를 활용하여 가상환경 패키지를 설치한다.
    sudo apt install python3-venv

    - 가상환경 생성
    다음의 코드를 활용하여 가상환경을 구성하게 되는데 지정된 폴더 내에 지정된 명칭으로 폴더가 생기게 됨으로 cd 명령어를 활용하여 작업 디렉터리를 가상환경을 구성하고자 하는 폴더로 이동한 후 가상환경 생성 코드를 실행한다. 아래 코드는 이전에 생성해놓은 작업 폴더 python_ex 내에 project1이라는 가상환경을 생성하기 위한 코드이다.
    cd /home/han/Documents/Works/python_ex
    python3 -m venv project1

    - 가상환경 활성화/비활성화
    가상환경의 활성화/비활성화 코드는 아래와 같다.
    # 활성화 시
    source project1/bin/activate  # Linux/macOS
    
    # 비활성화 시
    deactivate


  4. 가상환경 활용 예시
    활용 예시를 보며 활용 방법에 대해 숙지하도록 하겠다. 

    - 가상환경 활성화 후 numpy 패키지 설치
    가상 환경이 활성화되면 터미널 프롬프트 앞에 (project1)라는 이름이 표시된다. 이 상태에서는 설치하는 모든 파이썬 패키지가 이 특정 가상 환경 내에만 저장되므로, 다른 프로젝트나 시스템 전역 환경에는 영향을 주지 않는다. 이후 아래 코드를 활용하여 numpy 패키지를 설치한다.
    # 가상환경 활성화
    source project1/bin/activate
    
    # numpy 설치
    pip install numpy



    - 가상환경 비활성화 후 numpy 패키지 호출 코드 실행 : 오류 발생
    다음은 실험을 위하여 가상환경을 비활성화 후 numpy 패키지를 불러오는 코드를 실행시켜본다. 지난 포스팅에서 생성한 파이썬 코드 파일 example1.py에 numpy를 불러오기 위한 코드를 추가한다. 이후 가상환경 비활성화시킨다. 가상환경에서 빠져나오게 되며 터미널 프롬프트 앞에 가상환경 표시가 사라지게 된다. 이후 example1.py 코드를 실행하게 되면 현재 numpy 패키지는 project1 가상 환경에서 설치가 되었음으로 가상환경을 비활성화를 시킨 이후에는 numpy가 설치되지 않았다는 오류가 발생하게 된다.


    - 가상환경 활성화 후 numpy 패키지 호출 코드 실행 : 실행 성공
    다음은 numpy 패키지를 설치한 가상환경을 활성화 시킨 후 동일한 example1.py 코드를 실행시킨다. 가상환경에 설치된 패키지로 접근하며 코드가 오류없이 실행됨을 확인할 수 있다.

 

위에서 살펴본 예시를 통해 가상 환경의 실제 활용법을 파악해보았다. 앞으로 파이썬으로 다양한 프로젝트를 진행할 때 가상 환경을 적절히 활용하면, 서로 다른 프로젝트 간의 버전 충돌을 방지하고 체계적으로 개발 환경을 관리할 수 있을 것이다. 이러한 습관은 장기적으로 개발 생산성을 높이고 유지보수를 더욱 효율적으로 만들어 줄 것이다. 이상으로 포스팅을 마치도록 하겠다.

파이썬을 본격적으로 배우기 시작하면서 중요한 것 중 하나는 나만의 개발 환경을 구성하는 일이다. 특히 초보자들에게는 복잡한 설정보다는 직관적이고 쉽게 다룰 수 있는 도구가 필요하다. 그런 점에서 Visual Studio Code, 즉 VS Code는 매우 훌륭한 선택이다. 이 글에서는 Ubuntu 24.04 환경에서 설치된 VS Code를 활용하여 파이썬 기본 개발 환경을 설정하고 첫 번째 코드를 실행하기까지의 과정을 소개하고자 한다. VS Code를 아직 설치하지 않았다면 이전에 올렸던 블로그 포스팅에 쉽고 직관적으로 설명을 해놓았으니 참고하기 바란다.

2025.07.29 - [분류 전체보기] - [알쓸신잡 연구노트 3편] MS Visual Studio Code 설치

 

[알쓸신잡 연구노트 3편] MS Visual Studio Code 설치

프로그래밍을 시작하거나 본격적인 개발 환경을 구축할 때, 가장 먼저 떠오르는 도구 중 하나가 바로 Visual Studio Code (VS Code)이다. Microsoft에서 개발한 이 경량 IDE는 무료이면서도 강력한 확장성,

piggymode.tistory.com

 

 

  1. VS Code 실행
    설치가 완료된 VS Code를 실행하면 아래 그림과 같은 초기 화면을 마주하게 된다. 이 화면에서는 다양한 추천 작업 항목들이 나열되어 있고, 기본적인 설정을 도와주는 기능들도 함께 제공된다. AI 기반 코드 생성 도구인 Copilot과 관련된 안내도 뜨지만, 본 글의 목적은 파이썬 개발 환경이므로 이를 우선 넘기고 확장 기능 설치로 바로 넘어간다.



  2. 파이썬 및 확장 기능 설치
    파이썬을 VS Code에서 제대로 활용하기 위해서는 관련 확장 기능을 설치해야 한다. 화면 왼쪽의 확장 아이콘(네모 형태)을 클릭하거나 단축키 Ctrl+Shift+X를 눌러 확장 프로그램 검색 창을 연다. 상단 입력창에 ‘Python’을 입력하면 다양한 파이썬 관련 확장 기능들이 나타난다. 이 중에서도 가장 상단에 위치한 Microsoft의 공식 ‘Python’ 확장을 선택해 설치한다. 이 확장은 코드 자동완성(IntelliSense), 문법 검사, 디버깅, 실행환경 탐색 등 VS Code에서 파이썬을 다룰 때 필요한 거의 모든 기능을 제공한다. 설치 후 자동으로 관련 하위 확장 기능들이 함께 설치되므로 매우 편리하다. 추가적으로, 더 다양한 기능을 함께 사용하고 싶다면 ‘Python Extension Pack’을 설치하는 것도 좋은 선택이다. 이 확장팩은 기본 Python 확장을 포함하여 자동으로 주석을 생성해주는 autoDocstring, Jinja 템플릿 엔진 지원 등의 부가 기능도 함께 제공한다. 이처럼 VS Code는 원하는 기능들을 모듈화된 확장을 통해 유연하게 구성할 수 있다는 장점이 있다.

    - 확장아이콘 클릭 > 'python' 검색 > Install 버튼으로 설치 > Uninstall 버튼으로 바뀌면 설치 완료
    - Python 설치
    - Python Extension Pack 설치



  3. 작업 폴더 지정
    확장을 설치한 후에는 실제로 코드를 작성할 작업 폴더를 VS Code에서 열어야 한다. 필자는 'Documents/Works' 디렉토리 하위에 'python_ex'라는 폴더를 만들어 이 폴더를 VS Code에서 열었다. 파일 탐색기에서 폴더를 생성한 후, VS Code에서 'Open Folder' 메뉴를 클릭하고 해당 경로를 선택하면 된다. 이렇게 하면 프로젝트 기반의 구조가 만들어지고, 이후 생성하는 모든 파일은 이 폴더 안에 저장되므로 관리가 훨씬 편해진다.

    &


  4. 파이썬 파일 생성
    작업 폴더를 연 후에는 이제 코드를 작성할 새 파일을 만들 차례다. VS Code에서는 좌측 탐색기 영역의 ‘+’ 아이콘을 클릭하거나, 메뉴에서 ‘New File’을 선택하면 새로운 탭이 열린다. 처음 생성할 때는 확장자가 없는 일반 텍스트 파일이지만, 저장하기 전에 언어를 선택하거나 파일명에 .py 확장자를 붙이면 파이썬 파일로 자동 인식된다. 또는 파일 상단에 표시되는 선택창에서 Python File을 클릭하여 언어를 지정해줄 수도 있다.
    이제 새 파일에 간단한 코드를 작성해본다. 가장 기본적인 예제로 print('Hello World!') 한 줄을 입력한다. 그리고 파일 이름을 지정하여 저장한다. 여기서는 example1.py로 저장하였다. 파일을 저장하는 위치는 아까 열었던 'python_ex' 폴더 내부가 된다. 이처럼 간단한 코드지만, 이것이 환경 설정이 제대로 되었는지를 검증하는 가장 직관적인 방법이다.



  5. 파이썬 파일 실행
    다음으로는 작성한 파이썬 코드를 실제로 실행해보는 과정이 필요하다. VS Code에는 통합 터미널이 내장되어 있어 굳이 외부에서 터미널을 다시 열지 않아도 된다. 상단 메뉴에서 Terminal → New Terminal을 선택하거나, 단축키 Ctrl+` (백틱, 숫자 1 왼쪽에 위치)을 눌러 터미널을 실행할 수 있다. 터미널이 열리면 현재 작업 중인 폴더가 기본 경로로 설정되어 있으므로 별다른 이동 없이 바로 코드를 실행할 수 있다.
    작성한 파일을 실행하려면 터미널에서 다음과 같이 입력한다. 파일명이 hello.py인 경우에는 다음 명령어를 사용한다. 위 명령을 실행하면 'Hello World!'라는 출력 결과가 터미널에 나타나게 되며, 이는 환경 설정이 성공적으로 완료되었음을 의미한다. 만약 python3 명령어가 인식되지 않는다면, 시스템에 파이썬이 제대로 설치되어 있는지 또는 PATH 환경변수 설정에 문제가 없는지를 확인할 필요가 있다.

 

정리하자면, VS Code에서 파이썬 개발 환경을 설정하는 전체 과정을 살펴보았다. 처음 설정하는 과정이 다소 번거롭게 느껴질 수 있지만, 일단 한 번 익숙해지면 이후부터는 매우 빠르게 프로젝트를 시작할 수 있다. 이 글을 통해 VS Code에서의 파이썬 개발이 훨씬 즐겁고 효율적으로 느껴졌길 바란다.

프로그래밍을 시작하거나 본격적인 개발 환경을 구축할 때, 가장 먼저 떠오르는 도구 중 하나가 바로 Visual Studio Code (VS Code)이다. Microsoft에서 개발한 이 경량 IDE는 무료이면서도 강력한 확장성, 다양한 언어 지원, 빠른 실행 속도, 그리고 뛰어난 커스터마이징 기능 덕분에 전 세계 개발자들의 필수 툴로 자리잡았다. Ubuntu를 포함한 리눅스 기반 시스템에서도 VS Code는 매우 안정적으로 동작하며, 특히 Python, C++, Web 개발, ROS, 데이터 분석 등 다양한 분야의 작업에 활용된다. 또한 Git 연동, 터미널 내장, 자동완성, 디버깅 기능 등 실무에서 필요한 기능이 기본적으로 잘 갖춰져 있어 초보자부터 고급 사용자까지 두루 선호되고 있다.

이번 포스팅에서는 이러한 VS Code를 우분투에서 설치하기 위한 2가지 대표적인 방법에 대해 기술한다.

  • 터미널에서 설치하는 방식
  • 공식 웹사이트에서 파일을 다운로드하여 설치하는 방식
  1. 터미널에서 설치하는 방식
    이 방식은 터미널에서 MS 공식 레포지토리에 접근하여 설치를 진행하는 방식이다.
    우선 아래 코드를 실행하여 필수 패키지들을 설치한다.

    - software-properties-common : 레포지터리 추가 명령어를 사용하기 위한 패키지. Ubuntu에서는 기본으로 제공하지 않아 별도 설치가 필요하다.

    - apt-transport-https : APT가 HTTPS(보안 HTTP) 프로토콜을 통해 저장소에 접근할 수 있도록 해주는 패키지이다.

    - wget : HTTP 또는 FTP 통신을 통해 서버로부터 콘텐츠를 가져오는 프로그램이다. 이름은 World Wide Web과 get의 합성어이며, 웹 크롤링 기능도 지원하여 여러 링크를 순회하며 자동으로 다운로드할 수 있다.

    # 필수 패키지 설치
    sudo apt update
    sudo apt install software-properties-common apt-transport-https wget


    패키지를 설치한 이후에는 VS Code를 설치하기 전에 Microsoft의 GPG 키를 등록해야 한다. GPG 키는  (GNU Privacy Guard)의 줄임말록 RSA 암호화... 파고드려니 너무 어렵다. 쉽게 설명해서 APT가 설치하려는 패키지의 커밋에 대한 보안 및 신원 확인을 위해서하는 데 사용된다. 즉 GPG 키는 패키지의 서명을 검증하는 용도로, 패키지가 설치 도중 변조되지 않았는지를 확인해준다. 우리는 Microsoft의 공개 키를 시스템에 등록하고, APT는 그 키를 이용해 VS Code 패키지를 자동으로 검증한다. 이를 위해 아래 명령어를 사용한다.

    # GPG 키 등록
    wget -q https://packages.microsoft.com/keys/microsoft.asc -O microsoft.gpg
    sudo install -o root -g root -m 644 microsoft.gpg /etc/apt/trusted.gpg.d/


    다음은 Microsoft에서 제공하는 공식 VS Code 저장소를 Ubuntu의 APT 시스템에 추가한다. 이를 통해 APT가 이 저장소에서 VS Code 패키지를 찾아 설치하고, 이후에도 자동 업데이트가 가능해진다.

    # 저장소 추가
    sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/vscode stable main" > /etc/apt/sources.list.d/vscode.list'


    여기까지의 절차를 완료했다면 드디어 VS Code를 설치할 준비가 되었다. 아래 코드를 활용해 업데이트 후 설치를 진행한다. 

    # VS Code 설치
    sudo apt update
    sudo apt install code


    이러한 과정을 거쳐 설치를 진행하게 되면 설치 과정 중에 자동으로 VS Code의 실행파일이 시스템 Path에 등록이 되기 때문에 Code를 실행하기 위하여 터미널에서 아래 명령어로 아주 간편하게 진입이 가능하다.


  2. 공식 웹사이트에서 파일을 다운로드하여 설치하는 방식
    VS Code를 공식 웹사이트에서 설치하는 방식은 매우 간편하며 직관적이다. 다만 추후 버전 업데이트가 되는 경우 앞선 설치 방법은 레포지터리가 등록되어 있어 간편한 업데이트가 가능하지만 직접 다운받는 해당 방법으로 설치를 진행하는 경우엔 동일한 방법으로 새로 설치하는 방법을 거쳐야 한다.

    - MS VS Code 공식 홈페이지
    https://code.visualstudio.com/
     

    Visual Studio Code - Code Editing. Redefined

    Visual Studio Code redefines AI-powered coding with GitHub Copilot for building and debugging modern web and cloud applications. Visual Studio Code is free and available on your favorite platform - Linux, macOS, and Windows.

    code.visualstudio.com


    공식 홈페이지에 들어가서 Linux를 위한 설치파일을 다운받아 실행하게 되면 아주 간편하게 설치가 가능하다. 다운받은 .deb파일을 실행하기 위한 코드는 아래와 같다. 터미널에서 다운받은 파일이 위치한 디렉터리로 이동한 후 해당 코드를 입력해주면 된다. 설치가 완료된 이후 터미널에서 code 명령어를 통해 VS Code를 실행할 수 있다.

    sudo dpkg -i (다운받은파일명).deb

지금껏 살며 처음으로 맞춰본 데스크탑에 Ubuntu LTS 운영체제를 설치하며 새 컴퓨터이니 모든것이 잘 풀릴거라 기대하였다. 하지만 예상과는 달리 ‘설치’ 자체가 전혀 순탄하지 않았고 꽤나 고생스러운 여정이었다. Ubuntu를 설치하고 그래픽 카드를 인식시키는 과정동안 겪었던 시행착오를 간단히 정리하면 아래와 같다. 우선 사용하는 컴퓨터의 사양은 아래와 같다.
- CPU: Ryzen 5 9600X3D
- GPU: Nvidia RTX 5060 Ti

 

  1. Ubuntu 22.04 버전 설치 시도 (실패)
    Nvidia에서 개발한 Isaac Sim을 구동해보는 목적으로 데스크탑을 구매하였는데 Isaac Sim의 권장 Ubuntu 버전이 22.04라고 하여 가장 최신 LTS 버전인 24.04를 두고 조금 지난 22.04 버전의 설치를 우선 시도하였다. 이 과정 중 문제가 발생한다.

    문제 증상
    - GRUB화면 (Try or Install Ubuntu 화면)까지 진입. 그러나 Install 메뉴 선택 시 까만 화면에서 먹통, 탈출 불가

    시도 1 (실패)
    - Try or Install Ubuntu에 커서 올려놓은 상태로 "e" 입력, 편집모드 진입
    - quiet splash 코드 부분을 찾아서 아래와 같이 수정
    quiet splash nomodeset

    nomodeset 코드는 리눅스 커널이 부팅 중에 GPU 드라이버를 사용하지 않도록 막는 역할을 한다. 리눅스는 부팅 도중에 GPU 드라이버를 불러와서 해상도 설정이나 그래픽 초기화를 하려 하는데, 호환되지 않거나 버그가 있는 경우 까만 화면이나 부팅 실패로 이어질 수 있다. 이럴 때 nomodeset을 사용하면 그래픽 초기화를 설치 후 드라이버가 제대로 로드될 때까지 기본 VGA 모드로 진입하게 된다.

    시도 2 (실패)
    nomodeset 코드를 추가하는것 되에도 Bios에서 Fast Boot 옵션 혹은 Secure Boot 옵션을 Off 해야한다고 하여 설정

    Fast Boot : BIOS 단계에서 하드웨어 초기화를 생략하거나 최소화해서 부팅 속도를 빠르게 하는 기능이다. USB 설치 디스크를 제대로 인식하지 못하거나, 부팅 중 입력 장치가 작동하지 않는 경우가 생길 수 있다.

    Secure Boot : 컴퓨터 부팅 시 검증 받지 않은 프로그램의 실행을 막는 보안 시스템이다.Ubuntu를 설치하기 위해 반드시 Secure Boot를 비활성화 할 필요는 없지만 특정 타사 드라이버(일부 독점 그래픽 드라이버 등)를 사용하려는 경우 보안 부팅과 호환되지 않을 수 있으므로 보안 부팅을 비활성화하고 설치하는것을 권한다.


  2. Ubuntu 24.04 버전으로 설치 재시도 (성공)
    문제를 해결하기 위하여 검색을 하던 중 최신 그래픽카드가 Ubuntu 22.04에서 사용하는 커널 버전에서는 제대로 인식되지 않을수도 있다는것을 알게 되었다. 아무래도 22.04는 2022년 기준의 드라이버와 커널을 포함하고 있어서, 최신 GPU나 메인보드와의 호환성이 부족했던 것이다.

    문제 증상 1
    - GRUB화면 (Try or Install Ubuntu 화면)까지 진입. 그러나 Install 메뉴 선택 시 까만 화면에서 먹통, 탈출 불가

    시도 1 (설치 성공)
    - Try or Install Ubuntu에 커서 올려놓은 상태로 "e" 입력, 편집모드 진입
    - 22.04 버전에서 했던것과 같이 quiet splash 코드 부분을 찾아서 quiet splash nomodeset으로 수정

    문제 증상 2
    - Ubuntu의 설치는 완료하였으나 화면의 해상도가 1024*768로 고정됨, 그래픽 카드 인식 불가
    - 아래 코드로 Nvidia 그래픽 드라이버 검색 시 장치를 찾을 수 없다고 출력
    nvidia-smi
     


    시도 1 (실패)
    자동 설치 - 그래픽 드리이버가 인식이 안되는것같아서 아래 코드를 활용하여 드라이버를 자동 설치해주었다.아래 코드를 활용하면 권장드라이버를 자동으로 설치해준다.
    sudo ubuntu-drivers autoinstall


    수동 설치 - 자동설치를 사용하여 권장되는 버전을 다운받는것이 아닌 원하는 버전을 직접 다운받을 수 있다.아래 코드를 활용하면 원하는 드라이버의 버전으로 설치해본다.아래 코드를 입력하였을때 뒤에 recommended가 적힌 버전이 권장 버전이라고한다.
    ubuntu-drivers devices


    권장하는 버전을 찾았다면 아래 코드를 활용하여 설치를 진행하면 된다. XXX 부분에 권장 설치 버전의 넘버를 입력하면 된다.
    sudo add-apt-repository ppa:graphics-drivers/ppa
    sudo apt update
    
    sudo apt install nvidia-driver-XXX
    
    sudo apt update
    sudo apt upgrade
    sudo reboot


    시도 2 (성공)
    결국 성공한 시도는 무엇이었냐하면 계속된 오류에 인하여 검색을 지속하는 도중 다음과 같은 글을 발견하였다. Bios에서 Resize Bar 메뉴를 On, 그리고 홈페이지에서 직접 다운받은 드라이버로 설치를 진행해야된다고 한다. Bios에서 설정하는것은 간단하여 생략하고 홈페이지에서 직접 받은 드라이버를 설치하는 절차에 대해 간략히 기술하겠다.

    우선 다음의 절차로 그래픽카드 드라이버를 설치한다.



    다운로드를 클릭하면 선택한 버전의 .run 그래픽 드라이버 설치 파일을 다운받게 된다. 해당 파일을 실행하기 위해서는 실행 권한 파일을 활성화를 해주어야 하는데 chmod 명령어를 활용하면 가능하다.XXX.XX.XX에는 설치한 드라이버의 버전을 입력해주면 된다. 이후 해당 드라이버 .run 파일을 실행한다.
    chmod a+x NVIDIA-Linux-x86_64-XXX.XX.XX.run

    실행 권한 활성화를 해준 후에는 그래픽 카드를 종료하기 위해 TTY에 접근하여 작업을 진행해야 한다. TTY는 Teletype 의 줄임말로, GUI(그래픽 사용자 인터페이스) 없이 텍스트만 입력 가능한 터미널 환경을 말한다. TTY는아래 명령어를 통해 접근할 수 있다. 사용하던 GUI가 없어지고 텍스트 기반의 인터페이스로 전환되니 놀라지 않도록 한다.
    Ctrl + Alt + F3  >>  TTY 접근 F1~F6까지 가능
    Ctrl + Alt + F7  >>  TTY 이탈

    TTY 에 접근한 이후에는 독자의 ID와 PW를 입력하여 로그인을 진행한 후 앞서 다운받은 .run 파일의 디렉터리를 찾아가 해당 파일을 실행하주면 설치가 진행된다.
    sudo ./NVIDIA-Linux-x86_64-XXX.XX.XX.run
     
    설치를 진행할 때 가장 중요한 것은 설치중 NVIDIA Proprietary가 아닌 MIT/GPL로 설치해야 성공적으로 그래픽 카드가 인식이 완료된다. 이 부분은 추후에 업데이트 지원이 추가될 것으로 보이지만 현재로써는 그렇다.


    설치가 완료된 후 다시 그래픽 카드의 상태를 확인해보면 다음과 같이 뜨며 그래픽 카드의 인식이 성공적으로 수행된것을 확인할 수 있다.

 

+ Recent posts