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

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

Arduino UnoとPCをシリアル通信させる方法と参考コード集まとめ【hardware】

ArduinoとPCとの情報のやりとりはシリアル通信でする。このサイトを参考にした。

深層学習(DNN)にはシリアル通信は必須なので、やり方とデモもかねて動かしたコードをまとめていく。

f:id:trafalbad:20200526161410j:plain

目次
1.Arduino Unoのシリアル通信の設定
2.Arduino UnoからPCへのデータ送信
3.PCからArduino Unoへのデータ送信



1.Arduinoのシリアル通信の設定

Arduino for Macを起動して、[ツール]-[シリアルボード~]で表示されてるパスを取得して確認。
f:id:trafalbad:20200526161555p:plain

# シリアル通信できるか確認
$ sudo pip install pyserial
$ python3
>>>import serial
>>>ser = serial.Serial("/dev/cu.usbmodem14301")
>>>print(ser)
Serial<id=0x106a8f710, open=True>(port='/dev/cu.usbmodem14301', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False)

>>>ser.close()
>>>exit()

シリアル通信ができてる。





2.Arduino UnoからPCへのデータ送信

f:id:trafalbad:20200526161623j:plain

0~9までの数字を一秒おきに送信


Arduinoから1秒毎にカウントされる値がPCに送られる。
通信中はArduinoのTXと書かれた通信用LEDが一秒毎に点滅する。

serial_send.ino

void setup() {
 int signal_speed = 9600;
 Serial.begin(signal_speed);
}

void loop() {
 static int count=0;
 Serial.print(count);
 count ++;
 if(count == 10)
   count = 0;
 delay(1000);
}


serial_receive1.py

# -*- coding: utf-8 -*-
import serial
import time
wait_second = 5.0
total_number = 10
ser = serial.Serial("/dev/cu.usbmodem14301", timeout=0.5)
time.sleep(wait_second)
for i in range(total_number):
   line = ser.read()
   print(line)
ser.close()
# 実行
$ python3 serial_receive1.py
>>>
b'0'
b'1'
b'2'
~
b'5'

f:id:trafalbad:20200526161707g:plain



1~10までを読みこんで表示


ser.read()関数で一文字ごとに読み込んで表示。

serial_receive2.py

# -*- coding: utf-8 -*-
import serial
import time

wait_second = 5.0
total_number = 10 
with serial.Serial("/dev/cu.usbmodem14301") as ser:
   time.sleep(wait_second)
   for i in range(total_number):
       line = ser.read()
       print(line)
# 実行
$ python3 serial_receive2.py
>>>
b'0'
b'1'
b'2'
~
b'8'
b'9'
# ファルダ構造
$ tree Serial_receive
>>>
Serial_receive
├── serial_send
│   └── serial_send.ino
├── serial_receive1.py
└── serial_receive2.py




データロガー



データロガーは「Arduinoで計測したデータをPCに送って、PCでそのデータを保存する」こと。

試しに一秒おきに

0, 0, 0.00
1, 1, 2.00

と0, 1, 2, 3と増えるデータをArduinoからPCに送信して、テキストファイル(data.txt)に保存してみる。

serial_datalogger.ino

void setup() {
 int signal_speed = 9600;
 Serial.begin(signal_speed);
}

void loop() {
 static int count=0;
 Serial.print(count);
 Serial.print(',');
 Serial.print(count);
 Serial.print(',');
 Serial.println(count*2.0);
 count ++;
 if(count == 10)
   count = 0;
 delay(1000);
}


serial_datalogger.py

# -*- coding: utf-8 -*-
import serial
import time
wait_second = 12.0

with serial.Serial('/dev/cu.usbmodem14301', timeout=0.5) as ser:
   time.sleep(wait_second)
   with open('data.txt', 'w') as f:
       for i in range(10):
           line = ser.readline()
           line = line.rstrip().decode('utf-8')
           print(line)
           f.write((line)+'\n')
# 実行
$ python3 serial_datalogger.py
>>>
0,0,0.00
1,1,2.00
2,2,4.008,8,16.00
9,9,18.00


データがうまく保存できないならtime.sleep()の時間を増やすのがコツ

# ファルダ構造
$ tree Serial_datalogger

Serial_datalogger
├── data.txt
├── serial_datalogger
│   └── serial_datalogger.ino
└── serial_datalogger.py




3.PCからArduino Unoへのデータ送信

今度は逆にPCからArduinoへ文字や数値を送信する。
これを使えばDNNで得た学習モデルを使って、Arduinoを含めたラズパイとかの電子工作を動かせる。

f:id:trafalbad:20200526161758j:plain

バイト文字の送信



void setup() {
 int signal_speed = 9600;
 Serial.begin(signal_speed);
 pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
 if(Serial.available()>0){
   char c = Serial.read();
   if(c=='a')
         digitalWrite(LED_BUILTIN,HIGH);
   else if(c=='b')
         digitalWrite(LED_BUILTIN,LOW);
 }
}
# -*- coding: utf-8 -*-
import serial
import time

with serial.Serial('/dev/cu.usbmodem14301') as ser:
   time.sleep(5.0)
   for i in range(5):
       ser.write(b'a')
       time.sleep(1.0)
       ser.write(b'b')
       time.sleep(1.0)


受信した変数が’a’なら確認用LEDを点灯、’b’なら確認用LED消灯。

‘a’を送信し、1秒待ち、’b’を送信して1秒待つを5回繰り返す。

Arduinoの確認用LEDが5回点滅する。
f:id:trafalbad:20200526161831g:plain





数値の送信



0~255の数値を送ってLEDの明るさを変化させる(もっと大きい数値(500とか1500)も送信可能)。

デジタル9番ピンを使ってLEDの明るさを変える。
serial_receive_value.ino

int pin_number = 9;

void setup() {
 int signal_speed = 9600;
 Serial.begin(signal_speed);
 pinMode(pin_number, OUTPUT);
}

void loop() {
 if(Serial.available()>0){
   long int v = Serial.parseInt();
   analogWrite(pin_number, v);
 }
}


Serial.available()関数は浮動小数点値を受け取る。

LEDがだんだん明るくなる=>消える

を5回繰り返す(0~255までの値を送る)。
serial_receive_value.py

# -*- coding: utf-8 -*-
import serial
import time

wait_second = 0.01
with serial.Serial('/dev/cu.usbmodem14301') as ser:
   time.sleep(5.0)
   for i in range(5):
       for j in range(255):
           ser.write((str(j)+'\n').encode('utf-8'))
           time.sleep(wait_second)  # 0.01秒待つ
# 実行
$ python3 serial_send_value.py

f:id:trafalbad:20200526161855g:plain

$ tree serial_receive_value
>>>
serial_receive_value
├── serial_receive_value.ino
└── serial_receive_value.py

これでArduinoを使って深層学習ができる。


速度とかとはultra96v2と比較して劣るものの、Arduino Unoは動かすのはかなり簡単だった。


f:id:trafalbad:20200526163409j:plain

Arduino Unoを動かす基本コードと環境設定方法【hardware】

ラズパイの一種、「Arduino UNO」の基本的な動作をさせる際のコード集(個人的メモ)。

