アプリとサービスのすすめ

アプリやIT系のサービスを中心に書いていきます。たまに副業やビジネス関係の情報なども気ままにつづります

Jetson nanoと超音波センサー(HC-SR04)で奥行きの距離を測定

前回はステレオビジョンで奥行きを測定したけど、今回は超音波センサー(HC-SR04)を使って奥行きを測定した。

個人的な備忘録なので、簡単にまとめてく。

目次
1. 配線の構成図
2. 超音波センサーで奥行き測定
3. ステレオビジョンと超音波センサーのメリットとデメリット

1. 配線の構成図

・jetson nano
・USBカメラ
・超音波センサー
・ブレッドボード

の4つを使って配線を組んだ。

GND => GND
Trig   => 19 番pin
Echo => 21番pin
VCC => 5 V(電源)


画像とセンサーの検出物体の位置に差が出ないように、超音波センサーとUSBカメラはなるべく近づけた。



2. 超音波センサーで奥行き測定

下のコードで測定(一部略)

import time
import RPi.GPIO as GPIO

class SensorDist():
    def __init__(self, hyp):
        self.__TRIG = hyp['TRIG_PIN'] # 19 pin
        self.__ECHO = hyp['ECHO_PIN'] # 21 pin
        GPIO.setwarnings(False)
        GPIO.setmode(GPIO.BOARD) 
        GPIO.setup(self.__TRIG,GPIO.OUT)
        GPIO.setup(self.__ECHO,GPIO.IN)
        self.sound_speed = hyp['sound_speed'] #[cm/s]
        
    def getDistance(self):
        GPIO.output(self.__TRIG, GPIO.LOW)
        # TRIG = HIGH
        GPIO.output(self.__TRIG, True)
        # after 0.01[s], TRIG = LOW
        time.sleep(0.01)        
        GPIO.output(self.__TRIG, False)

        signaloff=0
        signalon=0
        # signal start
        while GPIO.input(self.__ECHO) == 0:
            signaloff = time.time()
        # signal returned
        while GPIO.input(self.__ECHO) == 1:
            signalon = time.time()
        # dist calculation
        return (signalon - signaloff) * int(self.sound_speed /2)

    def __del__(self):
        GPIO.cleanup()

