プログラミングの芽

面白そうな技術を使って、楽しいことやりたい

SG90のざっくり寸法メモ(Fusion360)

SG90を使って何か作る場合、ざっくりでも寸法がわからないと不便なのでメモがてら
値に関しては実測値ですが、ディジタルノギスの電池が切れてた関係でスケールで測ってます。従って、”目安値”ということでお願いします。
f:id:atarms:20190213202323p:plain
f:id:atarms:20190213203906p:plain
Fusion360の2D書き起こし機能は、私自身の練度が低いのもあってあんまり好きくないですね。
jwcadで書いたことは何回かあるのでそっちでやろうとしたんですけど、まぁメモなので・・・
図面に足りない値があったら教えて頂けたら幸いです。

ArduinoとPython間のシリアル通信によるDHT22を使った温度湿度リアルタイム表示

良いタイトルが思い浮かびませんね。
正直Matplotlibのグラフ表示練習みたいな感じでした。

準備

必要なもの

Arduino Uno
10kΩ抵抗
DHT22(AM2302)
ブレッドボード(必要ならユニバーサル基盤等)
※ジャンパワイヤ等は省略
記事内で使ってるやつ


回路(メモ程度)
f:id:atarms:20190213154932j:plain

Arduinoの必要ライブラリ

GitHub - adafruit/DHT-sensor-library: Arduino library for DHT11, DHT22, etc Temperature & Humidity Sensors
GitHub - adafruit/Adafruit_Sensor: Common sensor library
上記2つをArduinoのライブラリフォルダに入れてください。

以上で準備は終わりです。

ソースコード

Arduino

#include <DHT.h>

#define DHTTYPE DHT22
#define DHT22_PIN 7
DHT dht(DHT22_PIN, DHTTYPE);

void setup() {
  pinMode(DHT22_PIN, INPUT);      
  Serial.begin(9600);
}

char ch[4];
char ct[4];

void loop()
{
  float h  = dht.readHumidity() ;
  float t  = 5.0/9.0*(dht.readTemperature(true)-32.0); // fahrenheit -> celsius
  dtostrf(h, 3, 1, ch); //数列tを文字列(全3文字の小数点以下1文字)に変換してchに代入
  dtostrf(t, 3, 1, ct);
  if (isnan(h) || isnan(t)){
    return;
  }
  Serial.println(t);
  Serial.println(h);
  delay(1000);
}

Python

import numpy as np
import matplotlib.pyplot as plt
import serial

def main():
    ser = serial.Serial("COM4")  # COMポート(Arduino接続)
    temps = [0]*300
    humidities = [0]*300
    t = np.arange(0,300,1)
    h = np.arange(0,300,1)
    plt.ion()

    while True:
        temp = float(ser.readline().rstrip().decode(encoding='utf-8'))
        humidity = float(ser.readline().rstrip().decode(encoding='utf-8')) 
        # 温度データのリスト更新
        temps.pop(299) #299番目の要素を削除
        humidities.pop(299)
        temps.insert(0,float(temp)) #0番目にfloat型で要素を挿入
        humidities.insert(0,float(humidity))
        
        fig, ax1 = plt.subplots()
        ax1.plot(t, temps, "r-", label="Temperature[C]")
        ax2 = ax1.twinx()
        ax2.plot(h, humidities, "b-", label="Humidity[%]")
        
        plt.title("AM2302-M.Value")
        ax1.set_xlabel("Time [s]")
        ax1.set_ylabel("Temperature [Celsius]")
        ax2.set_ylabel("Humidity [Percent]")
        
        h1, l1 = ax1.get_legend_handles_labels()
        h2, l2 = ax2.get_legend_handles_labels()
        ax1.legend(h1+h2, l1+l2, loc='upper right')
        
        plt.grid()
        plt.xlim([1, 300]) #5分
        ax1.set_ylim([0, 40])
        ax2.set_ylim([0, 100])
        
        plt.pause(.01)

if __name__ == '__main__':
    main()

実行結果(GIF)

