2021년 9월 21일 화요일

docker-compose시 ARG에 빈 값이 넘어오던 문제

졸업 작품을 준비하면서 L4T-Tensorflow에 추가적으로 내 프로젝트가 제공하는 파일과 기타 필요로한 설치를 한꺼번에 할 수 있도록 Dockerfile과 docker-compose.yml을 이용하기로 했다.

내 처음 도커파일은 다음과 같다
# 1. l4t-tensorflow의 이미지를 가져온 다음 base 이미지로 명칭 설정, 시스템 업데이트를 수행
# 2. 현재 docker-compose를 실행한 위치 (복제한 리포지토리 위치)의 내용을 모두 새로 생성될 
#    도커 이미지로 복사 
# 3. Python에서 GStreamer 사용하는데 필요한 기타 파일들을 받는다.
# 4. 이후에 두개의 branch로 나눈다. 하나는 디버그용 그리고 디버그가 아닌 이미지
# 5. 모든 branch를 위한 이미지가 생성되면 DEBUG의 값을 참조하여 요청된 이미지를 
#    최종 이미지로 선정하고 docker-compose에 따라 이미지를 꾸며준다. 
ARG DEBUG

FROM nvcr.io/nvidia/l4t-tensorflow:r32.5.0-tf2.3-py3 AS base

RUN apt-get update
RUN apt-get purge -y gnome* ubuntu-desktop
RUN apt-get autoremove
RUN apt-get clean
RUN apt-get upgrade -y

ENV DIR=/root/sopoware-panoptes
RUN mkdir $DIR
WORKDIR ${DIR}
COPY ./ ./
RUN chmod +x ./start.sh

RUN apt-get install -y gstreamer1.0-tools gstreamer1.0-alsa gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav
RUN apt-get install -y libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-good1.0-dev libgstreamer-plugins-bad1.0-dev;
RUN apt-get install -y python3-gi python3-gst-1.0

FROM base AS RUNTYPE-1
RUN echo "Building Debug mode..."
RUN apt-get install -y lighttpd iptables
# iptables setting. TODO
RUN service lighttpd start
RUN cp ./demo/index.html /var/www/html/index.lighttpd.html

FROM base AS RUNTYPE-0
RUN echo "Building Batch mode..."

FROM RUNTYPE-${DEBUG} AS final
ENTRYPOINT $DIR/start.sh
FROM에서 AS에 사용한 이미지 이름에 대문자를 사용해서 오류가 발생했고, 이후에는 알수없는 invalid reference format이라는 에러를 계속해서 받았다. 이유를 찾기 위해 DEBUG 값 (빌드 명령인자로 받기로 설정한 값)을 echo로 꺼내보니 비어있는 것을 확인했다.

FROM 이전에 있는 ARG는 DEBUG 인자의 값을 받아왔지만 문제는 base 이미지를 만들때 해당 ARG가 설정되지 않는다는 것이다. 그래서 ARG를 base의 안쪽으로 옮기고 확인해보니 값이 정상적으로 넘어왔다. 하지만, 마지막 FROM에서 해당 ARG 값을 받아오자 다시 빈 값이 넘어오는 것이다. 그래서 처음에 ARG를 선언하고, 다시 base 이미지를 생성할때 ARG를 한번 더 설정하니 다음부터 모든 ARG DEBUG의 값이 정상적으로 들어가기 시작했다.

2021년 9월 1일 수요일

Jetson Nano 세팅 및 알아두어야 할 것들

 

1. 전원 공급

  • Jetson Nano는 Micro-USB 또는 AC Adapter 중 하나만을 전원공급으로 사용함
  • J48에 점퍼를 끼우면 AC Adapter로만 전원 공급을 받게 할 수 있고 반대로 점퍼가 없으면 Micro-USB를 전원 공급으로 사용함
  • 2GB는 M.2 Key 슬롯이 없고 어댑터를 사용하지 않으며, Micro-USB만 가지고 있음

그림1. Jetson Nano 다이어그램

2. OS(우분투) 포팅

Jetson 장치 패밀리를 위한 우분투 기반 리눅스 배포판 JetPack이 Nvidia에서 지원됨

3. WiFi 세팅

와이파이 모듈은 Jetson Nano 보드의 SODIMM 모듈을 고정하는 상단 좌우 나사 두개를 풀고 좌우 고정핀을 당겨 J2에서 제거한 후 J18에 장착 (그림1 참조)

4. 원격데스크톱 및 SSH 세팅

접속방법

  • Wi-Fi
  • Micro-USB (해당 경우 192.168.55.1로 접근)
  • 이더넷

원격 데스크톱

  • Jetson Nano에서 다음을 설정

    sudo vim /usr/share/glib-2.0/schemas/org.gnome.Vino.gschema.xml
    # Vino 스키마 수정
    
    <key name='enabled' type='b'>
    	<summary>Enable remote access to the desktop</summary>
    	<description> If true, allows remote access to the dekstop via the RFB protocol. Users on remote machines may then connect to the desktop using a VNC viewer.</description>
    	<default>true</default>
    </key> 
    # 다음 내용을 붙여넣고 저장
    
    sudo glib-compile-schemas /usr/share/glib-2.0/schemas
    # 스키마 업데이트
    
    # 검색에서 Startup application를 찾아 실행 후 Vino 추가, 파일 위치는 /usr/lib/vino-server
    
    gsettings set org.gnome.Vino require-encryption false
    gsettings set org.gnome.Vino prompt-enabled false
    gsettings set org.gnome.Vino enabled true
    
  • 클라이언트에서는 VNC 접속 프로그램으로 Jetson Nano에 원격 데스크톱 연결을 수행하면 됨

  • 2021/09/02 문제점 - 계정에서 로그아웃 될 경우 vino가 죽음