Arduinoを動作させるまでの環境設定
MacにUSBを使ってUbuntuをインストールする方法

も簡単に書いた。


目次
1.LEDを点滅させる
2.LEDをだんだん明るくさせる
3.Arduino UNO環境設定
4.MacにUSBカードでubuntuをinstallする方法

1.LEDを点滅させる

LEDをarduinoに挿して、点滅させる。

f:id:trafalbad:20200525214049j:plain

ブレッドボードに挿して点滅させる。
f:id:trafalbad:20200525214641j:plain

int led = 13;

void setup() {//一度だけ実行される
  pinMode(led, OUTPUT);//Arduinoボードに付いているLEDを出力に
}

void loop() {//何度も繰り返し実行される
  digitalWrite(led, HIGH);//LEDを光らせる
  delay(1000);//1000ミリ秒待つ
  digitalWrite(led, LOW);//LEDを消す
  delay(1000);//1000ミリ秒待つ
}


2.LEDをだんだん明るくさせる

f:id:trafalbad:20200525220904g:plain

使ったもの

・抵抗(1/2W1kΩ)
・LED
・ブレッドボード
・ジャンパーワイヤー(オスーオス)

int led = 9;

void setup() {
  pinMode(led, OUTPUT);//デジタル9番ピンを出力に
}

void loop() {
  for(int i=0;i<256;i++){
    analogWrite(led, i);//iの値に従って明るさを設定
    delay(10);
  }
}


3.Arduino UNO環境設定

Arduinoのwebページから[Arduino for MAC]のMac版をここからインストールする。

ほぼ「Arduino IDEインストール方法 – Mac編」を参考にした。



ボードマネージャを使ってボード制御プログラムを追加


[Arduino]メニューの[Preferences]を選択。"ESP8266" のArduinoライブラリのgitサイトを開いて、
下の方にある

Boards manager link : https://arduino.esp8266.com/stable/package_esp8266com_index.json

のURLをコピーして、さっきにの環境設定画面の下の方にある「追加のボードマネージャのURL」という入力欄にペースト。[OK]ボタンをクリックして環境設定画面を閉じる。

メニューの[ツール]-[ボード “Arudino Uno”]-[ボードマネージャ]でボードマネージャ画面を開く。
インターネットからボード一覧を取得。ボード一覧の取得が終わるとプログレスバーが消える。

画面上部にある入力欄に「esp8266」を入力。最新版version=2.7.1をinstall。(2020/05月時点)

f:id:trafalbad:20200612230716p:plain

[閉じる]ボタンをクリックで閉じる。


ESPr Developer用のボード制御プログラムの選択とパラメータ設定


1.メニュー[ツール]-[ボード]で”Generic ESP8266 Module”を選ぶ。メニュー[ツール]を開いて、[書き込み装置]を”USBasp”に変更。
f:id:trafalbad:20200525223704p:plain


2.メニュー[ツール]-[シリアルボード]を”/dev/cu.usbmodem14301(Arduino Uno)”に変更。

f:id:trafalbad:20200612230255p:plain

3.メニュー[ツール]-[ボード]で”Generic ESP8266 Module”を”Arduino Uno”に変更
f:id:trafalbad:20200612230324p:plain

これでArduino Unoの設定完了。ボードに書き込める。



4.MacにUSBカードでubuntuをinstallする方法

1.USBカードを差し込む。

$ diskutil list
$ diskutil unMountDisk /dev/disk2 (USB= /dev/disk2)
$ sudo dd if=ubuntu-18.4.2.iso of=/dev/disk2 bs=1m

終わったら、「無視」をクリック。

2.macをoption押しながら起動してUSBの選択肢を選択する。

3.あとは[ubuntu〜 install]をクリックしてwifi設定も含めてubuntuをinstall
ほとんどvirtualBoxと同じ方法でinstall。

GKEのkubenetes上でflaskを動かし、curlでPOSTした画像の予測結果を受け取る【機械学習】

flaskで機械学習の学習済みモデルを入れてkubenetes上で動かしてみた。

curlで投げて、予測結果を受け取る形式だけど、envoyとかスケーラビリティも意識した構成になってる。

kubenetes上での flask動作環境
f:id:trafalbad:20200417224845j:plain


目次
1.flaskアプリケーションの作成
2.Docker上でflaskを動かす
3.GKEのkubenetesでflaskを動かす
4.GKEのflask動作環境
5.minikubeのメモ




1.flaskアプリケーションの作成

# 仮想環境作成
$ Python3.7 -m venv venv && source venv/bin/activate
$ pip install -r requirements.txt


projectフォルダ内のファイルの役割


・__init___.py
App = Flask(__name__)
でFlask本体を作る

Server.py単体でも動く。



・views.py
http://~でリクエストがあった時の処理

@app.route(‘/’)でhttpにリクエストがあったことをしめす
@app.route(‘/post’)とかは「https://~/post」とURLの後にその文字列をつける


・server.py
"python server.py" でHTTPにアクセスした時にする処理

rom flask import Flask, jsonify, request
import requests
import numpy as np
import cv2
import json
from flasks.predict import predict
app = Flask(__name__)

@app.route("/", methods=['GET'])
def hello():
    return "Hellos !"

@app.route('/reply', methods=['GET', 'POST'])
def reply():
    if request.method == 'POST':
        data = request.data.decode('utf-8')
        url = json.loads(data)['key']
        resp = requests.get(url, stream=True).raw
        img = np.asarray(bytearray(resp.read()), dtype="uint8")
        img = cv2.imdecode(img, cv2.IMREAD_COLOR)
        pred = predict(img)
        return int(pred)

if __name__ == "__main__":
    app.run(host='0.0.0.0',port=5000,debug=True)


・configファイル(config.py)
環境・設定情報を書く

DEBUG =True


ディレクトリ構成図

$ tree
├── Pipfile
├── Pipfile.lock
├── flasks
│   ├── __init__.py
│   ├── config.py
│    |└── views.py
     ________templates
└── server.py

html系の「templates」ファルダ
=>views.py返す処理(レンダリング)のhtmlやCSSその他を置く場所


Djangoとほぼ同じ仕組みだけど、かなり簡単な構成になってる。




2.Docker上でflaskを動かす

今回はtensorflow-gpuを入れた。

Dockerfile

FROM tensorflow/tensorflow:devel-gpu
RUN mkdir /home/app
WORKDIR /home/app/
COPY requirement.txt /home/app/
RUN pip install --upgrade pip
RUN pip install -r /home/app/requirement.txt
ADD server.py /home/app/
ADD flasks /home/app/flasks
ADD Pipfile /home/app/
ADD Pipfile.lock /home/app/
CMD ["python", "server.py"]


Makefileでコマンドをまとめて簡略化
Makefile

build:
	docker build -t flasks .
run:
	docker run -p 5000:5000 -it flasks
# dockerイメージ作成
$ make build
# コンテナ起動
$ make run


curl画像のURLをPOSTして、予測結果を受けってみる



# 試す
curl -X POST -H "Content-Type: application/json" -d{"key":"http://tore~e.jpg"}' http://localhost:5000/flask
>>>
16