https://i.gyazo.com/5e38f08ec81fd76ba94f116d24e4cacc.gif
1秒間隔で更新されます。
盛り上がってるところは口でハーってやりました。湿度も温度も上がっているので正常に動いてそうですね。
それにしても湿度が低い・・・。
Pythonでデータの読み書きができれば後は煮るなり焼くなりって感じです。

次やりたい事

サーボモータ(具体的にはSG90)を2つ使って、物体を自動追尾するWebカメラArduinoで作りたいなと考えています。
最初はRaspberryPiでやろうと考えていたのですが、処理速度とSSH接続等の手間を考えて辞めました。
今回やったシリアル通信で、サーボモータの制御だけをArduinoにやらせようかなと。

Pythonで位相画像の生成

ロボットビジョンについての論文を読んでたら位相限定相関法というのがあり、何だろうと調べました。
画像と比較したい画像のズレを位相画像を使って得る方法らしいです。
位相画像とは何ぞやって感じです。
参考:位相画像 – Rest Term

ソース

といっても別にフーリエ変換のコードを書くとかはしないので短いですが。

import numpy as np
import cv2

fimg = cv2.imread("img.jpg",0)

#2次元高速フーリエ変換
Fimg = np.fft.fft2(fimg)
#正規化 Fimgの絶対値は振幅スペクトル
Nimg = Fimg / np.abs(Fimg)
#2次元高速フーリエ逆変換
Pimg = np.fft.ifft2(Nimg).real

#保存
cv2.imwrite("phase_img.jpg",Pimg)


ズレを知りたい画像の位相画像2枚が手に入れば、あとはその2枚の相関を取ってIDFTしてピークを探せばいいだけみたいです。
そのピークのズレを元にロボットアームの移動距離を逆運動学で計算すればオフラインティーチングのズレを補正できるという事ですかね?

ウェブカメラ映像内の色をリアルタイムでヒストグラム表示

メモ

# OpenCV のインポート
import cv2
import numpy as np
import matplotlib.pyplot as plt
from collections import Counter

# VideoCaptureのインスタンスを作成する。
# 引数でカメラ選択
cap = cv2.VideoCapture(0)

while True:
    # VideoCaptureから1フレーム読み込む
    ret, frame = cap.read()
    #HSVに変換
    f_hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
    
    #画像のサイズと検出した色を格納する配列を用意
    height = f_hsv.shape[0]
    width = f_hsv.shape[1]
    pixels = []
    
    #各ピクセルで閾値を満たしたらpixels[]に格納する
    for y in range(height):
        for x in range(width):
            if (f_hsv[y, x, 1] > 45 and 32 < f_hsv[y, x, 2]):
                pixels.append(f_hsv[y, x, 0])
    
    #12分割して色を判断(ヒストグラムの出力)
    plt.xlim(0,180) # x軸の範囲
    plt.xticks(np.arange(0, 180 + 1, 15)) # x軸の目盛りの設定
    plt.hist(pixels, bins=12, range=(0,180)) # ヒストグラムの出力 
    plt.pause(.001)
    
    #最頻値を求めてその画像の色を判断
    # 軸の作成 (0から180を13等分[12個の区間を出したいため]) 
    bins = np.linspace(0, 180, 13)  
    # pixelsをそれぞれの要素を12分割した色範囲に格納  
    index = np.digitize(pixels,bins) 
    # 最頻値
    c = Counter(index)
    print(c)
    mode = c.most_common(1)
    # 最頻値の出力
    print(mode[0][0])
    
    #カメラ映像の出力
    cv2.imshow('Raw Frame', frame)

    # キー入力を1ms待って、k が27(ESC)だったらBreakする
    k = cv2.waitKey(1)
    if k == 27:
        break

# キャプチャをリリースして、ウィンドウをすべて閉じる
cap.release()
cv2.destroyAllWindows()


実行結果(GIF)
https://i.gyazo.com/82895dd2da06638a5be0d1fc7f5a9f7c.gif

Azure Machine Learningでタイタニック生存予測

またタイタニックです。とりあえずの勉強にはすごく使いやすいです。

MicrosoftのAzure Machine Learning(以下AzureML)はずっと触りたいと思っていたのですが、今日時間が取れてやっと触れました。
軽くチュートリアル的なのをやった感じ、かなり直観的に機械学習を行えそうだなと感じました。
ということで、タイタニックのデータセットを使って生存予測をAzureMLでやっていきたいと思います。

