読者です 読者をやめる 読者になる 読者になる

3Dプリンタ ダヴィンチ mini wレビュー

前々から欲しいと思っていた3Dプリンタを遂に購入したのでレビュー。購入したのは有名なダヴィンチシリーズのダヴィンチ mini W。wifi機能がついていて4万円以下のお手頃価格。私はAmazonで購入しましたが、ポイントはつかないので、そこを考えると、家電量販店のほうが安いかもしれません。また、フィラメントが付いてこないものだと思って、一緒にフィラメントを買ったのですが、黄色のフィラメントが本体に付いていました。

セットアップ

開封すると、下の写真のようなものが出てきます。ヘラが入ってるのに驚きましたが、実際重要なアイテムでした。また、ノズルをクリーニングするための道具も色々入っています。なお、大変簡素なマニュアルが入っていましたが、カラーではなくモノクロなので、物凄く写真が見づらかったです。せめてカラーにして欲しかった。

f:id:oki-lab:20170429175354j:plain:w300

3Dプリンタ本体にテープやらストップやらが全部取り払った後、セットアップを行います。と言っても、大層なものではなく、数分で終わります。
まずは、プリントモジュールとガイドチューブを取り付け。このガイドチューブを溶けたフィラメントが通って、ノズルから出てきます。

f:id:oki-lab:20170429180503j:plain:w300

次にフィラメントのセット。ドライバを使い、リールから部品を外します。次に、ICチップを 所定の位置にセットし、部品をリールに再固定。このICチップで長さを管理しており、なおかつ純正のフィラメントしか使えないようにしています。(Arduinoを使ってゴニョゴニョすると純正以外も使えるらしい)
リールは本体の左側にセットします。更に、プラットフォームテープをベッド部分に貼ります。

f:id:oki-lab:20170429180841j:plain:w300 f:id:oki-lab:20170429181134j:plain:w300

以上でハードのセットアップは完了です。次に、ソフトウェアをダウンロードします。 以下のリンク先でXYZwareというソフトをダウンロードしてインストールします。なお、会員登録しないとダウンロードできないようです。

XYZprinting 3D Printer

インストールが終わったら、XYZwareを起動して、モデルを開いてプリントするだけです。なお、最初は直接USBでPCと接続する必要がある為、ノートPCで接続して、wifiの設定を完了してからwifi経由でデスクトップPCと接続すれば、特に、デスクトップPCの近くに配置することなく、自由な場所に置くことが出来ます。

プリント

今回は、ソフトに初めから入っていたペン立てっぽいサンプルモデルをプリントすることにしました。
印刷の設定は標準のままでプリントを開始したのですが、結論からいうと2回失敗しました。
1回目は、ノズル先でフィラメントがぐちゃぐちゃになったまま、どうにもならず。ガイドチューブにフィラメントが充填されていない状態なので、フィラメントが出る頃にはノズルが浮いていたのかもしれません。
2回目は数分くらいうまくいっていましたが、途中で印刷物がテーブルから離れてしまいました。

f:id:oki-lab:20170429183043j:plain:w300

ここで、Google先生に助けを求め、結果、予めテーブルにのりを塗っておくと安定して印刷できるということを知りました。そこで、のりを塗りたくって印刷した結果、やっと印刷に成功しました。

f:id:oki-lab:20170429183359j:plain:w300

上の写真ではサイズが分かりにくいですが、高さが約7cm、直径が約5cmです。印刷のクオリティは標準のままで印刷時間は1時間半くらいでした。積層した跡は残っていますが、隙間等はなく、期待以上の出来でした。
なお、無事印刷自体は完了したのですが、のりを多めに塗ったせいか、剥がすのに一苦労しました。付属されていたヘラが無ければ剥がせなかったかもしれません。
くっついている物を無理やり剥がしたので、当然テーブルに貼っていたテープはボロボロになりました。ググると、3Mのテープが良い感じらしいので、次からはそれを試してみます。

カルマンフィルタで角度推定 (加速度センサ+ジャイロセンサ)