返ってきた。


普通のpngとかの画像をcurlで投げるコマンドはこれ

$ curl -F "file=@test.png" http://localhost:5000/flask


3. GKEのkubenetesでflaskを動かす

全部GCPのターミナルで動かす。

# dockerイメージ作成
$ docker build -t gcr.io/[プロジェクト名]/flask .
# GCRにdockerイメージのpush
$ docker push gcr.io/[プロジェクト名]/flask

クラスタGUIで作成した後のコマンド。
yamlファイルとかflaskのアプリケーションをuoloadしておく。

# クラスタのアクセス権取得
$  gcloud container clusters get-credentials cluster-1 --zone us-central1-c

# yamlファイル実行
$ kubectl apply -f ~.yaml

# flaskが動いてるか確認
$ kubectl get service

f:id:trafalbad:20200417225002j:plain

# curlでPOSTしてみる
$ curl -X POST -H "Content-Type: application/json" -d{"key":"http://tore~e.jpg"}' http://[EXTERNAL-iP]/flask
>>>
16


正常に動いてる。





4.GKEのflask動作環境

外部からcurlとかでアクセスして、予測結果を受け取る形式になっている。

Podを多くしてもスケーラビリティが悪くならないようにenvoyを使った。


envoyを使うとPod数が多くても綺麗に分散される
f:id:trafalbad:20200417225020p:plain


再度動作環境の全体像
f:id:trafalbad:20200417224845j:plain



4.minikubeのメモ

minikubeはローカルでもkubectlコマンドも使えるkubenetesと同じ環境を簡単に作れて、動かすことができる。

GCPとかでいちいち動かすのが億劫なら、仮想環境に入れとくと便利。

# kubectl install
$ brew update && brew install kubectl 
# minikube install
$ brew install minikube

# バージョン確認
minikube version
#起動
minikube start
# minikube削除
$ minikube delete


バックエンドは門外漢に近いけど、flaskとかkubenetesに詳しくなったとか、いいスキル習得になった。



参考記事



kubernetesでgRPCするときにenvoy挟んでみたよ

Dockerfile-GCS

PIL を使って GCS にある画像を動的にリサイズして送信する

BytesIO(およびStringIO、cStringIO)の使い方【初心者向け】


追記


シンボリックリンクについて

シンボリックリンク
・ファイルやフォルダの代理人ファイル
・元のファイルとシンボリックリンクは別物
シンボリックリンクを削除しても元のファイルに影響はない
・どこにでも作れる
・フォルダに対しても作れる

■ハードリンク
・ファイルに付けたあだ名
・元のファイルとハードリンクは(ほぼ)同じ物
・状況によっては、ハードリンクが削除されると元のファイルも削除される
・同じパーティションにしか作れない
・フォルダに対しては作れない


参考サイト:シンボリックリンク(英:symbolic link)とは

PetaLinux上からultra96v2ボードでYolov3の物体検出【FPGA, hardware, AI】

前の記事「Vitis,Petalinuxのインストールから、Vivadoの起動まで【FPGA】-VitisPlatform作りpart2」でVivado, vitis, Petalinuxの環境構築をした。


PetaLinuxの環境構築をしておくことで、linux(PetaLinux)上から直接、ultra96ボードにアクセスできるらしい。

少なくともVivado, vitis, Petalinuxの環境構築さえしてしまえば、PetaLinuxを通して、直接ultra96を動かして性能を確かめられる。


今回は物体検出で有名なyolov3とtiny-yolov3をPetaLinux上で動かし、ultra96v2の性能を試してみた。



目次
1.Yolov3の準備
2.使う画像
3.ultra96v2でYolov3の性能検証
4.ultra96v2でTiny-Yolov3の性能検証
5.gprofでYolov3の処理性能可視化





1.Yolov3の準備

簡単にコマンド操作で完了。

# darknetをgit clone
$ git clone https://github.com/pjreddie/darknet
# Yolov3の動作環境構築
$ cd darknet; make

# 学習済みyolov3の重みをdownload
$ cd darknet
$ wget https://pjreddie.com/media/files/yolov3.weights


これでyolov3の動作環境ができた。PetaLinuxの環境構築をしておけば簡単。





2.使う画像

拾ってきたこの画像。


test1.jpegf:id:trafalbad:20200413114840j:plain


test2.jpegf:id:trafalbad:20200413114915j:plain

これでyolov3とtiny-yolov3の性能を比較してく。




3.ultra96v2でYolov3の性能検証

test1.jpegでトライ


# yolov3で物体検出
$ cd darknet
$ ./darknet detect cfg/yolov3.cfg yolov3.weights /home/[host-name]/test1..jpeg

>>>
../test1.jpeg: Predicted in 41.924274 seconds.
truck: 79%
car: 93%
car: 85%
car: 83%
car: 78%
car: 67%
person: 100%
person: 99%


推論にかかった処理時間(予測時間)は41.924274秒

予測結果画像f:id:trafalbad:20200413115150j:plain






test2.jpegでトライ



$ cd darknet
$ ./darknet detect cfg/yolov3.cfg yolov3.weights /home/[host-name]/test2..jpeg
>>>
../test2.jpeg: Predicted in 37.329435 seconds.
backpack: 80%
person: 100%
person: 100%
person: 99%
person: 98%
person: 93%
person: 87%

予測結果画像f:id:trafalbad:20200413115320j:plain

推論にかかった処理時間(予測時間)は37.329435秒


かなりいい具合に検出できてる。

ラズパイだとYolov3に213.6秒くらいかかるらしいから、ultra96v2がかなり高速で推論可能なことがわかる。




4.ultra96v2でTiny-Yolov3の性能検証

# 学習済みTiny-Yolov3の重みをdownload
$ wget https://pjreddie.com/media/files/yolov3-tiny.weights

# test1.jpegで物体検出
$ ./darknet detect cfg/yolov3-tiny.cfg yolov3-tiny.weights /home/[host-name]/test1.jpeg
>>>
Loading weights from yolov3-tiny.weights...Done!
../test1.jpeg: Predicted in 1.380456 seconds.
car: 65%
car: 55%
person: 94%


処理速度(推論速度)は1.380456 seconds(ほぼ1秒)
かなり高速

予測結果画像f:id:trafalbad:20200413115547j:plain

結果は本家Yolov3と比べてあまり良くないけど、簡単な画像なら十分な気がする。


ちなみにターミナル上での可視化は下コマンドで。

$ sudo apt install imagemagick
$ display predictions.jpg

f:id:trafalbad:20200413120009p:plain




5.gprofでYolov3の処理性能可視化

gprofでYolov3のtest1.jpeg, test2.jpeg処理性能を可視化してみる。

gprofでの可視化は「System-on-Chip (SoC) Design」を参考に。

'gprof2dot.py'はgprof2dot.pyの配布サイトから持ってきた。

gprofで可視化するまでの手順

#  gprof2dot.pyをダウンロード
$ git clone https://github.com/jrfonseca/gprof2dot
$ mv gprof2dot/gprof2dot.py gprof2dot.py; chmod 755 gprof2dot.py

# yolov3をダウンロード
$ git clone https://github.com/pjreddie/darknet
$ cd darknet; make