パソコンにあるデータセットをAzureMLで使えるようにする。

1.左のメニューからDATASETを選択
2.左下の+NEWを押す
3.FROM LOCAL FILEを押して、データセットをアップロードする
4.プロジェクト内でMy Datasetsの中に、アップロードしたファイルがあるので置く
f:id:atarms:20190202220931p:plain
右クリックでデータを見れる
f:id:atarms:20190202221413p:plain

ここからは以下の記事でやった手順で進めていく。
k最近傍法でTitanic生存者予測 - 森と秋刀魚と備忘録

学習に使えそうなデータだけ抽出する

Select Columns in Datasetを使う。
f:id:atarms:20190202221733p:plain
Select Columns in Datasetをアクティブにして、プロパティーのLaunch column selectorを選択する。
f:id:atarms:20190202222103p:plain
抽出したいのを右欄に移動させて、右下のチェックマークで反映。
画面下のRUNで動かす。
Select Columns in DatasetをVisualizeする。
f:id:atarms:20190202223356p:plain
できた。

欠損値を中央値で埋める

Missing Values Scrubberを使う。
f:id:atarms:20190202222950p:plain
プロパティのFor missing valuesはReplace with medianを選択
f:id:atarms:20190202223140p:plain
RUNで動かす。
f:id:atarms:20190202223318p:plain
できた。

文字列を数字に置き換える。

Convert to Datasetを使う。
f:id:atarms:20190202230702p:plain
1つ目のパラメータはこう
f:id:atarms:20190202230737p:plain
2つ目のConver to Datasetはfemaleを1に置き換えてる。

f:id:atarms:20190202230928p:plain
できた。

本当は1つのモジュールで済ませたいんですが、カンマや””で区切ってもうまくいかなかった。
恐らく方法はあるのでしょうが、今回は流します。

訓練用とテスト用で分ける

上の記事ではやらなかったけれど、最後に言及はしたのでやってみる。
Split Dataを使う。
f:id:atarms:20190202232245p:plain
プロパティのFraction of rows in the firs...が割合
訓練:テスト=8:2でやるので、0.8を入力

訓練する

k近傍法を使おうと思ったけど、k平均法しかなかった。
本当か?って感じ。もしかしたらあるかもしれない。無ければPythonやRコードが書けるのでそれでやればいい。
今回はコードを書かないと心に決めてるので、Two-Class Boosted Decision Tree Regressionを使う。決定木。
Train Modelのプロパティは、予測したいものを選択するのでSurvivedを選択する。
f:id:atarms:20190202235607p:plain
RANで動かす。
f:id:atarms:20190202235728p:plain
こんな感じで訓練してるらしい。今回100回
できた。

学習したモデルをテストデータで評価する

Score Modelでテストデータを予測。
Evaluate Modelで評価。
f:id:atarms:20190202235923p:plain
RANで動かす。

テストデータの予測結果。
f:id:atarms:20190203000023p:plain
Scored Labelsが予測、Scored Probabilitiesは1に属する確率。
見る限りは0.5が閾値っぽい。当たり前ですね。

評価結果
f:id:atarms:20190203000501p:plain
ROC曲線やらが見れる。
Accuracyが0.775だった。まぁそんなもんでしょって感じです。

Kaggleに提出した

せっかくだし用意されたテストデータも予測して提出してみた。
f:id:atarms:20190203001917p:plain
順位が上がった。

以上です。

k最近傍法でTitanic生存者予測

機械学習の勉強ちゃんとしなきゃなって想いでやりました。
タイトル通り、k最近傍法でTitanic生存者予測コンペをやります。普通だと決定木とか使うみたいですね。

参考


順順にやっていきます。

とりあえずtrain.csvとtest.csvを読み込む

import pandas as pd

train_df = pd.read_csv("train.csv")
test_df  = pd.read_csv("test.csv")


訓練データと訓練ラベルに分ける