def run_camera(opt, hyp):
    sensor = SensorDist(hyp)
    cap = cv2.VideoCapture(0)
    i = 0 
    while True:
        ret, frame = cap.read()
        i+=1
        if i%opt.per_frames==0:
            distance = sensor_dist(sensor)
            texts = 'Distance: {} [cm/s]'.format(str(distance))
            cv2.putText(frame, texts, (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 2, [255, 0, 0], thickness=3)
            frame = cv2.resize(frame, (500, 500))
            cv2.imshow('camera', frame)
            #print("{:.0f}cm".format(distance))
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    cap.release()
    cv2.destroyAllWindows()
    del sensor

パフォーマンスとしてはかなり正確。


3. ステレオビジョンと超音波センサーのメリットとデメリット

超音波センサー

・メリット 
かなり精度がいい。カメラ一台なのでデバイスへの負荷が少ない

・デメリット
ソナーみたいにある一定領域内でしか検出できない(検出領域が狭い)。


ステレオビジョン

・メリット
検出領域が広い。カメラ画像と連動して距離を検出できるので、応用範囲が広い

・デメリット
LIDARや機械学習みたい代替手法の方がいいのでわざわざ使うメリットが少なくなってる。
カメラ2台使うからデバイスへの負荷がでかい
精度が低い


センサーはかなり正確で用途によってかなり使い勝手がいい。ステレオビジョンは代替手法がかなり多くなってきたからわざわざ使う必要なくなってる感じがした。




参考記事

超音波距離センサー(HC-SR04)をJetson Nanoで使用してみました

機械学習でC++の代わりにRustの開発環境構築

機械学習C++の代わりのコンパイル言語の『Rust』の開発環境を構築したのでその備忘録。

目次
1.ubuntuでJupyter notebook
2. opencvでカメラを使ってみる

1.ubuntuでJupyter notebook

# rustをubuntuにinstall
curl https://sh.rustup.rs -sSf | sh
source $HOME/.cargo/env
cargo --version
## cargo 1.67.1

# rust & cargo install
$ rustup install nightly
$ rustup default nightly

# Evcxr Jupyter のinstall
rustup component add rust-src
evcxr_jupyter --install
rustup component add rust-src
sudo apt install jupyter-notebook cmake build-essential
cargo install evcxr_jupyter
evcxr_jupyter --install

# 起動
jupyter notebook


うまく動いた。


use std::fmt::Debug;
pub struct Matrix<T> {pub values: Vec<T>, pub row_size: usize}
impl<T: Debug> Matrix<T> {
    pub fn evcxr_display(&self) {
        let mut html = String::new();
        html.push_str("<table>");
        for r in 0..(self.values.len() / self.row_size) {
            html.push_str("<tr>");
            for c in 0..self.row_size {
                html.push_str("<td>");
                html.push_str(&format!("{:?}", self.values[r * self.row_size + c]));
                html.push_str("</td>");
            }
            html.push_str("</tr>");
        }
        html.push_str("</table>");
        println!("EVCXR_BEGIN_CONTENT text/html\n{}\nEVCXR_END_CONTENT", html);
    }
}
let m = Matrix {values: vec![1,2,3,4,5,6,7,8,9], row_size: 3};

2. opencvでカメラを使ってみる

opencvを使ったrustのタスクをしてみる

# rustのtaskを作成
# binary で作る
cargo new --bin rust-opencv
cd rust-opencv

opencvのversionを調べる
googleから「carates.io」にアクセスしてopencvで検索。


最新のversionを確認。Cargo.tomlに追記

Cargo.toml

[package]
name = "rust-opencv"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
opencv = "0.77.0"

main.rs

use opencv::{highgui, prelude::*, videoio, Result};
fn main() -> Result<()> {
	let window = "video capture";
	highgui::named_window(window, highgui::WINDOW_AUTOSIZE)?;
	let mut cam = videoio::VideoCapture::new(0, videoio::CAP_ANY)?; // 0 is the default camera
	let opened = videoio::VideoCapture::is_opened(&cam)?;
	if !opened {
		panic!("Unable to open default camera!");
	}
	loop {
		let mut frame = Mat::default();
		cam.read(&mut frame)?;
		if frame.size()?.width > 0 {
			highgui::imshow(window, &frame)?;
		}
		let key = highgui::wait_key(10)?;
		if key > 0 && key != 255 {
			break;
		}
	}
	Ok(())
}
## コンパイル
$ cargo run
#Compiling rust-opencv v0.1.0 (/home/parallels/rust-opencv)
#    Finished dev [unoptimized + debuginfo] target(s) in 4.24s
#     Running `target/debug/rust-opencv`
#[ WARN:0] global ./modules/videoio/src/cap_gstreamer.cpp (1100) open #OpenCV | GStreamer warning: Cannot query video position: #status=0, #value=-1, duration=-1


動いた。


参考

opencv-rust
evcxr
Jupyter で Rust を動かせる

レーザーシステムのレーザーの射出角度の設定方法の備忘録

ソフトウェアとハードウェアでカメラに写ったターゲットを自動追尾するレーザーシステムを作るので

ハードウェア側でレーザーで、下の2点を考えてレーザーの射出角度の設定方法を2つ考えた。

・なるべく正確にターゲットに照射する
・設定にコストがかからないようにする

解説を入れるとややこししいので図とコードで設定方法をざっとまとめいくただの個人的な備忘録。

目次
共通パラメーター
方法1. 視差(disparity)を使った4stepの設定方法
方法2. レーザーの射出角度とカメラのピクセル範囲をマッチングするように調整する3stepの設定方法(視差なし)


共通パラメーター

・画像サイズ:Height(縦)=720[pixel] Width(横)=1080[pixel]
・レーザー照射範囲(物体稼働領域) : 120[cm]
・物体までの距離(distance):130[cm]
・レーザー照射角度範囲のminとmax(θ):0〜180


方法1. 視差(disparity)を使った4stepの設定方法

Step
1.カメラとレーザーの位置はなるべく揃える
2.レーザー射出範囲の距離(cm)とそのピクセル数を図る
3.物体までの距離(dist)を計測する
4.公式から照射角度(ε)を求める


disparityから物体までの距離(z)を求めて、座標からレーザーの角度を求める

1.カメラとレーザーの位置はなるべく揃える

カメラとレーザー光がほぼ水平になるようにできる限り近づける。

2.レーザー射出範囲の距離(cm)とそのピクセル数を図る

レーザーで照射したい範囲の実寸とそのpixel数を図る。単位はcmが一般的で扱いやすいのでおすすめ。



3.物体までの距離(dist)を計測する

disparityを計算したら、カメラの画像素子と焦点距離を使った公式から物体までの距離を計算。


def distance_formula(disparity):
    T=2.6
    f = 0.315
    img_element = 0.00028
    K = int(T*f/img_element) #2925
    return K/disparity

4.公式から照射角度(ε)を求める
物体の移動距離(pixel)の単位をcmに直して、物体までの距離(z)からアークジェントを使って求める。

ここでは移動距離は5[pixel]とした。

def pixel2cm(pix):
    object_size = 120
    pixel = 900
    cm = pix * (object_size/pixel)
    return cm *100

	
def calcurate_Xangle(pix, dist):
    x = pixel2cm(pix)
    sita = np.arctan(x/dist)
    return sita
 

dist = disranse_formula(disparity)
#dist= 130
sita = calcurate_Xangle(pix=5, dist=130)
# sita(angle) is 0.47

コード全体

import os
import numpy as np

def pixel2cm(pix):
    object_size = 120
    pixel = 900
    cm = pix * (object_size/pixel)
    return cm *100

# 3
def distance_formula(disparity):
    T=2.6
    f = 0.315
    img_element = 0.00028
    K = int(T*f/img_element) #2925
    return K/disparity
	
# 4
def calcurate_Xangle(pix, dist):
    x = pixel2cm(pix)
    sita = np.arctan(x/dist)
    return sita
	

dist = disranse_formula(disparity)
#dist= 130
sita = calcurate_Xangle(pix=5, dist=130)
# sita(angle) is 0.47
# this is the angle for laser


方法2. レーザーの射出角度とカメラのピクセル範囲をマッチングするように調整する3stepの設定方法(視差なし)

備考
・カメラとレーザーの位置を揃えなくていい
・レーザー照射範囲の長さを計測しなくていい

Step
1.照射範囲に対してレーザーの照射角度(θ)を設定する
2.レーザーの照射角度と画像内のpixel範囲(ε)を合わせる
3.物体の位置座標と公式から照射範囲内のレーザー照射角度(ε =θ)を求める


1.照射範囲に対してレーザーの照射角度(θ)を設定する

pan_tilt.pyとかを使ってレーザーを実際に動かして照射範囲内に必要な角度を設定する。

2.レーザーの照射角度と画像内のpixel範囲(ε)を合わせる
1で設定した角度に画像内のpixel範囲を合わせる。

ちなみにpixelを角度に変換する公式は下のやつ。

class LaserAngleRange(Enum):
	XMin=80
	XMax=130
	YMin=70
	YMax=120
class AngleFormula(Enum):
    ServoMax = 180
    WidthMax = 1080
    HightMax = 720
	
def Xangle2duty(Xcoordinate):
    deg = Xcoordinate / (WidthMax/ServoMax)
    return deg


3.物体の位置座標と公式から照射範囲内のレーザー照射角度(ε =θ)を求める

レーザーの設定角度と画像内の角度が同じになるように、レーザーの設定角度範囲内で画像角度を求める。

def restricted_formula(degX):
	if degX>XMin or degX<XMax:
		#Yduty = int(float(degY)*2,17 + 102)
		Xdeg = degX
	else:
		pass
    return Xdeg
	
degX = Xangle2duty(Xcoord=700)
Xdeg = restricted_formula(degX)
# Xdeg is 116.66°

コード全体

class LaserAngleRange(Enum):
    XMin=80
    XMax=130
    YMin=70
    YMax=120
class AngleFormula(Enum):
    ServoMax = 180
    WidthMax = 1080
    HightMax = 720
	
def Xangle2duty(Xcoordinate):
    deg = Xcoordinate / (WidthMax/ServoMax)
    return deg

def restricted_formula(degX):
	if degX>XMin or degX<XMax:
		#Yduty = int(float(degY)*2,17 + 102)
		Xdeg = degX
	else:
		pass
    return Xdeg
	
degX = Xangle2duty(Xcoord=700)
Xdeg = restricted_formula(degX)
# Xdeg is 116.66° . This is laser angle

特に計算間違いはないし、このほかにもっといい計算方法があるだろうけど初手はこんな感じで。

JetPack4.6.0とJetson NanoでPytorchとOnnxでyolov7の物体検出の環境設定(2023/02)

Jetson NanoでPytorchとOnnxで機械学習の物体検出とその環境設定をしたのでその備忘録。


ちなみに2023の2月でJetson NanoのJetPackの最新版は「4.6.0」

今回は「4.6.0」で環境構築してみた。


目次
1. versionと必要用語
2. 必要なライブラリのinstall
3. Pytorch(1.10.0)のインストール
4. OnnxRuntime(1.11.0)のインストール
5. yolov7で物体検出してみる

1. versionと必要用語

JetPack 4.6.0の各ライブラリバージョン
ubuntu 18.04
・Python3 3.6
・cuda 10.2
・cuDNN 8.2.1



Wheelファイルについて

Wheelファイル(.whl)はNVIDIAがすでにビルドしたものを提供しているファイルのこと。
downloadして使う。
それ以外は直接ソースからビルドしてinstallしたりする。


2. 必要なライブラリのinstall

JetPackをinstallしてから行う。

sudo apt update 
sudo apt install curl git unzip tree vim python3-pip
sudo apt-get install libopenblas-base libopenmpi-dev libomp-dev
pip3 install --upgrade pip
sudo reboot

3. Pytorch(1.10.0)のインストール

# pytoerch 1.10.0 from wheel 
# dependencies whee
apt-get install libopenblas-base libopenmpi-dev libomp-dev
pip3 install Cython
pip3 install numpy torch-1.10.0-cp36-cp36m-linux_aarch64.whl

torchvisionのインストール

# torchvision 0.11
sudo apt-get install libjpeg-dev zlib1g-dev
git clone --branch release/0.11 https://github.com/pytorch/vision torchvision
cd torchvision
sudo python3 setup.py install
pip3 install 'pillow<7'
# Versionチェック
$ torch.__version__
# 1.10.0
$ torchvision.__version__
# 0.11.0

Pytorch とtorchVisionのversionの対応表







Pytorchのバージョン対応するtorchVisionのバージョン
1.9.00.10.0
1.9.10.10.1
1.10.00.11.0
1.10.10.11.2
1.11.00.12.0
1.12.10.13.1


4. OnnxRuntime(1.11.0)のインストール

# onnxruntime 1.11.0
wget https://nvidia.box.com/shared/static/pmsqsiaw4pg9qrbeckcbymho6c01jj4z.whl -O onnxruntime_gpu-1.11.0-cp36-cp36m-linux_aarch64.whl
pip3 install onnxruntime_gpu-1.11.0-cp36-cp36m-linux_aarch64.whl
onnxruntime.__version__
'1.11.0'


5. yolov7で物体検出してみる

import cv2
import random
import math
import numpy as np
import onnxruntime

def letterbox(im, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleup=True, stride=32):
    # Resize and pad image while meeting stride-multiple constraints
    shape = im.shape[:2]  # current shape [height, width]
    if isinstance(new_shape, int):
        new_shape = (new_shape, new_shape)

    # Scale ratio (new / old)
    r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])
    if not scaleup:  # only scale down, do not scale up (for better val mAP)
        r = min(r, 1.0)

    # Compute padding
    new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r))
    dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1]  # wh padding

    if auto:  # minimum rectangle
        dw, dh = np.mod(dw, stride), np.mod(dh, stride)  # wh padding

    dw /= 2  # divide padding into 2 sides
    dh /= 2

    if shape[::-1] != new_unpad:  # resize
        im = cv2.resize(im, new_unpad, interpolation=cv2.INTER_LINEAR)
    top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1))
    left, right = int(round(dw - 0.1)), int(round(dw + 0.1))
    im = cv2.copyMakeBorder(im, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color)  # add border
    return im, r, (dw, dh)