ここでMakeファイルを書き換える。CFLAGSライン全部に "-pg" オプションをつける。

$ sudo vi Makefile
>>>
# CFLAGSライン全てに -pgをつける
GPU=0
CUDNN=0
OPENCV=0LDFLAGS= -lm -pthread 
COMMON= -Iinclude/ -Isrc/
CFLAGS=-Wall -Wno-unused-result -Wno-unknown-pragmas -Wfatal-errors -fPIC -pg

ifeq ($(OPENMP), 1) 
CFLAGS+= -fopenmp -pg
endif

ifeq ($(DEBUG), 1) 
OPTS=-O0 -g
endif

CFLAGS+=$(OPTS) -pg

ifeq ($(OPENCV), 1) 
COMMON+= -DOPENCV
CFLAGS+= -DOPENCV -pg
LDFLAGS+= `pkg-config --libs opencv` -lstdc++
COMMON+= `pkg-config --cflags opencv` 
endif

ifeq ($(GPU), 1) 
COMMON+= -DGPU -I/usr/local/cuda/include/
CFLAGS+= -DGPU -pg
LDFLAGS+= -L/usr/local/cuda/lib64 -lcuda -lcudart -lcublas -lcurand
endif

ifeq ($(CUDNN), 1) 
COMMON+= -DCUDNN 
CFLAGS+= -DCUDNN -pg
LDFLAGS+= -lcudnn
endif
〜〜〜
# 再ビルド
$ make clean; make

# yolov3を動かして「gmon.out」を出力させる
$ ./darknet detect cfg/yolov3.cfg ../yolov3.weights ../street.jpeg
>>>>
../street.jpeg: Predicted in 35.500371 second

# 確認
$ ls 
gmon.out      predictions.jpg darknet  〜

# 可視化画像(output.png)を作成
$ cp ../gprof2dot.py gprof2dot.py
$ gprof ./darknet | ./gprof2dot.py | dot -Tpng -o output.png

Yolov3のtest1.jpegの処理性能の可視化f:id:trafalbad:20200413123603p:plain


Yolov3のtest2.jpegの処理性能の可視化f:id:trafalbad:20200413124300p:plain


Yolov3のNN以外のCPUの処理性能部分で高速化できる要素は、「gemm_nn」の部分。
ここがCPU部分の処理性能の90%以上を占めてるので、vivadoで高速化できる。




Tiny-Yolov3のtest1.jpegの処理性能の可視化f:id:trafalbad:20200413123746p:plain





今回はultra96v2でyolov3の物体検出をしてみた。
PetaLinuxの環境構築をしておけば、linux(PetaLinux)上から簡単にultra96v2を動かせるので便利。

今度は、USBカメラにつけてもっと実用的に動かしてみる。



参考サイト



Ultra96 PYNQ Darknet Google-Colabo

System-on-Chip (SoC) Design

gprof2dotのgithub

強化学習で三目並べ版の「AlphaZero」を作ったのでその仕組みまとめ【機械学習】

DeepMindが作った世界最強のゲームAIに使われているアルゴリズムが「AlphaZero」の仕組みを利用して、今回は「三目並べ」というゲーム版のAlphaZeroを作ってみた。

今回は備忘録として「三目並べ版-AlphaZero」の仕組みを淡々とまとめていく。


目次
1.AlphaZeroの仕組み
2.「三目並べ」の環境
3.AlphaZeroで使うニューラルネットワーク
4.自己対戦(Self-Playing)部分
5.パラメータ更新部分
6.パラメータ評価部分
7.パフォーマンス


1.AlphaZeroの仕組み


1.はじめに「best player」(いわゆるAgent)を作る

2.戦略と価値を更新するニューララネットワーク(Dual NN)でモンテカルロ法を使いながら自己対戦を繰り返して、学習データを貯めていく

3.その学習データをもとに「latest player」という、この時点で最強のpalyerをもう一つ作る。

4.「best player」と「latest player」を対戦させ、より強い方を「best player」として採用し、また自己対戦をさせる~

5.2〜4を繰り返す


というサイクルを繰り返して強くなっていく。

f:id:trafalbad:20200408173249j:plain


三目並べは単純なのでGPUが1つでも半日もあれば、十分に強くなる。





2.「三目並べ」の環境

ここでは三目並べ用の環境(Environment)を定義するコードが必要で適宜関数とかクラスを用意する。


「三目並べ」というゲームの詳細な説明は参考サイトを参照。
いわば。超simpleな簡易版の対戦ゲーム。






3.AlphaZeroで使うニューラルネットワーク

AlphaZeroで使うニューラルネットワーク(Dual NN)は

入力:「相手と自分の状態(S)」

出力戦略(Policy)と価値(Value)

の出入力構成で「戦略と価値」の2つ出力するDual NN。

まずDual NNを動かして一番はじめの「best player」を作る。

optimizerはDeepmind本家のはSGDだけど、今回はスピード重視なのでAdamにした。

def dual_network():
 # if trained model, nothing to do
 if os.path.exists('./model/best.h5'):
     return

 input = Input(shape=DN_INPUT_SHAPE)
 x = conv(DN_FILTERS)(input)
 x = BatchNormalization()(x)
 x = Activation('relu')(x)

 # resblock x 19
 for i in range(DN_RESIDUAL_NUM):
     x = residual_block()(x)

 x = GlobalAveragePooling2D()(x)
 p = Dense(DN_OUTPUT_SIZE, kernel_regularizer=l2(0.0005),
             activation='softmax', name='pi')(x)

 v = Dense(1, kernel_regularizer=l2(0.0005))(x)
 v = Activation('tanh', name='v')(v)
 model = Model(inputs=input, outputs=[p,v])


4.自己対戦(Self-Playing)部分

best player(Dual NN)同士を戦わせて互いに腕を上げていく部分。GANの仕組みとほぼ同じ。

戦わせながら1 playごとに学習データに

・相手と自分の盤上の駒の状態:累積s(累積状態)

・1 playの戦略のscore:policy score

・1 playの価値の合計:累積v(累積価値)

の3つをlist形式で貯めていく。


f:id:trafalbad:20200408174339j:plain


SELFPLAY_GAME_COUNT = 500
def self_play():
 # train data list
 history = []

 # load best player
 model = load_model('./model/best.h5')

 # multi play
 for i in range(SELFPLAY_GAME_COUNT):
     # 1 play
     h = one_episode_play(model)
     history.extend(h)

     print('\rSelfPlay {}/{}'.format(i+1, SELFPLAY_GAME_COUNT), end='')
 print('')

 # save train data
 save_state_policy_value(history)

 K.clear_session()
 del model



5.パラメータ更新部分

自己対戦(Self-Playing)で貯めた学習データを使って、Dual NNを学習。

・説明変数が「状態s」

・ターゲット変数が「戦略(p)」と「価値(s)」