#Survived、Sex、Ageを取り出す。
#male = 0、female = 1とする。
#Ageの欠損値は中央値で埋める。
train_df = train_df[["Survived", "Sex", "Age"]].replace("male", 0).replace("female", 1).fillna(train_df["Age"].median())

X_train = train_df[["Sex", "Age"]] #訓練データ
y_train = train_df["Survived"] #訓練ラベル


訓練をする。

from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=5) #n_neighbors : 近傍点の数

knn.fit(X_train, y_train) #訓練

>>KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
           metric_params=None, n_jobs=1, n_neighbors=5, p=2,
           weights='uniform')


テストデータを予測する。

X_test = test_df[["Sex", "Age"]].replace("male", 0).replace("female", 1).fillna(test_df["Age"].median())

y_pred = knn.predict(X_test) #予測

print("Test set predictions:\n {}".format(y_pred))
#print("Test set score: {:.2f}".format(knn.score(X_test, y_test))) #y_test(テストデータの正解ラベル)があれば正解率もわかる。

>>Test set predictions:
 [0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 1 0 0 1 0 0 0 1 0 1 0 1 0 1 1 1 0 0 1 0 0 1
 0 0 1 0 1 0 1 1 0 0 1 0 1 1 0 1 1 0 0 0 0 1 1 0 0 0 1 1 0 0 0 0 0 1 0 0 0
 1 0 1 1 0 1 0 0 1 1 0 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 1 0 1 0 1 0 0 1 1 0 0
 1 1 0 0 0 1 1 1 1 1 1 1 0 1 0 0 1 0 0 0 0 1 1 0 0 0 0 1 0 0 1 0 0 1 0 1 0
 1 0 1 1 0 1 1 0 1 1 1 1 1 0 1 1 0 1 1 0 1 1 1 1 0 1 0 1 1 0 1 0 0 0 1 1 1
 0 0 0 1 0 0 1 0 0 1 0 1 0 0 1 1 1 0 1 0 1 0 0 1 0 0 1 0 0 0 1 1 0 1 1 1 0
 1 0 1 1 0 1 0 0 0 1 0 1 0 0 0 0 1 1 1 0 0 1 1 1 1 0 1 1 1 0 1 0 0 1 1 0 1
 0 0 0 1 1 0 1 1 1 1 0 0 1 1 1 1 1 0 0 0 0 1 1 1 0 0 0 1 1 1 1 1 0 1 0 0 0
 1 1 0 0 0 0 0 0 1 0 0 1 0 0 0 0 1 1 1 0 0 0 1 0 0 0 0 1 1 0 1 0 0 0 1 0 1
 1 1 0 0 0 0 1 0 0 1 1 1 1 0 0 0 1 1 0 0 0 1 0 1 1 1 0 0 1 1 1 1 1 1 1 1 0
 0 1 1 0 1 1 1 0 0 1 1 0 1 1 0 1 0 0 0 0 0 1 1 0 0 1 0 1 0 0 1 0 1 1 1 0 0
 0 1 0 1 1 1 1 1 0 1 1]

訓練データをさらに訓練用とテスト用に分けると、未知データに対する評価ができると思います。
ここではやりませんが。

提出用のcsvに書き出す。

import csv

submit_file = open("submit.csv", "w", newline="")
file_object = csv.writer(submit_file)
file_object.writerow(["PassengerId", "Survived"])
ids = test_df["PassengerId"].values
file_object.writerows(zip(ids, y_pred))
submit_file.close()


結果
f:id:atarms:20190131134258p:plain
0.73205でした。
訓練データにPclassも入れてみたら、画像の通り0.60765でした。

どうでもいいですけど、私は最初機械学習ライブラリの良さがよくわかりませんでした。
一行で訓練できるとはよく言いますけど、実際訓練させようとしたら上のような感じで1行じゃないじゃん。って思ってました。
最近になってようやく、一行で訓練できるって言葉に納得できるようになりました。

以上

物体検出を学習させる際の画像水増し手順まとめ

今まで書いた記事のまとめです。
一連の流れで水増しできます。

1.画像をいっぱいあつめる
2.LabelImageでラベリングする
3.
atarms.hatenablog.com
4.
atarms.hatenablog.com
5.
atarms.hatenablog.com
6.
atarms.hatenablog.com