SSH

  • 이더넷 및 와이파이의 경우 해당 Jetson Nano에 할당된 IP로 접속

  • Jetson Nano에서 실행

    sudo vim /etc/ssh/sshd_config
    
    Port *[원하는 포트번호]* 
    Host /etc/ssh/ssh_host_rsa_key
    SyslogFacility AUTH
    LogLevel INFO
    
    LoginGraceTime 2m
    PermitRootLogin yes
    StrictModes yes
    
    PubkeyAuthentication yes
    
    HostbaseAuthentication no
    IgnoreRhosts yes
    PermitEmptyPasswords no
    ChallengeResponseASuthentication no
    
  • 접속 클라이언트에서 실행

    # 리눅스 및 macOS 환경
    
    ssh-keygen -b 2048
    # SSH키 생성
    ssh-copy-id [생성한 키 위치] [Jetson Nano 사용자 이름]@[Jetson Nano 주소] -p [SSH설정 포트]
    # 생성한 SSH 키 중 Public 키를 Jetson Nano에 전송
    # macOS는 HomeBrew를 통해 ssh-copy-id를 다운로드 가능
    
    vim ~/.ssh/config
    
    Host *[별칭]*
    	HostName [Jetson Nano 주소]
    	Port [SSH 설정 포트]
    	User [Jetson Nano 사용자 이름]
    	IdentityFile [생성한 키 위치]
    
    # Option: ssh 접속 별칭 설정하는 과정, ssh *[별칭]*으로 접속 가능. 
    

5. 삼바 세팅

6. 카메라 연동 테스트

VNC 또는 장치에서 접속

카메라 영상 보기

gst-launch-1.0 nvarguscamerasrc ! 'video/x-raw(memory:NVMM), \
width=(int)1920, height(int)=1080, format=(string)NV12, \
framerate=(fraction)30/1' ! nvoverlaysink -e

카메라 영상을 이미지로 분할 저장

# %~nd에서 n은 채워질 총 자리수를 의미하고, 앞에 있는 0의 갯수 만큼 0으로 미리 채워넣는다.
gst-launch-1.0 nvarguscamerasrc ! 'video/x-raw(memory:NVMM), \
width=(int)1920, height=(int)1080, format=(string)NV12, \
framerate=(fraction)30/1' ! nvjpegenc ! multifilesink location=img-%00005d.jpg

카메라 영상을 H.264로 저장

gst-launch-1.0 nvarguscamerasrc ! 'video/x-raw(memory:NVMM), \
width=(int)1920, height=(int)1080, format=(string)NV12, \
framerate=(fraction)30/1' ! nvv4l2h264enc bitrate=8000000 ! h264parse ! \
qtmux ! filesink location=video.mp4 -e

Python에서 GStreamer 사용하기

  • OpenCV

  • Gst-Python

    # 설치
    sudo apt-get install python-gst-1.0 python-gi
    
    # 예시 Python script
    import gi
    gi.require_version('Gst', '1.0')
    from gi.repository import Gst
    
    import matpoltlib.pyplot as plt
    
    Gst.init(None)
    
    pipeline = Gst.parse_launch('nvarguscamerasrc sensor-id=0 name=cam0 \
    aelock=true awblock=true wbmode=0 ! video/x-raw(memory:NVMM), \
    width=(int)1280, height=(int)720, format=(string)NV12, \
    framerate=(fraction)5/1 ! nvvidconv flip-method=0 !\
    video/x-raw,width=640,height=480,format=BGRx ! \
    nvvidconv ! video/x-raw,width=640,height=480 ! \
    videoconvert ! queue leaky=downstream max-size-buffers=1 !
    appsink max-buffers=1')
    
    # 0번 카메라를 얻고, 자동 화이트 밸런스, 노출 기능 잠금.
    # 카메라를 1280x768 해상도와, NV12, 프레임레이트 5/1로 설정하고
    # NV12의 포멧을 BGR의 포멧으로 GPU에서 변경하고
    # BGR를 다시 RGB의 포멧으로 변경함 (GPU 사용 안함)
    # 이 데이터를 Gst에 sink함
    
    sink = pipeline.get_by_name('appsink0')
    sample = sink.emit('pull-sample')
    buffer = sample.get_buffer()
    caps = sample.get_caps()
    
    img = np.ndarray((caps.get_structure(0).get_value('height'), caps.get_structure(0).get_value('width'), 3),
    			buffer=buffer.extract_dup(0, buffer.get_size()),
    			dtype=np.uint8)
    # sink된 데이터를 가져옴
    
    plt.imshow(img)
    plt.show()
    # 이미지 출력
    

참고자료

[번] Callback 지옥, Promises, 그리고 Async/Await

원문:  https://blog.avenuecode.com/callback-hell-promises-and-async/await  Callbacks와 promises, 그리고 async/await을 쓰는 비동기 자바스크립트는 반환하는데 시간이 소요되는...