以前購入していた加速度センサ、ジャイロセンサの使い方を思い出す為に、それぞれの値を取得するプログラムを書きました。それだけでは面白くないので、カルマンフィルタで値を統合してみました。

機器構成はArduino nanoに加速度センサ(MMA7361)、ジャイロセンサ(ENC-03R)を接続し、更に、ArduinoRaspberry piを繋いでシリアル通信でデータのやり取りをする、というものです。Arduinoを使う理由はアナログ入力が楽だから、Raspberry piを使う理由はカルマンフィルタを使うのにpythonでプログラムを書きたかったからです。
なお、センサは秋月電子で買える以下のものです。

3軸加速度センサモジュール MMA7361(アナログ出力)
小型圧電振動ジャイロモジュール

各センサの接続先は加速度センサのx,y,zがそれぞれArduinoのA0,A1,A2、ジャイロセンサのOUT1がA3,OUT2がA4です。
加速度センサは計測範囲を広げるため、gSに3.3V入力します。

また、事前準備として、加速度センサを使うためのライブラリをインストールしておきます。

github.com

Arduino側プログラム

#include <AcceleroMMA7361.h>
#include <stdio.h>

AcceleroMMA7361 accelero;

int ax=0;
int ay=0;
int az=0;

int wx=0;
int wy=0;

char buf[50];

void setup(){
 Serial.begin(9600);
 accelero.begin(13,12,11,10,A0,A1,A2);
 accelero.setARefVoltage(3.3);
 accelero.setSensitivity(LOW);
 accelero.calibrate();
}

void loop(){
 ax=accelero.getXAccel();
 ay=accelero.getYAccel();
 az=accelero.getZAccel();
 
 wx=analogRead(3);
 wy=analogRead(4);
 
 //ax=accelero.getXRaw();
 //ay=accelero.getYRaw();
 //az=accelero.getZRaw();
 
 sprintf(buf,"%d,%d,%d,%d,%d\n",ax,ay,az,wx,wy);
 
 Serial.write(buf);
 delay(1);
}

Raspberry pi側プログラム

import serial
import numpy as np
import time

ser=serial.Serial("/dev/ttyUSB0",9600)

data=np.zeros(5)

#offset=1.35/3.3*1023
offset=np.array((445,442))

F=np.matrix(np.identity(2))
H=np.matrix(np.identity(2))
x=np.zeros((2,1))
y=np.zeros((2,1))
u=np.zeros((2,1))
dt=0.01
P=np.zeros((2,2))
Q=np.array(((1E-3,0),(0,1E-3)))
R=np.array(((1E-2,0),(0,1E-2)))
t=time.time()
a=np.zeros((2,1))

elapsedTime=0
w=np.zeros((2,1))
rawData=[]
estData=[]
t=time.time()
dt=0

firstFlag=True

while True:
    val=str(ser.readline())
    temp=val.split(",")

    try:
        for i in range(5):
            data[i]=float(temp[i])

        print (data[0],data[1],data[2],data[3],data[4])

        #For initializing time
        if (firstFlag):
            firstFlag=False
            t=time.time()

        #angular acceleration (gyro sensor)
        a[0]=(data[3]-offset[0])/1023*3.3/0.00067*np.pi/180
        a[1]=(data[4]-offset[1])/1023*3.3/0.00067*np.pi/180

        #angular velocity (gyro sensor)
        for i in range(2):
            if (np.abs(a[i])>5):
                u[i]+=a[i]*dt

        #angle (acceleration sensor)
        y[0]=np.arctan2(data[1],np.sqrt(data[0]**2+data[2]**2))
        y[1]=np.arctan2(data[0],data[2])

        #angle (gyro sensor)
        w+=u*dt*180/np.pi

        #kalman filter
        x=x+u*dt
        P=np.dot(np.dot(F,P),F.T)+Q
        K=np.dot(np.dot(P,H.T),np.linalg.inv(np.dot(np.dot(H,P),H.T)+R))
        x=x+np.dot(K,(y-np.dot(H,x)))
        P=P-np.dot(np.dot(K,H),P)

        estData.append(np.r_[x*180/np.pi,y*180/np.pi,w])
        rawData.append(data)

        dt=time.time()-t
        t=time.time()
        elapsedTime+=dt

        print (int(elapsedTime),x*180/np.pi)

        if (elapsedTime>10):
            np.savetxt("estData.csv",estData,delimiter=",")
            np.savetxt("rawData.csv",rawData,delimiter=",")
            break

    except Exception as e:
        print (e.message)