def preprocess(img):
    # Scale input pixel values to 0 to 1
    image = img.transpose((2, 0, 1))
    image = np.expand_dims(image, 0)
    image = np.ascontiguousarray(image)
    return image.astype(np.float32) / 255

def onnx_inference(session, input_tensor):
    output_names = [i.name for i in session.get_outputs()]
    input_names = [i.name for i in session.get_inputs()]
    inp = {input_names[0]:input_tensor}
    outputs = session.run(output_names, inp)[0]
    return outputs

def post_process(outputs, ori_images, ratio, dwdh, conf_thres):
    for i, (batch_id, x0, y0, x1, y1, cls_id, score) in enumerate(outputs):
        image = ori_images[int(batch_id)]
        box = np.array([x0,y0,x1,y1])
        box -= np.array(dwdh*2)
        box /= ratio
        box = box.round().astype(np.int32).tolist()
        cls_id = int(cls_id)
        score = round(float(score),3)
        if score < conf_thres:
            continue
        name = names[cls_id]
        color = colors[name]
        name += ' '+str(score)
        cv2.rectangle(image, (box[0], box[1]), (box[2], box[3]), color, 2)
        cv2.putText(image, name, (box[0], box[1] - 2),cv2.FONT_HERSHEY_SIMPLEX,0.75,[225, 255, 255],thickness=2)
    return ori_images
