개요

WSL 내 우분투 OS에서 컴퓨터 비전 관련 프로젝트를 테스트해 볼 일이 있어 작업 중 기본적으로는 WSL 내에서 노트북에 내장된 카메라 혹은 USB로 연결 된 장비를 사용하지 못한다는 것을 알았다. 아예 사용을 못하는 것은 아니고 어찌저찌 장비의 연결을 넘겨주고 WSL의 리눅스 커널을 USB 장치등을 사용할 수 있게 재 빌드해주고 커널을 교체해주면 사용할 수 있는 방법이 있다는 것을 보고 직접 수행해보았다. 결론은 뭔가 될 것 같음에 거의 도달한 것 같은데 최종적으로는 뭔가 제대로 작동하지 않는다.

환경

  • Samsung Galaxy book 2 pro 360
  • windows 11
  • WSL2 Ubuntu 20.04
  • Linux 5.15.90.1-microsoft-standard-WSL2
    • Linux Kernal 5.10.60.1 이상 필요

usbipd install

Windows 에서

WSL의 리눅스 배포판이 아닌 호스트 Windows OS에서 우선 usbipd 프로그램을 설치한다.

Releases 페이지에 있는 .msi 파일을 통해 설치한다.

WSL2 에서

WSL 터미널로 들어가 Ubuntu 20.04 os 내에서 리눅스 사용자 도구 및 하드웨어 식별자 도구를 설치한다.

$ sudo apt install linux-tools-5.4.0-77-generic hwdata
$ sudo update-alternatives --install /usr/local/bin/usbip usbip /usr/lib/linux-tools/5.4.0-77-generic/usbip 20

usb 장치 확인

Windows 터미널을 열고 아래와 같이 명령어를 실행한다. 실행 된 결과로 Windows에 연결된 USB 버스를 통해 연결된 장치가 출력된다.

$ usbipd wsl list

>>>
BUSID  VID:PID    DEVICE                                                        STATE
2-5    1c7a:0582  EgisTec Touch Fingerprint Sensor                              Not attached
2-6    1bcf:2d05  1080p FHD Camera                                              Not attached
2-10   8087:0033  인텔(R) 무선 Bluetooth(R)                                     Not attached
6-1    046a:0077  USB 입력 장치                                                 Not attached
6-5    2109:8817  USB Billboard Device                                          Not attached
7-4    0bda:8152  Realtek USB FE Family Controller                              Not attached

위의 결과와 같이 노트북의 터치센서, 내장카메라, 블루투스 장치. USB 키보드 등의 여러 장치들이 보인다. 그리고 STATENot attached라는 것을 확인할 수 있다.

장치 연결

위에서 각 usb장치의 busid를 확인하였고 다음의 명령어를 통해 windows 터미널에서 wsl2 의 리눅스 배포판으로 장치를 연결해줄 수 있다.

# usbipd wsl attach --busid {busid}
$ usbipd wsl attach --busid 2-6

WSL에서 확인

WSL 의 리눅스 배포판으로 들어와 lsusb 명령어를 통해 연결해준 장비를 확인할 수 있다.

$ lsusb

>>>
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 004: ID 1bcf:2d05 Sunplus Innovation Technology Inc. 1080p FHD Camera
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

위의 결과에서 Bus 001 Device 004 장비는 attach 작업을 해주기 전에는 보이지 않던 장비로 이제 인식이 되는 모양이다.

장치 연결 해제

WSL 내에서 장치를 다 사용했다면 attach 시와 마찬가지로 detach 명령어를 통해 장치를 다시 연결 해제할 수 있다.

# usbipd wsl detach --busid {busid}
$ usbipd wsl detach --busid 2-6

장치 사용 불가