一応コメントを書いてありますが、xがカルマンフィルタによる推定値、yが加速度による推定値、wがジャイロによる推定値(積分値)です。
QやRの共分散行列の値は適当です。数値を変えてもあまり変わりませんでした。
なお、はじめにプログラムを書いた時、ジャイロによる推定値が明らかにおかしかったので、計算方法が間違っていたのかと思いましたが、 ネットで調べてみると、回路上にハイパスフィルタが入っていて、出力値が角加速度になっているようです。その為、2階積分になるようなプログラムにしています。
また、ジャイロの積分誤差が大きい為、一定値以下の数値は無視しています。

一通り接続してセンサを傾けてみた結果が下記のグラフです。
ジャイロによる値は誤差が大きいですが、加速度による推定値とカルマンフィルタによる推定値は殆ど同じです。
今回の場合だとジャイロセンサがあまり役に立っていない気もしますが、とりあえず傾きが取得できるようになりました。

f:id:oki-lab:20170425202847j:plain

格安のArduino Nano互換機を使う

海外の通販でArduino Nanoの互換機を買ってみたのですが、動かすまでに少し手間取ったのでやったことをメモ。
目標は、Raspberry Pi上でスケッチを書くための環境を整えて、ArduinoRaspberry Piとデータのやり取りができるようにすることです。
また、今回はUbuntu MATEで試しています。

1.ドライバインストール

シリアル接続用のドライバをインストールします。 今回はRaspberry Pi上で使用するので、Linux用を下記からダウンロード。

CH341SER_LINUX.ZIP下载页面-江苏沁恒股份有限公司

解凍して、readmeに書かれている通り、make、make loadを実行します。 ただ、私の環境だと上記を実行すると、 /lib/modules/4.4.38-v7がどうのこうのというエラーが出てきたので、 色々調べてみた結果、下記を実行すると、makeが通るようになりました。

sudo apt-get install raspberrypi-kernel-headers

2.Arduino IDEインストール

下記を実行して、IDEをインストールします。

sudo apt-get install arduino

3.Arduinoへ書き込み

下記を実行してIDEを立ち上げます。

sudo arduino

Arduinoを接続した後、
ツール→マイコンボード→Arduino Nano w/ATmega328を選択。
ツール→シリアルポートでArduinoが接続されているポートを選択。

適当なスケッチを書いてみて、無事書き込みが出来ればOKです。

文字にすると簡単そうですが、ドライバのmakeができずに苦労しました。 また、Arduinoは2つ買ったのですが、そのうち1個はどうしても書き込みができず、 不良品だと思って諦めました。どうせ数百円なので返品はしませんが、 海外通販を使う際は、ダメ元くらいの感覚でいた方が良さそうです。

【TensorFlow】リカレントニューラルネットワークで為替レートを予測【FX】

以前、ニューラルネットワークで為替レートを予測する記事を書きましたが、 今度はTensorFlowを使って予測してみました。
前回とは異なり、今回はリカレントニューラルネットワークというものを使ってみます。理論は殆ど理解できていないので、 ここにあるコードを書き換えました。

入力は、4時間足のデータ25個、出力は3パターンで、4時間後に値が上昇するなら、[1,0,0]、下がるなら[0,1,0]、同値なら[0,0,1]としています。 なお、入力値は0~1の値に正規化しています。

学習プログラム

import tensorflow as tf
from tensorflow.contrib import rnn
import numpy as np


# Parameters
learning_rate = 0.01
training_iters = 100000
batch_size = 100
display_step = 10

# Network Parameters
n_input = 1
n_steps = 25 # timesteps
n_hidden = 1024 # hidden layer num of features
n_classes = 3