def onnx_setup(opt):
    cuda = False if opt.cpu=='True' else True
    providers = ['CUDAExecutionProvider', 'CPUExecutionProvider'] if cuda else ['CPUExecutionProvider']
    session = onnxruntime.InferenceSession(opt.onnx_path, providers=providers)

    IN_IMAGE_H = session.get_inputs()[0].shape[2]
    IN_IMAGE_W = session.get_inputs()[0].shape[3]
    new_shape = (IN_IMAGE_W, IN_IMAGE_H)
    return session, new_shape

def inference_(frame, session, new_shape, conf_thres):
    ori_images = [frame.copy()]
    resized_image, ratio, dwdh = letterbox(frame, new_shape=new_shape, auto=False)
    input_tensor = preprocess(resized_image)
    outputs = onnx_inference(session, input_tensor)
    pred_output = post_process(outputs, ori_images, ratio, dwdh, conf_thres)
    return pred_output

session, new_shape = onnx_setup(opt)

_, left_image = left_camera.read()

Routput, Rx, Ry, Rrange = inference_(left_image, session, new_shape, opt.conf_ 
camera_images = Routput[0] 
# 中略 〜〜〜〜〜
cv2.imshow(window_title, camera_images)
〜〜〜〜


Jetson Nano & yolov7で物体検出できた。

参考サイト

IoT環境における知的情報処理技術 環境設定 (Jetson Nano編)
JetPack SDK 4.6 Release Page
Jetson Zoo

PCA9685とjetson nanoで複数のサーボモータを動かす

Jetson nano でPWMコントローラーのPCA9685を使ってサーボモータを複数動かすまでの備忘録。

PWMコントローラーを使えば、モータを16個同時に操作できるし、スクリプト側でマルチthreadingを使わなくて済むとかいいことばかりなので使ってみた。

あとPWMコントローラーは普通にサーボモータを使うより角度や、デューティ比を正確に設定できるので必須アイテム。

目次
1. Adafruit-PCA9685のインストール
2. PCA9685とjetson nanoの配線
3. 複数のサーボモータを実際に動かす



1. Adafruit-PCA9685のインストール

pip3 install Adafruit_PCA9685

このままだとエラーが出るのでI2C.pyを書き換え。

vi ~/.local/lib/python3.6/site-packages/Adafruit_GPIO/I2C.py


I2C.pyの以下を修正
・2行をコメントアウト
return Device(address, "1", i2c_interface, **kwargs)にする

def get_i2c_device(address, busnum=None, i2c_interface=None, **kwargs):
    """Return an I2C device for the specified address and on the specified bus.
    If busnum isn't specified, the default I2C bus for the platform will attempt
    to be detected.
    """
#    if busnum is None:
 #       busnum = get_default_bus()
    return Device(address, "1", i2c_interface, **kwargs)

下のように信号が表示されればOK。

$ sudo i2cdetect -y -r 1
>>>>

#     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
#00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
#10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
#20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
#30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
#40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
#50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
#60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
#70: 70 -- -- -- -- -- -- --                         


2. PCA9685とjetson nanoの配線

PCA9685.                    Jetson Nano
------------------------------------
GND                  ->        GND
SCL                   ->        I2C(5 番)
SDA                   ->        I2C(3番)
VCC                   ->        3.3V
V+                      ->        5V




3. 複数のサーボモータを実際に動かす

simpletest.py

from __future__ import division
import time
import Adafruit_PCA9685

pwm = Adafruit_PCA9685.PCA9685()

# Configure min and max servo pulse lengths
servo_min = 102  # Min pulse length out of 4096
servo_max = 492  # Max pulse length out of 4096

# Helper function to make setting a servo pulse width simpler.
def set_servo_pulse(channel, pulse):
    pulse_length = 1000000    # 1,000,000 us per second
    pulse_length //= 60       # 60 Hz
    print('{0}us per period'.format(pulse_length))
    pulse_length //= 4096     # 12 bits of resolution
    print('{0}us per bit'.format(pulse_length))
    pulse *= 1000
    pulse //= pulse_length
    pwm.set_pwm(channel, 0, pulse)

# Set frequency to 60hz, good for servos.
pwm.set_pwm_freq(50)

print('Moving servo on channel 0, press Ctrl-C to quit...')
while True:
    # Move servo on channel O between extremes.
    pwm.set_pwm(15, 0, servo_min)
    time.sleep(1)
    pwm.set_pwm(14, 0, servo_max)
    time.sleep(1)
    pwm.set_pwm(15, 0, servo_max)
    time.sleep(1)
    pwm.set_pwm(14, 0, servo_min)
    time.sleep(1)


Tkinerを使ったversion

from __future__ import division
import time
import Adafruit_PCA9685

from tkinter import *

pwm = Adafruit_PCA9685.PCA9685()
pwm.set_pwm_freq(50)

class App:

    def __init__(self, master):
        frame = Frame(master)
        frame.pack()
        scale_pan = Scale(frame, label="pan", from_=0, to=180, tickinterval=90, orient=HORIZONTAL, command=self.update_pan)
        scale_pan.set(90)
        scale_pan.grid(row=0, column=0)
        scale_tilt = Scale(frame, label="tilt", from_=0, to=180, tickinterval=90, orient=VERTICAL, command=self.update_tilt)
        scale_tilt.set(90)
        scale_tilt.grid(row=0, column=1)

    def update_pan(self, angle):
        duty = int( float(angle) * 2.17 + 102 )
        pwm.set_pwm(14, 0, duty)
        time.sleep(0.1)

    def update_tilt(self, angle):
        duty = int( float(angle) * 2.17 + 102 )
        pwm.set_pwm(15, 0, duty)
        time.sleep(0.1)

root = Tk()
root.wm_title('Servo Control')
app = App(root)
root.geometry("220x120+0+0")
root.mainloop()

うまくいった。


参考サイト

Jetson nanoとPCA9685でサーボを動かそうとするときのI2Cエラー対処法!
jetson_nano_grove

Jetson Nano セットアップ備忘録 (Pytorch , onnxとか動かすまで)

Jetson nanoを使ったのでセットアップの備忘録。

nv-jetson-nano-sd-card-image-r32.3.1(JetPack 4.3)」のページのイメージをMicro SDカードに焼いた。(from qiitaの記事)


JetPacはtensorflowの都合でJetpack==4.3にした。

パーツ一式はこのサイト「Mac でJetson Nanoをセットアップ」を参考にした。

Jetso nanoセットアップのパーツ一式
Team microSDカード 64GB
HDMIケーブル
有線USBスリムキーボード
小型ディスプレイ HDMI
有線マウス
TP-Link 無線LAN子機
Jetson Nano AC/DC アダプタ
***自分はHDMIディスプレイの電源アダプタも必要だった。



目次
1.SDカードに書き込み
2.はじめにjetson nano起動 & apt upgrade
3.仮想環境作成
4.Pytorch のinstall
5.whlでTensorflowのインストール
6.jetson上でonnxでyolov4のリアルタイム推論してみる

1.SDカードに書き込み

Getting Started with Jetson Nano Developer Kit」通りにパーティションをいじる。

SDカードが刺さってない状態

# 何も表示されない。
$ diskutil list external | fgrep '/dev/disk' 

SDカード入れると

$ diskutil list external | fgrep '/dev/disk'
>>>>>
/dev/disk4 (external, physical):
/dev/disk5 (synthesized):


EtcherからSDカードは/dev/disk4らしいので、

$ sudo diskutil partitionDisk /dev/disk4 1 GPT "Free Space" "%noformat%" 100% 
>>>>
Unmounting disk
Creating the partition map
Waiting for partitions to activate
Finished partitioning on disk4

Etcherで書き込み。

書き込み完了。



2.はじめにjetson nano起動 & apt upgrade

sudo apt update
sudo apt upgrade
sudo apt dist-upgrade

3.仮想環境作成

sudo apt install python3-venv

仮想環境の例

python3 -m venv place
cd place
source bin/activate

# 抜けるとき
deactivate
python3 -m venv place 
cd place
source bin/activate

# dependencies
# sudo pip3 install wheel
sudo apt install gfortran libopenblas-base libopenmpi-dev libopenblas-dev libjpeg-dev zlib1g-dev libv4l-dev python3-pip
# pip update
sudo pip3 install -U pip

# sudo pip3 install jupyter notebook
sudo pip3 install cython numpy # scipy
sudo pip3 install pandas tqdm Pillow pybind11 scikit-learn
sudo pip3 install opencv-python

4.Pytorch のinstall

nvidiaのサイトから

pytorch version 1.4をdownload

wget https://nvidia.box.com/shared/static/ncgzus5o23uck9i5oth2n8n06k340l6k.whl -O torch-1.4.0-cp36-cp36m-linux_aarch64.whl

sudo pip3 install torch-1.4.0-cp36-cp36m-linux_aarch64.whl

# torchvision インストール
pip3 uninstall numpy
pip3 install numpy==1.19.4

git clone https://github.com/pytorch/vision torchvision
cd torchvision && git checkout v0.5.0 && export BUILD_VERSION=0.5.0
sudo python3 setup.py install


Version確認

$ python3
$ import torch
$ torch.__version__
>>>>>
'1.4.0'

Pytorch とtorchVisionのversionの対応表







Pytorchのバージョン対応するtorchVisionのバージョン
1.9.00.10.0
1.9.10.10.1
1.10.00.11.0
1.10.10.11.2
1.11.00.12.0
1.12.10.13.1


5.whlでTensorflowのインストール

whlでnvidiaのサイトからインストールする。

sudo apt-get install libjpeg8-dev hdf5-tools libhdf5-serial-dev libhdf5-dev zlib1g-dev zip

# Python package dependencies
sudo pip3 install bumpy grpcio absl-py py-cpuinfo psutil portpicker mock six requests gast h5py astor termcolor wrapt protobuf google-pasta keras_preprocessing keras_applications

# tensorflow install
sudo pip3 install https://developer.download.nvidia.com/compute/redist/jp/v42/tensorflow-gpu/tensorflow_gpu-1.13.1+nv19.5-cp36-cp36m-linux_aarch64.whl


tensorflowのversion確認

$ python3 
$ import tensorflow as tf
$ tf.__version__
>>>
1.13.1


6.jetson上でonnxでyolov4のリアルタイム推論してみる

onnxに変換したyolov4-tinyでリアルタイム推論してみる。

# onnx dependencies
sudo apt install libprotobuf-dev protobuf-compiler pybind11-dev libprotoc-dev

# onnx install
sudo pip3 install onnxruntime
sudo pip3 install onnxconverter-common==1.6.0
sudo pip3 install onnx==1.6.0

# 推論
$ python3 camera_estimate.py yolov4_tiny.onnx

jetson上での推論をモニターで写した動画。

画像サイズ小さくしたから、距離推定の値も小さくなってもうた。
tensorRTとかc++は機会があったら。




大相撲インフェルノ(趣味のカラクリ武器作り)

参考サイト

This guide provides instructions for installing TensorFlow for Jetson Platform.

【Jetson_nano】インストールからTensorflow,Chainer,そしてKeras環境構築出来たよ♬

【Jetson Nano】Jetson NanoにPyTorchをインストールしようとしてハマった話。

Jetson本格仕様セットアップTips part2

Jetson NanoのJetPack SDK Card imageをinstallした後の、本格的に使うためのセットアップのTipsのメモのpart2。

目次
1. GUI機能の無効化でメモリ消費量を抑える
2. 電源をACアダプターからmicroバッテリーに変換する


1. GUI機能の無効化でメモリ消費量を抑える

自動GUI表示機能を無効化して、メモリ消費量を減らす。

# GUIがONか確かめる
$ systemctl get-default
# graphical.target

# GUI時のメモリ使用量
$ free -m
#               total        used        free      shared  buff/cache   available
# Mem:           3964         808        2324          21         831        2980
# Swap:          6078           0        6078

# GUI機能を無効化
$ sudo systemctl set-default multi-user.target
# Removed /etc/systemd/system/default.target.
# Created symlink /etc/systemd/system/default.target → /lib/systemd/system/multi-user.target.

# 再起動して反映
$ sudo reboot
# GUIを無効時のメモリ使用量
$ free -m
#               total        used        free      shared  buff/cache   available
# Mem:           3964         617        2621          20         725        3174
# Swap:          6078           0        6078

# GUIに戻す時
$ sudo systemctl set-default graphical.target

メモリ使用量が200くらい減った。



2. 電源をACアダプターからmicroバッテリーに変換する

ジャンパーPINをとり外して、電源をMicroバッテリーに対応させる。
ACアダプターに戻すにはジャンパーPINをつければ戻る。


microバッテリーは専用のを使わなくても、スマホの携帯充電器(5V)とmicro-B とUSB-Aのケーブルがあれば携帯用microバッテリーができる。


jetson nanoが動いて、headlessと加えて、どこでも使えるようになった




参考

JetsonNanoの電源として使えるモバイルバッテリーについて