위의 작업만으로는 lsusb 명령어 입력 시 인식된 장치에 출력은 되나 문제는 따로 있다. /dev 파티션에 대해서 아무리 ls 명령어를 입력해봐도 /dev/video0 등의 카메라 장치가 인식되지 않는다. 혹은 꼼수를 피워 장치명이 Bus 001 Device 004 인것을 착안하여 /dev/bus/usb/001/004로 접근해볼 수도 있으나 python3opencv 모듈을 통해 카메라를 열어봐도 전혀 작동하지 않았다.

import cv2

# try 1
cap = cv2.VideoCapture(0)
ret, frame = cap.read()
# fail to read frame 

# try 2
cap = cv2.VideoCapture('/dev/bus/usb/001/004')
ret, frame = cap.read()
# fail to read frame 

아래의 기술할 리눅스 커널 빌드 및 교체 내용을 통해 해결을 시도해보았다.

Linux Kernel Build and replace

패키지 설치 및 커널 버전 확인

WSL 터미널에서 다음 명령어를 통해 커널 빌드에 필요한 패키지를 설치하고 현재 설치되어 있는 커널 버전을 확인한다.

$ sudo apt install -y build-essential flex bison dwarves libssl-dev libelf-dev bc libncurses-dev

$ uname -a

>>> Linux DONGLE-BOOK2 5.15.90.1-microsoft-standard-WSL2 #1 SMP Fri Jan 27 02:56:13 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

uname 명령어의 실행 결과를 보면 일단 커널 버전은 5.15.90 인 것을 알 수 있고 빌드 시기는 2023년 2월 27일 임을 알 수 있다.

커널 소스 다운로드

해당 버전의 리눅스 커널을 빌드하기 위해 커널 소스를 내려받는다.

$ wget https://github.com/microsoft/WSL2-Linux-Kernel/archive/refs/tags/linux-msft-wsl-5.15.90.1.tar.gz
$ tar zxf linux-msft-wsl-5.15.90.1.tar.gz
$ cd WSL2-Linux-Kernel-linux-msft-wsl-5.15.90.1

커널 빌드 설정

커널을 빌드하기 위해 옵션 파일을 옮겨주고 적절한 설정을 잡는다.

$ sudo cp /proc/config.gz ./
$ gunzip config.gz
$ mv config .config

설정을 바꿔준다. 기존에 하위 메뉴가 없던 것은 스페이스바를 눌러 *로 설정을 바꾸고 나면 하위메뉴로 들어갈 수 있게 바뀌는 경우가 있다.

$ make menuconfig

  • Device Driver enter로 진입하여 Multimedia Support <*>로 변경
  • Multimedia Support enter로 진입
    • Filter media drivers [*]로 변경
    • Media device types enter로 진입하여 Cameras and video grabbers [*]로 변경
    • Video4Linux options enter로 진입하여 V4L2 sub-device userspace API [*]로 변경
    • Media drivers enter로 진입하여 Media USB Adapters [*]로 변경
    • Media USB Adapters enter로 진입
      • USB Video Class (UVC) <*>로 변경
      • GSPCA based webcams <*>로 변경

<save>를 해주고 지속 적인 <exit> 선택을 통해 설정을 마친다.

커널 빌드

아래의 명령어를 통해 커널을 빌드한다. 빌드에 들어가는 cpu 코어 수는 최대로 땡겨왔지만 다른 작업과 동시에 한다면 사양을 생각해서 적절히 넣자.

$ make -j$(nproc)