#exchange rates
data=np.loadtxt("input.csv",delimiter=",")

# tf Graph input
x = tf.placeholder("float", [None, n_steps, n_input])
y = tf.placeholder("float", [None, n_classes])

# Define weights
weights = {
    # Hidden layer weights => 2*n_hidden because of foward + backward cells
    'out': tf.Variable(tf.random_normal([2*n_hidden, n_classes]))
}
biases = {
    'out': tf.Variable(tf.random_normal([n_classes]))
}

def BiRNN(x, weights, biases):

    # Prepare data shape to match `bidirectional_rnn` function requirements
    # Current data input shape: (batch_size, n_steps, n_input)
    # Required shape: 'n_steps' tensors list of shape (batch_size, n_input)
    
    # Permuting batch_size and n_steps
    x = tf.transpose(x, [1, 0, 2])
    # Reshape to (n_steps*batch_size, n_input)
    x = tf.reshape(x, [-1, n_input])
    # Split to get a list of 'n_steps' tensors of shape (batch_size, n_input)
    x = tf.split(x, n_steps, 0)

    # Define lstm cells with tensorflow
    # Forward direction cell
    lstm_fw_cell = rnn.BasicLSTMCell(n_hidden, forget_bias=1.0)
    # Backward direction cell
    lstm_bw_cell = rnn.BasicLSTMCell(n_hidden, forget_bias=1.0)

    # Get lstm cell output
    try:
        outputs, _, _ = rnn.static_bidirectional_rnn(lstm_fw_cell, lstm_bw_cell, x,
                                              dtype=tf.float32)
    except Exception: # Old TensorFlow version only returns outputs not states
        outputs = rnn.static_bidirectional_rnn(lstm_fw_cell, lstm_bw_cell, x,
                                        dtype=tf.float32)

    # Linear activation, using rnn inner loop last output
    return tf.matmul(outputs[-1], weights['out']) + biases['out']

pred = BiRNN(x, weights, biases)

# Define loss and optimizer
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=pred, labels=y))
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)

# Evaluate model
correct_pred = tf.equal(tf.argmax(pred,1), tf.argmax(y,1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))

# Initializing the variables
init = tf.global_variables_initializer()

# Launch the graph
with tf.Session() as sess:
    sess.run(init)
    step = 1
    # Keep training until reach max iterations
    while step * batch_size < training_iters:
        
        np.random.shuffle(data)
        
        batch_x=data[0:batch_size,0:n_steps]
        #normalize
        batch_x=batch_x-np.min(batch_x,axis=1).reshape(batch_size,1)
        batch_x=batch_x/np.max(batch_x,axis=1).reshape(batch_size,1)

        batch_x = batch_x.reshape((batch_size, n_steps, n_input))
        batch_y=data[0:batch_size,n_steps:n_steps+n_classes]
        batch_y=batch_y.reshape((batch_size,n_classes))

        # Run optimization op (backprop)
        sess.run(optimizer, feed_dict={x: batch_x, y: batch_y})
        if step % display_step == 0:
            # Calculate batch accuracy
            acc = sess.run(accuracy, feed_dict={x: batch_x, y: batch_y})
            # Calculate batch loss
            loss = sess.run(cost, feed_dict={x: batch_x, y: batch_y})
            #print ("Iter"+str(step*batch_size)+", Training Accuracy="+str(acc))
            print ("Iter " + str(step*batch_size) + ", Minibatch Loss= " + \
                 "{:.6f}".format(loss) + ", Training Accuracy= " + \
                  "{:.5f}".format(acc))

        step += 1
    print ("Optimization Finished!")

結果