def create_latest_player():
 def train_dual_network():
     # load train data
     xs, y_policies, y_values = load_policy_value()

     # load best player
     model = load_model(best_weight)
 
     model.compile(loss=['categorical_crossentropy', 'mse'], optimizer='adam')

     lr_decay, print_callback = call_back()


     # train
     model.fit(xs, [y_policies, y_values], batch_size=128, epochs=RN_EPOCHS,
             verbose=0, callbacks=[lr_decay, print_callback])
     print('')

     # save latest player
     model.save('./model/latest.h5')

     # delete model 
     K.clear_session()
     del model
 return train_dual_network


最後に「latest player」として学習済みモデルを保存する。
「latest player」は500戦した学習データをもとに、報酬(勝率)が最大になるように作り上げた一番強いplayer。

これではじめの「best player」と「latest player」という2人のplayer(正確にはAgent)ができた。






6.パラメータ評価部分

「best player」と「latest player」を10回戦わせて、一番強いplayerを新たな「best player」として採用し、弱い方は捨てる。

def total_episode_play():
 # load latest player
 model0 = load_model('./model/latest.h5')

 # load best layer 
 model1 = load_model('./model/best.h5')

 # select action by PV MCTS
 next_action0 = select_action_by_pv_mcts(model0, BOLTZMAN_TEMP)
 next_action1 = select_action_by_pv_mcts(model1, BOLTZMAN_TEMP)
 next_actions = (next_action0, next_action1)

 # multi play
 total_point = 0
 for i in range(GAME_COUNT):
     # 1 play
     if i % 2 == 0:
         total_point += one_episode_play(next_actions)
     else:
         total_point += 1 - one_episode_play(list(reversed(next_actions)))

     print('\rEvaluate for update player {}/{}'.format(i + 1, GAME_COUNT), end='')
 print('')

 # caluculate average point
 average_point = total_point / GAME_COUNT
 print('AveragePoint', average_point)

 # delete models
 K.clear_session()
 del model0
 del model1

 if average_point > 0.5:
     print('change best player')
     update_best_player()
     return True
 else:
     return False

これでまた始めに戻り、自己対戦(Self-Playing)~パラメータ評価を繰り返してplayerの強さを上げていく。





7.パフォーマンス

以下がAlphaZeroのサイクルを回してplayerを強くしていくアルゴリズムのコード。

途中の「新パラメータ評価部」で、別のアルゴリズムと対戦させて、best playerを評価(強さを確かめてる)してる。

train_network = create_latest_player()

# create dual NN
dual_network()

for i in range(10):
 print('Train',i,'====================')
 # セルフプレイ部
 self_play()

 # パラメータ更新部
 train_network()

 # 新パラメータ評価部
 update_best_player = total_episode_play()

 # ベストプレイヤーの評価
 if update_best_player:
     evaluate_best_player()

>>>>>

Train 0 ====================
SelfPlay 500/500
Train 100/100
Evaluate for update player 10/10
AveragePoint 0.95
Change BestPlayer

Evaluate 10/10
VS_Random 1.0
VS_AlphaBeta 0.25
VS_MCTS 0.5
<略>
Train 10 ====================
SelfPlay 500/500
Train 100/100
Evaluate for update player 10/10
AveragePoint 0.95
Change BestPlayer

Evaluate 10/10
VS_Random 1.0
VS_AlphaBeta 0.55
VS_MCTS 0.6


三目並べでほぼ最強のアルゴリズム「alpha-beta法」に互角以上の成績を叩き出した。




AlphaZeroはかなり汎用性がある、対戦用のメカニズムになっているなと感じた。

ハイエンド脳無もこんな感じで作れたらなとか思う今日この頃。

f:id:trafalbad:20200408173342j:plain

Vitis IDEでultra96向けplatform作成と、ultra96v2で動作確認するまで【avnet,hardware】VitisPlatform作りpart4

今回は

Vitisプラットフォーム(Vitis IDE)でultra96向けプラットフォームを作成

ultra96v2で実際に動作確認する

ところまでやってみたいと思う。

本家サイトのラストの部分まで。


今回のpart4でこの部分ができる。
f:id:trafalbad:20200404110016p:plain


目次
1.ultra96向けプラットフォームの作成
2.テストアプリケーションの作成
3.ultra96v2のSDカードにコピー
4.wifiを接続後にultra96v2で動作確認
5.次にやりたいこと




1.ultra96向けプラットフォームの作成