...
...
Kernel: arch/x86/boot/bzImage is ready  (#1)

빌드가 끝나면 현재 경로에 vmlinux라는 파일이 생성된 것을 볼 수 있다. 해당 파일을 우선 wsl 저장공간이 아니라 windows os에서 참조할 수 있는 경로에 복사 혹은 이동 시킨다. 이름을 어떻게 해도 상관없다.

$ cp vmlinux /mnt/c/Users/dongle94/wsl-kernel

WSL 종료 및 빌드 된 커널 적용

우선 wsl을 아래와 같이 종료한다. 기존 wsl 내에서 하던 작업은 잘 정리하여 exit으로 나오고 windows 터미널에서 실행한다.

$ wsl --shutdown

.wslconfig 유저경로에 적용

wsl의 글로벌 설정을 적용하여 커널의 경로를 인식하도록 특정 경로에 .wslconfig라는 파일을 만들어야한다. 메모장으로 만든뒤 확장자를 없애줘도 되고 다른 텍스트 에디터를 통해 생성해도 된다. 아래 내용을 참고하여 적고 파일을 저장하자.

# PATH: C:\\Users\\dongle94\\.wslconfig
[wsl2]
kernel=C:\\Users\\dongle94\\Kernels

WSL 시작 및 확인

다시 WSL을 실행시켜 적용된 커널을 확인해보자. 다음의 명령어로 확인가능하다.

$ uname -a

>>> Linux DONGLE-BOOK2 5.15.90.1-microsoft-standard-WSL2 #1 SMP Mon May 15 18:57:55 KST 2023 x86_64 x86_64 x86_64 GNU/Linux

빌드 된 커널의 버전은 같지만 처음과는 다르게 빌드된 시각은 5월 15일로 찍혀있어서 정상적으로 교체된 것을 확인할 수 있다. 이 상태에서 해당 포스팅의 앞에 언급했던 usbipd를 통한 장치 버스 연결을 해주면 내장 카메라 등의 장치가 정상 사용할 수 있음을 확인할 수 있다.

Windows 터미널에서

$ usbipd wsl list

>>>
BUSID  VID:PID    DEVICE                                                        STATE
2-5    1c7a:0582  EgisTec Touch Fingerprint Sensor                              Not attached
2-6    1bcf:2d05  1080p FHD Camera                                              Not attached
2-10   8087:0033  인텔(R) 무선 Bluetooth(R)                                     Not attached
6-1    046a:0077  USB 입력 장치                                                 Not attached
6-5    2109:8817  USB Billboard Device                                          Not attached
7-4    0bda:8152  Realtek USB FE Family Controller                              Not attached

$ usbipd wsl attach --busid 2-6

WSL 터미널에서

$ ls /dev/video*

>>>
/dev/video0  /dev/video1

최종 작동 불가 확인

python 기반의 cv2 라이브러리 혹은 우분투의 cheese 어플리케이션을 통해 노트북에 내장된 카메라의 영상을 받아와 그릴 수 있는지 확인해보았다.

import cv2

def main():
    cap = cv2.VideoCapture('/dev/video0') 

    while True:
        ret, frame = cap.read()

        if not ret:
            break

        cv2.imshow('Camera', frame)

        if cv2.waitKey(1) == ord('q'):
            break

    cap.release()
    cv2.destroyAllWindows()

if __name__ == '__main__':
    main()

위의 코드 실행 시 내장 카메라의 작동여부를 알리는 불은 들어오나 read() 메소드가 프레임을 정상적으로 가져오지 못하였다. ret 변수의 값은 False 였다.

VideoCapture() 인스턴스의 비디오를 가져오는 방식을 VideoCapture('/dev/video0', cv2.CAP_V4L), VideoCapture('/dev/video0', cv2.CAP_FFMPEG) 등으로 바꿔본 결과 비디오캡처 객체가 영상을 가져올 때 타임아웃 에러를 일으킨 다는 것을 일부 확인할 수 있었는데 왜 정확히 못가져오는지 좀 더 연구가 필요하다.

cheese 어플리케이션으로 카메라를 실행해보려하니 터미널 에러에는 인덱스 기반의 카메라 디바이스 이름을 가져올 수 없다는 alert가 발생하면서 장치를 찾을 수 없다는 이유로 정상적인 실행이 되지는 않았다.

참고링크: ahnbk 블로그, ruby( Phonedolly) 블로그, wsl microsoft blog

댓글남기기