Iter 90000, Minibatch Loss= 0.746534, Training Accuracy= 0.50000
Iter 91000, Minibatch Loss= 0.750871, Training Accuracy= 0.47000
Iter 92000, Minibatch Loss= 0.738956, Training Accuracy= 0.54000
Iter 93000, Minibatch Loss= 0.803958, Training Accuracy= 0.55000
Iter 94000, Minibatch Loss= 0.784448, Training Accuracy= 0.58000
Iter 95000, Minibatch Loss= 0.764126, Training Accuracy= 0.49000
Iter 96000, Minibatch Loss= 0.750926, Training Accuracy= 0.54000
Iter 97000, Minibatch Loss= 0.836504, Training Accuracy= 0.47000
Iter 98000, Minibatch Loss= 0.828720, Training Accuracy= 0.51000
Iter 99000, Minibatch Loss= 1.095886, Training Accuracy= 0.54000
Optimization Finished!

10万回回した結果、学習データに対してすら50数%程度で、ランダムと対して変わらない結果になってしまいました。 モデルが単純すぎるのか、入力値が悪いのか、そもそも予測ができないものなのか分かりませんが、もう少し工夫してみたいです。

WindowsにTensorFlowをインストール

普段、TensorFlowはUbuntuが入ったノートパソコンで動かしていますが、 画像処理を行おうとすると、流石にスペック不足の為、 Windows10のデスクトップPCにインストールすることにしました。

インストール方法

基本的に公式サイトを見れば良いですが、 案内通りにAnacondaをインストールして下記を実行すると、エラーが発生しました。

pip install --upgrade https://storage.googleapis.com/tensorflow/windows/cpu/tensorflow-0.12.1-cp35-cp35m-win_amd64.whl
tensorflow-0.12.1-cp35-cp35m-win_amd64.whl is not a supported wheel on this platform.

AnacondaでインストールされたのがPython3.6で、公式サイトでサポートしていると謳っているのが、3.5なので、 3.6をアンインストール後、3.5をインストールして、上記コマンドを実行すると、無事インストールされました。

ちゃんとインストールされているかどうかは、公式サイトにある通り、 pythonを起動して、tensorflowをインポートできるかどうかで確認できます。

TensorFlowのTutorialを改造して画像識別

以前少しだけTensorFlowの記事を書きましたが、 久しぶりにTensorFlowを触ってみたので、成果物のご紹介。

やりたいこと

アイドルマスターシンデレラガールズのキャラクターを識別する。

やったこと

  • フリーソフトを使って画像を自動収集。
  • ここのプログラムの応用で、顔画像を切り出して、手動でタグ付け。(ファイル名を"タグ,(連番).jpg"に)
  • チュートリアルのプログラムを元に、学習プログラムを作成して、顔画像を学習。
  • 学習したパラーメタを使って検証。

学習プログラム

学習した顔画像は、64*64のリサイズにして保存しています。 また、ファイル名のカンマ以前の数字がキャラクターを識別するタグとなります。 今回は2500枚程度用意しました。

顔画像の例↓

f:id:oki-lab:20170205200131j:plain f:id:oki-lab:20170205200202j:plain

import cv2
import sys
import os.path
import glob
import numpy as np
import tensorflow as tf

image_w=64
image_h=64
dim_in=image_w*image_h
dim_out=18
limit=3000
batch_size=100

paths=glob.glob("images/*")
image_num=len(paths)

train_x=np.zeros((image_num,dim_in))
train_y=np.zeros((image_num,dim_out))

#loading images
cnt=0
for path in paths:
    image = cv2.imread(path,0)/255.0
    tag=int(os.path.basename(path).split(",")[0])
    train_x[cnt,:]=[flatten for inner in image for flatten in inner] #flatten matrix
    train_y[cnt,tag]=1
    print (tag)
    cnt+=1

#neural network
x = tf.placeholder(tf.float32, [None, dim_in]) #place holder
W = tf.Variable(tf.zeros([dim_in, dim_out])) #weight
b = tf.Variable(tf.zeros([dim_out])) #bias
y = tf.nn.softmax(tf.matmul(x, W) + b) #normalize
y_ = tf.placeholder(tf.float32, [None, dim_out]) #placeholder

#cross entropy
cross_entropy = -tf.reduce_sum(y_ * tf.log(y))

#minimize cross_entropy using the gradient descent algorithm
train_step = tf.train.GradientDescentOptimizer(0.0005).minimize(cross_entropy)

#initialize all variables
init = tf.initialize_all_variables()