# vitis起動
cd /home/[user]/ultra96base/pfm
vitis -workspace wksp1


  • [Create platform project]からプラッフォフォーム作成

  • プラッフォフォーム名(今回は[ultra96base])を入力。
    f:id:trafalbad:20200404110625p:plain


    XSAファイルから作成するので、[Create from hardware specification (XSA)] => [Next]


  • Vivadoで作成した、XSAファイルを指定
  • Operating system は Linux

    Processorpsu_cortexa53

    足りないファイルは追加していくので、ビックリマークは赤いままでOK、[Finish]をクリック。
    f:id:trafalbad:20200404111101j:plain


    ファイル一覧に

    linux

    ・zynqmp_fsbl

    ・zynqmp_pmufw

    があることを確認。



  • [linux on psu_cortexa53]を選択
  • Bifファイルは 「linux.bif」

    Boot ComponentDirectoryは「bootディレクトリー」

    Linux imageのDirectoryは 「bootディレクトリー」

    Sysrootディレクトリーには、「sysroots/aarch64-xilinx-linux

    をそれぞれ指定。
    f:id:trafalbad:20200404110822j:plain





  • 下図のトンカチアイコンをクリックして、ビルド

  • インデックスファイルを作っているらしく、時間がかかる。


    少し待つとビルドがおわり、コンソールに[Bulid Finished]が表示される。
    f:id:trafalbad:20200404110738j:plain

    exportフォルダーにプラットフォームのデータ[ultra96base.xpfm]が作成されてる。

    # 確認
    $ ls /home/[host-name]/ultra96base/pfm/wksp1/ultra96base/export/ultra96base
    hw  sw  ultra96base.xpfm
    


    これでultra96向けのプラットフォームができた。






    2.テストアプリケーションの作成

    ultra96v2用のファイルを作成してく。

  • Vitis IDEのメニューから File→New→Application Projectを選択して、
    プロジェクトネーム(今回は「alternative_xsa」)を適当に入れて[Next]をクリック
  • f:id:trafalbad:20200404110554j:plain



    プラットフォームを選択できるので、[ultra96base]を選択して、Nextをクリック。
    f:id:trafalbad:20200404111209p:plain



  • 次はsysroot等を聞いてくるので、デフォルトで[Next]
  • その後、ultra96v2で試す用のExampleファイルを作成。

    今回は[Hello World]しかないので、Exampleとして取り込んでダウンロード。


  • 上のトンカチアイコンから、ハードウェアの[Debug]を選択してビルド

  • ビルド後、SDcardのハードウェアフォルダ(Debug)の中に必要なファイルが作成される。

    # Debugフォルダが出来てるか確認
    $ ls
    Debug  _ide  alternative_xsa.prj  src
    





    3.ultra96v2のSDカードにコピー

    ここでVitis IDEの操作は終わり。


    後はultra96v2のSDカードにコピーしていく。
    ultra96v2付属のSDカード
    f:id:trafalbad:20200404110110j:plain



    マウントフォルダのパス

    ・ホストOS側「Volumes/BUFFALO/mount」

    ・ゲストOS側「/media/sf_mount」


    Debugファルダ内のファイルを外付けHDDのマウントファルダ(Volumes/BUFFALO/mount)にコピーする。
    それからGUIでultra96v2のSDカードのFAT領域(/Volumes/boot/boot)に移動。

    # 外吹けHDDマウントフォルダにbootファルダを作成
    $ sudo mkdir /media/sf_mount/boot
    
    # マウントフォルダにコピー
    $ sudo cp -r /home/[host-name]/ultra96base/pfm/wksp1/alternative_xsa/Debug/* /media/sf_mount/boot
    

    コピーした後、GUIでSDカード内に移動。




    次に、Petalinuxで作ったrootfs.tar.gzをSDカードのEXTフォルダー(/Volumes/boot/rootfs)に入れる。
    その後、GUIでultra96v2のSDカードのEXTフォルダー(/Volumes/boot/rootfs)に移動。

    # マウントフォルダにrootfsファルダを作成
    $ sudo mkdir /media/sf_mount/rootfs
    
    # Petalinuxで作ったrootfs.tar.gzをrootfsファルダにコピー
    $ sudo cp /home/[host-name]/ultra96base/petalinux/images/linux/rootfs.tar.gz /media/sf_mount/rootfs/
    
    # ホストOS側で解凍してSDカードのEXTフォルダーにコピー
    $ sudo tar xzvf /Volumes/BUFFALO/mount/rootfs.tar.gz -C /Volumes/boot/rootfs
    

    同じくコピーした後、GUIでSDカード内に移動






    4.wifiを接続後にultra96v2で動作確認

    ultra96v2で動作確認のため、まずPCと


    ultra96v2を接続
    f:id:trafalbad:20200404110133j:plain

    ultra96v2の接続・ログイン記事はこちらを参照
    trafalbad.hatenadiary.jp



    # sshでログイン
    $ ssh -l root 192.168.2.1
    $ cd /run/media/mmcblk0p1 && export XILINX_XRT=/usr
    $ cd boot 
    
    # 動作確認
    $ ./alternative_xsa.elf vadd.xclbin
    >>>
    Hello World
    

    f:id:trafalbad:20200404110259p:plain


    動作してるのが確認できた!





    5.次にやりたいこと

    part1~4でultra96v2の動作の全体像のこの領域ができた。
    f:id:trafalbad:20200404110044p:plain




    次は

    ・実際にultra96v2で学習済みAIを動かす(Vitis AIの作成とか)

    ・リアルに論理回路をいじったりするガチなところまで触れる

    PYNQの構築

    とかもっとガチのAI部分まで触れてみたい。その前にこの低スペックPCを買い換えなきゃな。


    f:id:trafalbad:20200404111717j:plain



    追記:メモ


    一回作ったプロジェクトまたは、bspファイルから作成したプロジェクトで、回路デザインのプログラマロジック(PL)回路を変更する際の、変更手順を簡単にまとめ。



    プログラマロジックの回路変更手順

    1.vivadoでPL回路変更
    2.BitStream生成
    3.Export Hardware
    4.petalinux-config
    5.petalinux-build
    6.petalinux-package


    f:id:trafalbad:20200407104154j:plain


    参考サイト回路情報のエクスポート




    参考サイト



    How to create Ultra96v2 Linux-based Platform in Xilinx Vitis 2019.2

    ultra96v2の動作に必要な「BIFファイル」作成、vitis IDEの立ち上げまで【FPGA】- VitisPlatform作りpart3

    前回の続編のpart3。Vivadoでultra96のデザインブロックとかXSAファイルを作成した後、PetaLinuxでVitisプラットフォーム(vitis IDE)立ち上げまでやっていく。

    part3の作業で完了するのは「vitis IDE」構築のvitisの部分。
    f:id:trafalbad:20200314065320p:plain



    メインでにやること

    ・ultra96の動作に必要な「BIFファイル」の作成

    ・vitis IDEの立ち上げ


    手順はほぼ本家のサイト「Ultra96用Vitisプラットフォームの作り方(BASE編)」通り作業していく。



    ただVivadoで作成するXSAファイルは本家サイト通りやってもエラーが出て作成できなかったので、Xilinxgithubのファイルで代用した。
    Alternative XSA file at GitHub


    目次
    1.Vivadoでのハードウェア設計
    2.PetalinuxでLinuxシステムの設計
    3.Vitis IDEを立ち上げてみる





    1.Vivadoでのハードウェア設計

    Vivadoでultra96v2で動作させるハードウェアを設計。
    今回は参考サイトのだと何故かうまくいかないので、Xilinxgithubから代用のXSAファイルを使う。

    一応、ultra96で使うまでのハードウェア設計の手順だけまとめていく。ここはほぼ本家と同じ



    1.新規プロジェクトと新規ブロックデザインの作成



  • 「Create Project」からProject作成
  • ・Project name:ultra96base
    ・Project location: /home/[host-name]/ultra96base
    ・Project type:RTL Project
    (「Do not specify sources at this time」のブロックにチェックを入れた)


  • [Add Sources]と[Add Constraints]ページはデフォルトのまま[next]ボタン。

  • 次のページで右の「Board」クリックから「Ultra96」をsearchで「Ultra96v2 Evaluation Platform」を選択 => next&finishでNew Project完成。

  • ***Project再開方法
    Open ProjectからProjectを作ったフォルダの[プロジェクト名.xpr]を選択し、再開。



  • 次にブッロクデザインの作成

  • 右の[Flow Navigator]でIP INTEGRATOR => Create Block Design => ブロックデザイン名を決める。
    デフォルでいいのでOKで作成。




    2.Blockの配置・配線



    デザインを作成すると、キャンパスが出てくるのでブロック追加・配線をする。ここは本家サイトと同じなので
    ・簡単な流れ
    ・エラーになる箇所のポイント
    をまとめた。


  • +のアイコンから[Add IP]でブロックを追加していく

  • [Search]からzynqを入力して[Zynq UltraScale+ MPSoC]を選択・配置して、[Run Block Automation]をクリックし、デフォルト値のままOK。
    f:id:trafalbad:20200403001151j:plain



  • ZYNQ7 Processing Systemをダブルクリックし、PS-PL Configuration -> AXI Non Secure Enablement -> GP Master AXI Interface -> M_AXI_GP0 interface のチェックを外し、OKをクリック
  • Clocking Wizardを追加し、その後同IPの設定のOutput Clocksタブより、clk_out2~Nまで追加して、適切なHzに変更(例:clk_out2を200Hz, clk_out3を300MHz)。 Reset TypeをActive Lowにする
  • Processor System ResetとConcatを配置
  • Concatは[Number of Port]を1にする。

  • 下図のように配線
    f:id:trafalbad:20200403001244p:plain





    配線実行例

  • 1.右クリックからの[Add IP]
  • 2.resetで検索してから[Processer System Reset]を選択
  • 3.上の丸アイコン押すと、ブロックがアップになる
  • 4.連結したい配線部分をクリック(オレンジに染まる)
  • 5.右クリックから[Make Connection]

  • f:id:trafalbad:20200403001341j:plain


  • 6.連結したい導線部分を選択しOKで配線完了



  • 完全に慣れなので一つずつ確実に配線してく。







    3.プラットフォーム(PFM)インターフェースとプロパティの定義



  • [Window]から[Platform Interface] => [Enable platform Interfaces]をクリックインターフェイス作成。
  • Board名を「ultra96v2」に変更
  • [Source]から必要なポートをダブルクリックで[Enable]で有効化
  • clk_out1 (100 MHz) をクリック後、[Platform Interface Properties] の中の Optionsのタブをクリックして、[is_default]を選択して、idを0に変更。(id変更したら必ずエンターキーをクリック)


  • ***ここ大事
    ・clk_outのidをclk_out1から順にidを0, 1, 2にする(clk_out2, 3はidを1, 2に変更)


    18- Select the enabled clk_out1 and in the Options window change the id to 0 and select the is_default. Note, to change the id filed you must press the Enter key on your keyboard. Change ids of clk_out2, clk_out3, and clk_out4 to 1, 2, and 3, respectively.

    引用元:How to create Ultra96v2 Linux-based Platform in Xilinx Vitis 2019.2



    4.XRT用の設定から[BitStream]まで



  • 下のほうにTclコンソールがあるので次コマンドを入力。1行ずつ入れてく
  • set_property platform.design_intent.embedded true [current_project]
    set_property platform.design_intent.server_managed false [current_project]
    set_property platform.design_intent.external_host false [current_project]
    set_property platform.design_intent.datacenter false [current_project]
    set_property platform.default_output_type "sd_card" [current_project]
    

  • 上部にある[Validate Design]アイコンをクリック、OKなら問題なし

  • f:id:trafalbad:20200403001428j:plain


  • [Source]タブの中のデザインファイル[ultra96base(ultra96base.bd)]を右クリック、メニューから、[Create HDL Wrapper]を選択してOK
  • =>オレンジから青のファイル(ultra96base_wrapper(ultra96base_wrapper.v))に変わる
    f:id:trafalbad:20200403001741p:plain



  • [Flow Navigator]の[Generate Bitstream]をクリックで、ビットストリームを作成。2つほどダイアログが出て、Save=>Yes=>Okの順でクリックすればOK。

  • f:id:trafalbad:20200403001524j:plain


  • 数十分後、Bitstream Generation Completed ダイアログが表示されるので、Cancel ボタンをクリックする。



  • 5.XSAファイルの作成



    Vivadoのメニューから [File] → [Export]→[Export Hardware]
    をクリック。

    [include bitstream]にチェックをいれて、デザインの名前を[ultra96base](プロジェクト名と同じ)に変更
    f:id:trafalbad:20200403001806j:plain


    XSAファイルの名前をプロジェクト名と同じ「ultra96base.xsa」にするのは下の理由から。

    ハードウェア・コンポーネント(XSAファイル)とソフトウェア・コンポーネント(SPFMファイル)の名前を一致させる必要あるから

    アクセレーション・プラットフォームとVitisに認識させるにはハードとソフトの名前の一致が重要な要件だから



  • Tclコンソールから、出力したファイルのチェック以下コマンドで確かめる。
  • ちゃんとできてるなら、エラーが出ないで成功

    $ validate_hw_platform <Write Path>/ultra96base.xsa
    >>>
    INFO: [Vivado 12-6074] Validating Hardware Platform: ‘/home/[host-name]/ultra96base/ultra96base.xsa’
    〜略〜
    INFO: [Vivado 12-6067] Found file 'ultra96base.bit' of type 'FULL_BIT' in the Hardware Platform.
    INFO: [Vivado 12-6066] Finished running validate_dsa for file: '/home/[host-name]/ultra96base/ultra96base.xsa'
    




    2.PetalinuxでLinuxシステムの設計

    PetaLinuxシステムで、Ultra96の動作に必要なBIFファイルと、Vitis IDEに必要なSDKファイルを作成してく。

    メインでやること
    ・ultra96の動作に必要なBIFファイルの作成

    ・vitis IDE立ち上げ





    1.Petalinux用のプロジェクトの作成



    プロジェクトのファルダ内(/home/[host-name]/ultra96base)で実行。

    # ディレクトリ構成
    $ tree
    /home/[host-name]/ultra96base
               └── <>
               └──ultra96base.xpr
               └──ultra96base.xsa
    
    
    # git cloneしてきたものなので権限付与
    $  sudo chmod 777 ultra96base.xsa
    
    # プロジェクト作成
    $ petalinux-create -t project -n petalinux --template zynqMP
    >>>
    INFO: Create project: petalinux
    INFO: New project successfully created in /opt/petalinux/petalinux
    




    2.Vivadoで作成したXSAファイルの取り込み


    $ cd petalinux
    $ petalinux-config ―get-hw-description=/home/[host-name]/ultra96base
    

    コンソールによるメニュー形式が出てくるので本家の通り操作。
    DTG Settngs → MACHINE_NAMEを[avnet-ultra96-rev1]

    [Exit]で戻り、Subsystem AUTO Hardware Settings → Serial Settings を設定、その後、[psu_uart_1]に設定
    f:id:trafalbad:20200403002305j:plain


    f:id:trafalbad:20200403002324j:plain



    次にシステムを増やすために、SDカードの記録方法を指定。

    2回[Exit]でトップメニューから、[Image Packageing Configuration] => [Root filesystem type] から[EXT(SD/eMMC/QSPI/STAT/USB)]を[select]で選択。

    選択して[Exit]を2回。その後、「保存しますか」を聞いてくるので、Yesをクリック。

    完了まで時間がかかるのでコーヒーブレイク。

    出力ログ

    INFO: Getting hardware description...
    INFO: Rename ultra96base.xsa to system.xsa
    [INFO] generating Kconfig for project
    [INFO] menuconfig project
    configuration written to /home/[host-name]/ultra96base/petalinux/project-spec/configs/config
    
    *** End of the configuration.
    *** Execute 'make' to start the build or try 'make help'.
    〜略〜
    [INFO] silentconfig rootfs
    [INFO] generating petalinux-user-image.bb
    
    # ファルダ状況確認
    $ ls
    >>>
    build  components  config.project  project-spec
    



    3.ファイルの追加・編集



    # XRTを使えるようにするため追記
    $ sudo vi /home/[host-name]/ultra96base/petalinux/project-spec/meta-user/conf/user-rootfsconfig
    
    #Note: Mention Each package in individual line
    #These packages will get added into rootfs menu entry
    
    CONFIG_gpio-demo
    CONFIG_peekpoke
    CONFIG_xrt
    CONFIG_xrt-dev
    CONFIG_zocl
    CONFIG_opencl-clhpp-dev
    CONFIG_opencl-headers-dev
    CONFIG_packagegroup-petalinux-opencv
    # Zynqシリーズで、XRTドライバーが使えるようにする
    $ sudo vi /home/[host-name]/ultra96base/petalinux/project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi
    
    /include/ "system-conf.dtsi"
    / {
    };
    &amba {
      zyxclmm_drm {
          compatible = "xlnx,zocl";
          status = "okay";
      };
    };

    上の設定したファイルを有効可するため下コマンドを実行。

    コンソールによるメニュー形式が出てくるので[user packages]を選択。

    出ているプログラムでスペースキーをクリックしてすべて有効にする。
    f:id:trafalbad:20200403003528j:plain


    2回[Exit]で、セーブして、Yesで保存。

    $ cd && cd ultra96base/petalinux
    $ petalinux-config -c rootfs
    
    >>>
    [INFO] sourcing bitbake
    [INFO] generating plnxtool conf
    〜略〜
    [INFO] menuconfig rootfs
    configuration written to /home/[host-name]/ultra96base/petalinux/project-spec/configs/rootfs_config
    
    *** End of the configuration.
    *** Execute 'make' to start the build or try 'make help'.
    
    [INFO] generating petalinux-user-image.bb
    [INFO] successfully configured rootfs
    




    4.カーネルの操作でDMA転送用のメモリーの確保



    ここも本家通り操作。

    $ petalinux-config -c kernel
    >>>
    [INFO] generating Kconfig for project
    ~略~
    NOTE: Source tree extracted to /home/[host-name]/ultra96base/petalinux/components/plnx_workspace/sources/linux-xlnx
    WARNING: SRC_URI is conditionally overridden in this recipe, thus several devtool-override-* branches have been created, one for each override that makes changes to SRC_URI. It is recommended that you make changes to the devtool branch first, then checkout and rebase each devtool-override-* branch and update any unique patches there (duplicates on those branches will be ignored by devtool finish/update-recipe)
    NOTE: Recipe linux-xlnx now set up to build from /home/[host-name]/ultra96base/petalinux/components/plnx_workspace/sources/linux-xlnx
    ~略~
    NOTE: Updating config fragment /home/[host-name]/ultra96base/petalinux/components/plnx_workspace/sources/linux-xlnx/oe-local-files/devtool-fragment.cfg
    [INFO] successfully configured kernel
    

    ここでコンソールによるメニュー形式が出てくるので本家の通り操作。

    [Device Drivers]→ [Generic Driver Options]→ [DMA Contiguous Memory Allocator] → [Size in Mega Bytes]をクリックして、256を1024に変更。

    f:id:trafalbad:20200403003629j:plain

    f:id:trafalbad:20200403003645j:plain


    [Exit]=>[Save]で保存して終わり。

    ここまでで、コンフィグレーションの設定は終わり。




    5.ビルドしてSDKファイルの作成


    2箇所ビルドをします。かなり時間がかかるところなので、気長に。

    1回目のbuildが終わった時点で、Petalinux-packgeを使って、BOOT.BINファイルを作成して、SDカードにコピーすれば、Ultra96が動作可能。(今回はしない)

    # 1回目のビルド
    $ petalinux-build
    >>>
    [INFO] building project
    ~略~
    NOTE: Resolving any missing task queue dependencies
    WARNING: /opt/petalinux/components/yocto/source/aarch64/layers/meta-xilinx/meta-xilinx-bsp/recipes-kernel/linux/linux-xlnx_2019.2.bb.do_compile is tainted from a forced run
    ~略~
    NOTE: linux-xlnx: compiling from external source tree /home/[host-name]/ultra96base/petalinux/components/plnx_workspace/sources/linux-xlnx
    ~略~
    INFO: Creating /home/[host-name]/ultra96base/petalinux/images/linux directory
    NOTE: Failed to copy built images to tftp dir: /tftpboot 
    [INFO] successfully built project
    
    # ファルダ状況確認
    $ ls
    >>>
    build  components  config.project  images  project-spec
    
    # 2回目のビルド
    $ cd images/linux
    $ petalinux-build --sdk
    >>>
    [INFO] building project
    ~略~
    WARNING: /opt/petalinux/components/yocto/source/aarch64/layers/meta-xilinx/meta-xilinx-bsp/recipes-kernel/linux/linux-xlnx_2019.2.bb.do_compile is tainted from a forced run
    Initialising tasks: 100% 
    ~略〜
    [INFO] Copying SDK Installer...
    [INFO] successfully built project
    
    # sdk.shが出来てるか確認
    $ ls
    ~~~
    pxelinux.cfg      sdk.sh                 zynqmp-qemu-multiarch-pmu.dtb
    rootfs.cpio       system.bit             zynqmp_fsbl.elf
    


    sdk.shは自己解凍ファイルなので解凍して、Vitis IDEのsysrootにする。

    $ cd ../../..  && mkdir pfm
    $ ./petalinux/images/linux/sdk.sh
    


    出力する場所のパスを聞いてくるので、パス(今回は/home/[host-name]/ultra96base/pfm)を指定。

    PetaLinux SDK installer version 2019.2
    ======================================
    Enter target directory for SDK (default: /opt/petalinux/2019.2): /home/[host-name]/ultra96base/pfm
    
    You are about to install the SDK to "/home/[host-name]/ultra96base/pfm". 
    SDK............................................................done
    Setting it up...done
    SDK has been successfully set up and is ready to be used.
    Each time you wish to use the SDK in a new shell session, you need to source the environment setup script e.g.
    $ . /home/[host-name]/ultra96base/pfm/environment-setup-aarch64-xilinx-linux
    
    # 確認
    $ ls pfm
    >>>
    environment-setup-aarch64-xilinx-linux  sysroots
    site-config-aarch64-xilinx-linux        version-aarch64-xilinx-linux
    


    最後にVitis IDE作成時にブートするファイルのコピー

    $ mkdir boot && cd petalinux/images/linux
    $ cp image.ub zynqmp_fsbl.elf pmufw.elf bl31.elf u-boot.elf ../../../boot
    $ cd ../../..
    



    6.BIFファイルの作成



    BIFファイルはSDカードを作るときに必要。作成には下のテキストファイルをboot/linux.bif としてそのまま作成

    $ sudo vi boot/linux.bif
    
    /* linux */
    the_ROM_image:
    {
      [fsbl_config] a53_x64
      [bootloader] <zynqmp_fsbl.elf>
      [pmufw_image] <pmufw.elf>
      [destination_device=pl] <bitstream>
      [destination_cpu=a53-0, exception_level=el-3, trustzone] <bl31.elf>
      [destination_cpu=a53-0, exception_level=el-2] <u-boot.elf>
    }



    3.Vitis IDEを立ち上げてみる

    Vitis IDEを起動してみる。

    $ cd /home/[host-name]/ultra96base/pfm
    $ vitis -workspace wksp1
    

    f:id:trafalbad:20200403000935p:plain


    無事立ち上がった。
    PCが低スペックすぎるので、Petalinuxのビルドのところでとんでもなく時間かかった。2017年以降のMacなら割と早く終わるはず。



    参考サイト



    Ultra96-V2 の Vitis アクセラレーション・プラットフォームの作り方(ハードウェア・コンポーネント編)

    FPGAの部屋

    Running Ubuntu on Ultra96v2 Using Petalinux 2019.2, with Networking

    Xlinx-2018.3 SDSoC™ Development Environment Tutorials

    How to create Ultra96v2 Linux-based Platform in Xilinx Vitis 2019.2

    Xilinxサポートフォーラム