#correct boolean list
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
#cast to float point numbers
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
saver=tf.train.Saver()

sess = tf.Session()
sess.run(init)

#training step
train_count=0
for i in range(limit):
    rnd=np.random.randint(image_num-batch_size)
    sess.run(train_step,feed_dict={x:train_x[rnd:rnd+batch_size,:],y_:train_y[rnd:rnd+batch_size,:]})
    train_count+=1
    print train_count,sess.run(accuracy,feed_dict={x:train_x[rnd:rnd+batch_size,:],y_:train_y[rnd:rnd+batch_size,:]})
    
print sess.run(accuracy,feed_dict={x:train_x,y_:train_y})

#save
saver.save(sess,"model.ckpt")

概要説明:
“images"フォルダに保存された顔画像を読み込み、画素情報を一次元化し、入力用テンソルに保存。
ウェイトやバイアス、損失関数や正答率用の関数を定義。
バッチサイズ分のデータを切り出して、学習。それを規定ステップ分繰り返し。
最後にモデルを保存。

評価用プログラム

import cv2
import os.path
import glob
import numpy as np
import tensorflow as tf

image_w=64
image_h=64
dim_in=image_w*image_h
dim_out=18

paths=glob.glob("images/*")
image_num=len(paths)

train_x=np.zeros((image_num,dim_in))
train_y=np.zeros((image_num,dim_out))

#loading images
cnt=0
for path in paths:
    image = cv2.imread(path,0)/255.0
    tag=int(os.path.basename(path).split(",")[0])
    train_x[cnt,:]=[flatten for inner in image for flatten in inner] #flatten matrix
    train_y[cnt,tag]=1
    print (tag)
    cnt+=1

#neural network
x = tf.placeholder(tf.float32, [None, dim_in]) #place holder
W = tf.Variable(tf.zeros([dim_in, dim_out])) #weight
b = tf.Variable(tf.zeros([dim_out])) #bias
y = tf.nn.softmax(tf.matmul(x, W) + b) #normalize
y_ = tf.placeholder(tf.float32, [None, dim_out]) #placeholder

#correct boolean list
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
#cast to float point numbers
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
    
saver=tf.train.Saver()
sess=tf.Session()
saver.restore(sess,"model.ckpt")

print sess.run(accuracy,feed_dict={x:train_x,y_:train_y})

概要説明:
画像の読み込みや変数、関数の定義は同じ。
モデルを読み込み、これを使って識別した時の正答率を表示。

所感

今回は画像があまり集められなかったことと、振り分けが面倒だったことが理由で、
画像の量が少ないですが、学習用データに対する正答率は94%程度でした。
上記のプログラムはディープラーニングではなく、非常に単純なニューラルネットワークなので、
気が向いたらディープラーニング化してみたいと思います。

Unityの起動失敗と対策

初めてUnity Bug Reporterを使ってみた、というお話。

先日、デスクトップPCを買い替えたため、色々と開発環境を整えているところですが、
Unityをインストールしたところ、起動直後にクラッシュする現象が発生しました。

とりあえず調べてみて、下記の事を試してみました。

・再インストールする。
・セキュリティソフトを終了させる。
・起動オプションに「 -force-d3d11」を追加する。
・管理者として実行する。
・互換モードで実行する。
・起動時にAltキーを押す。

全部やっても解決せず、万策尽きた感じになったため、
Unity Bug Reporterにて、レポート送信してみました。

ログは勝手に送信可能な状態になってるので、メールアドレスとタイトルを
入れてSendボタンを押すだけです。

回答が来るまで時間がかかるかと思いましたが、約15時間で返ってきました。

回答要約すると、
Lavasoft Web Companionというソフトがインストールされてるので、
これをアップデートしなさい。
という内容でした。

Lavasoft Web Companionなどというソフトをインストールした覚えが無かったため、
アンインストールしたところ、無事Unityが起動するようになりました。

あまり期待していなかったのですが、非常に早く解決できたため、
Unityに関して何か問題があった場合は、Bug Reporterを活用すると
幸せになれるかもしれません。