スタートアップエンジニアの作ってみた日記

ものづくりが下手な横好きなエンジニアによる作ってみた的なブログです。

Insta360oneXと自作したドリフトダーツでドリフトショットを撮ってみた。

ドリフトショットに憧れてinsta360 one X を購入したのに、ドリフトダーツが全く入手できないためどうしたものかと考えていました。

*ちなみにドリフトショットとはこれです。

youtu.be

 

カメラにドリフトダーツというパーツを付けて動画を撮影すると映画のような動画が取れるというものです。

このドリフトダーツが全く手に入らない状態が長らく続きました。

 

たまーにECサイトなどに載ったりはしてるのですが、注文しても届かない。

なので、これは自作するしかないということで、3Dプリンタを使って自作しました。

TPUフィラメントという柔らかい材料を使い造形しました。

 

そのことに関してはこちらに載っています。興味のある方はどうぞ。

goengine.hatenablog.com

 

 実際にできたものはこちらです。

それなりに本物に似せて作ったので遠くから見ればそれっぽい形になりました。

 

実際に天気の良い晴れた日に公園で撮影してみました。

撮影したものがこちらです。360度動画になってますので、ぐりぐりと触ると色々な視点が見れます。

 

 

これはこれでいい動画なのですが、見る人に視線方向が委ねられてしまい、通常の360動画とそこまで変わらないイメージですね。

 

そして、視線方向を見せたいものに合わせて通常の動画に編集したものがこれです。

 

ドリフトショットの醍醐味はこの編集をしてこそだと私は考えています。

今回撮影したものはあまり動きがない物ですが、公式があげてる動画みたいに動きがあるものに対して投げて撮影すれば非常に面白い動画が撮れそうだと思っています。

 

今度、機会があったら動きのあるものの撮影もトライしてみようと思います。

3Dプリンタ(Anycubic mega zero)でTPUフィラメントを使って造形した。

Anycubic mega zeroでTPUフィラメントを使って造形してみました。

 

TPUフィラメントとはよく使われるPLAやABSと違ってゴムのように柔らかい材料で、そのため、造形に何度も失敗してしまったので、そのあたりについて書ければなと思います。

ちなみに私が購入したのはこちらになります。Amazonで2880円で購入しました。

www.amazon.co.jp

 

 ■エクストルーダーのつまり問題

始め何も考えずにPLAと同じ条件で造形してみたところ、フィラメントを送る部分のエクストルーダーのところで詰まってしまい、何回も失敗しました。

 

フィラメントが詰まった原因を調べてみると、エクストルーダーでフィラメントを送り出した後にねじの部分に隙間があり、TPUフィラメントは柔らかいために、エクストルーダーで押されるとうまくまっすぐ力が伝わらずに曲がって、その隙間に入りこんでしまい、詰まるというのが原因のようです。 

f:id:goengine:20200830153712j:plain

 

このチューブ用のネジを使うとどうしても隙間ができてしまうようで、何度やっても中で詰まってしまいました。

 

なので、私はチューブ用のネジを外し、直接エクストルーダーのプラスチックのケースにチューブを付け、接着剤で止めてしまいました。

f:id:goengine:20200829163629j:plain

そうすると、エクストルーダーのプラスチックケースとチューブの間に隙間がなくなるので、柔らかいTPUフィラメントで入り込む場所がなくなり、詰まることがなくなりました。

 

■スライサーソフトの設定

私はUltimaker Cura v4.6.1を使っていますが、ソフト上でMaterialを選べます。

まず初めてトライするときに、以下のようにMaterialをTPUに選択してinfill80%でgcodeを生成し造形してみました。

f:id:goengine:20200830154447p:plain

 

造形結果はこんな感じ。

●条件1

Material : TPU

infill 80%

スカスカで柔らかくてすぐ壊れそうです。また、淵の方が造形があまりうまくいってないのか、少しけば立っている感じです。

さすがにこれはダメだなと思い条件を変えてもう一度造形してみた。

f:id:goengine:20200830161430j:plain

 

●条件2

MaterialをTPUにしたままでinfillを上げただけではうまく行きそうになかったので、MaterialをPLAに戻して以下の条件で造形してみました。

Material : PLA

infill 80%

条件1に比べると大分しっかりしていて、それでいて柔らかさもあります。

ただ、個人的にはもう少し柔らかくてもよいかなという感じです。

作るもの次第ではこの条件でも問題なさそうです。

 

f:id:goengine:20200830161205j:plain

●条件3

Material : PLA

infill 50%

見た目には条件2とほとんど変わりませんが、条件2より少し柔らかくなりました。

しっかりしているし、それなりに弾力があります。

f:id:goengine:20200830161152j:plain

 

MaterialをPLAにして、infillの値を振ってみると硬さ、弾力をコントロールできて用途に合わせて硬さのモノを造形できるかと思います。

3Dプリンタ(anycubic mega zero)の造形の調子がファンの詰まりのせいで悪くなっていた。

タイトルの通り、ファンにモノが詰まって造形の調子が悪くなったよという話しです。

積層タイプの3Dプリンタは冷却が大事で、いろいろな方が自作でファンを追加したりしているかと思いますが、冷却はやっぱり大事なんだなと再度認識しました。

 

ーー

先日3Dプリンタを買い替えてanycubic mega zeroを使っていた。

 

1か月ほどは全く問題なく使えていたが、あるときからうまく造形できなくなってしまった。

 

症状としては造形し始めは問題なく造形できるのだが、造形している途中からフィラメントがうまくノズルから出てこなくなってしまう、造形物がスカスカになるというもの。この写真のように。

 

f:id:goengine:20200810205048j:plain

ノズルつまってるのかなーと思い、フィラメントを戻してノズルを針で通してもう一回やり直しても再度発生する。

どうしたものかと思い、引き戻したフィラメントを見てみると、ノズルの先端より手前のところでだまになってたまっていそうだということが分かった。

f:id:goengine:20200810204536p:plain

 

何でこうなるんだろうと思い、再度、トライすると手前のファンが全く回っていないことに気付いた。

f:id:goengine:20200810204713p:plain

この手前のファンはノズルの先端ではなくノズルの金属部品ホースとの付け根の方を冷やす役割がある。このファンが止まっているとその部分を冷やすことができなくなり、本来フィラメントが溶けてほしくないその場所で溶けてしまい、フィラメントが詰まっていたのだろうと推察される。

 

というわけで、何で動いてないんだと、ファンをよく見てみるとフィラメントのごみのようなものがファンに絡んでおり、それを取り除くとファンが回り始めた。

そして造形をすると、きちんと造形できるようになりました。

 

すごい間抜けで単純なことであったが、冷却ファンが重要だということを再度認識したので記事にしてみました。

 

皆さんも冷却やファン、ゴミつまりには気を付けてください。

 

CO2センサを作ってみた(CCS811搭載 空気品質センサモジュールを使ってみた)

最近、在宅勤務が増えてきて家で一人作業することが多くなりました。

家で作業をしているとなかなか集中できなかったり眠くなったりしちゃいますよね。

 

これは自分の集中力のせいではなく、部屋の二酸化炭素の濃度のせいなのでは思い、CO2センサーを作って設置してみました。

 

使用したのは以下の3つです。

■CCS811搭載 空気品質センサモジュール

https://www.switch-science.com/catalog/3298/

Arduino Uno

LCD液晶Display

https://www.amazon.co.jp/gp/product/B07BJ5PW3R/ref=ppx_yo_dt_b_asin_title_o03_s00?ie=UTF8&psc=1

 

1.配線

センサモジュールとArduinoはI2C通信と言われる通信を行います。

以下のように二つを接続してください。

モジュール  Arduino

GND ー GND

VCC ー 3.3V

SDA ー Analog 4

SCL ー Analog 5

 

f:id:goengine:20200720233803p:plain

 

 ArduinoLCDディスプレイの接続に関してはこちらの記事をご参照ください。

https://goengine.hatenablog.com/entry/2019/03/17/211934

 

2.Arduinoの準備

次にソフトウェアの準備です。

スイッチサイエンスの販売サイトよりライブラリをダウンロードしましょう。

f:id:goengine:20200720234701p:plainSparkFun_CCS811_Arduino_Library-master\SparkFun_CCS811_Arduino_Library-master\examples\Example1_BasicReadings.ino
を開きます。

そのまま書き込むと、" SparkFunCCS811.h"がありませんと怒られてしまうので、このファイルがincludeされるようにします。

以下に示すリンクをクリックします。

f:id:goengine:20200721000233p:plain

 

するとライブラリマネージャーが出てくるのでインストールを選びます。

f:id:goengine:20200721000443p:plain

 

これで準備ができたので早速さきほどのファイルを書き込んでみましょう。

問題がなく書き込めれば、これで計測がきちんと行えているかと思います。

シリアルモニタを見るとCO2の計測値が出てくるかと思います。

f:id:goengine:20200720235840p:plain

 

これでサンプルを動かし、計測はすることはできるのですが、パソコンがないと値が見れず不便なので私はサンプルコードを少しいじりLCDディスプレイに表示してみました。

 

こちらがそのソースコードになります。参考にしてください。

/******************************************************************************
  Read basic CO2 and TVOCs
  Marshall Taylor @ SparkFun Electronics
  Nathan Seidle @ SparkFun Electronics
  April 4, 2017
  https://github.com/sparkfun/CCS811_Air_Quality_Breakout
  https://github.com/sparkfun/SparkFun_CCS811_Arduino_Library
  Read the TVOC and CO2 values from the SparkFun CSS811 breakout board
  A new sensor requires at 48-burn in. Once burned in a sensor requires
  20 minutes of run in before readings are considered good.
  Hardware Connections (Breakoutboard to Arduino):
  3.3V to 3.3V pin
  GND to GND pin
  SDA to A4
  SCL to A5
******************************************************************************/
#include <Wire.h>

#include "SparkFunCCS811.h" //Click here to get the library: http://librarymanager/All#SparkFun_CCS811

#include <LiquidCrystal_I2C.h>

int count = 0;

LiquidCrystal_I2C lcd(0x27,16,2);

int list_num =3;
int co2_list[3] = {0,0,0};


#define CCS811_ADDR 0x5B //Default I2C Address
//#define CCS811_ADDR 0x5A //Alternate I2C Address

CCS811 mySensor(CCS811_ADDR);

void display_setup()
{
  lcd.init();                      
  lcd.backlight();
  lcd.setCursor(0, 0);
}

void display_print(int co2_noudo)
{
   int _position = 5;
   lcd.setCursor(0, 1);
   lcd.print("CO2:");
   lcd.init();
   if(co2_noudo > 1000){
    _position = _position -1;   
   }
   lcd.setCursor(_position, 1);
   lcd.print(co2_noudo);
   
   lcd.setCursor(8, 1);
   lcd.print("[ppm]");
}


void setup()
{
  Serial.begin(115200);
  Serial.println("CCS811 Basic Example");

  Wire.begin(); //Inialize I2C Hardware
  display_setup();

  if (mySensor.begin() == false)
  {
    Serial.print("CCS811 error. Please check wiring. Freezing...");
    while (1);
  }
}

void loop()
{
  //Check to see if data is ready with .dataAvailable()
  if (mySensor.dataAvailable())
  {
    //If so, have the sensor read and calculate the results.
    //Get them later
    mySensor.readAlgorithmResults();
   
  }
  for(int i =list_num;i > 1;i--){
    co2_list[i-1] = co2_list[i-2];
  }
  co2_list[0] = mySensor.getCO2();
  int co2_ave;
  co2_ave = (co2_list[0] + co2_list[1] +co2_list[2])/3.0; 
  display_print(co2_ave);
  Serial.print(co2_list[0]);
  Serial.print(",");
  Serial.println(co2_ave);
  

  delay(10); //Don't spam the I2C bus
}

そしてできたものがこちらです。

 

ちなみに僕の場合CO2の値は関係なく普通に眠くなっているだけだということがわかりました。。笑

 

以下のサイトを参考にさせていただきました。

ありがとうございます。

https://www.switch-science.com/catalog/3298/

http://blog.akanumahiroaki.com/entry/2018/06/12/080000

 

 

 

 

 

Google Colaboratoryとtensorflowを使って簡単に機械学習で画像判定。

機械学習素人の私がtensorflowを触ってみたといった内容です。

以前のブログでgoogle 画像検索で画像スクレイピングしました。

https://goengine.hatenablog.com/entry/2019/08/22/000112

 

こちらの画像を使って学習させた学習モデルを使って犬か猫どうかを判定させるものを作りたいと思います。

 

事前にスクレイピングで犬の画像と猫の画像を落としてください。

そしてその画像のディレクトリを同じディレクトリに入れておいてください。

こんな感じ。(dataディレクトリ内にcat、dogディレクトリを入れてあります。)

f:id:goengine:20191006232527p:plain

 

これでデータの準備は整いました。

 

retrain.pyを使い学習させていきます。こちらのファイルを以下のgithubから落としましょう。

 https://github.com/tensorflow/hub/blob/master/examples/image_retraining/retrain.py 

こちらのpyファイルを好きなディレクトリに入れます。

 

そしてColaboratory内での以下のコマンドを実行します。

!python drive/"My Drive"/190805_test/retrain.py \
  --bottleneck_dir=bottlenecks \
  --how_many_training_steps=4000 \
  --model_dir=inception \
  --summaries_dir=training_summaries/basic \
  --output_graph=drive/"My Drive"/190805_test/retrained_graph.pb \
  --output_labels=drive/"My Drive"/190805_test/retrained_labels.txt \
  --image_dir=drive/"My Drive"/190805_test/data

それぞれのパスは自分の好きなように設定してください。

僕は自分のgoogle deiveと連携させているので"My Driveが"入ってしまっていますが、google driveと連携させなくても大丈夫です。

 

こちらは学習回数にもよりますが、10分ほど時間がかかります。

f:id:goengine:20191007002435p:plain

 

これがうまくいくと、実際に判定に必要なretrained_graph.pbファイルとretrained_labels.txtファイルができます。

 

次に判定させる処理をしていきます。

label_image.pyが必要になるので、githubから落としてきましょう。

https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/label_image/label_image.py

 

また、評価を試す画像を適当に用意します。ここでは、tes.jpgとして以下の犬の画像を用意しました。

f:id:goengine:20191007004133j:plain

 

準備ができたら以下のように入力して実行します。

!python drive/"My Drive"/190805_test/label_image.py \
--image drive/"My Drive"/190805_test/test.jpg \
--graph drive/"My Drive"/190805_test/retrained_graph.pb \
--labels drive/"My Drive"/190805_test/retrained_labels.txt \
--input_layer=Placeholder

環境によって、以下のようなこのようなエラーが出るかもしれません。

KeyError: "The name 'import/InceptionV3/Predictions/Reshape_1' refers to an Operation not in the graph."

そしたらlabel_image.pyファイル内の

input_layer = "input"

output_layer = "InceptionV3/Predictions/Reshape_1"

input_layer = "Mul"

output_layer = "final_result"

に変更してみましょう。

 

うまくいくと、このようにdogとcatどちらに近いかを0~1に間の値で返してくれます。

f:id:goengine:20191007003906p:plain

dog 0.9991762
cat 0.0008238142

今回は犬の画像を使ってテストしたので、いい結果ですね。

以上です。

 

以下のサイトを参考にさせていただきました。

ありがとうございます。

https://stackoverflow.com/questions/46325799/tensorflow-for-poets-the-name-import-input-refers-to-an-operation-not-in-the

https://qiita.com/umeee/items/ffde72ec84fa2065b1ff

https://qiita.com/quotto/items/645b01cf9c3919a52b12

 

 

Python を使ってArduino 2台を通信してみた

Arduino2台の通信を調べてみたら、Arduino2台を直接接続してI2C通信する記事はたくさんあるのですが、Arduino2台をそれぞれをPCにUSBで接続して通信する記事はあまり見つからなかったので、書きます。

簡単ですが、以下のような構成です。

f:id:goengine:20190826002459p:plain

今回は1台のarduinoジョイスティックを接続して、もう1台にサーボモータを接続します。

ジョイスティックの値をserial.writeで一度、PCに送り、pythonでそちらの値を受け取ります。

その受け取った値を、python上で別のarduinoにserial.writeすることで別のarduinoに値を送信します。

その値に応じてサーボモータを動かします。

 

pythonの準備

以下のコードのser.port = "COM9"の箇所を自分の環境にあった値にしてください。デバイスマネージャーやArduino IDEなどで確認できると思います。

値;

と連続的に送られてきたものを;区切りで受け取り値を取り出すようになっています。

今回は受け取った値をそのままもう一台のArduinoに送ってますが、何かしらの処理をPython上でやって送ることももちろん可能です。

import serial
import binascii

#シリアル通信(PC⇔Arduino)
ser = serial.Serial()
ser.port = "COM9"     #デバイスマネージャでArduinoのポート確認
ser.baudrate = 115200 #Arduinoと合わせる
ser.setDTR(False)     #DTRを常にLOWにしReset阻止
ser.open()            #COMポートを開
ser1 = serial.Serial()
ser1.port = "COM3"     #デバイスマネージャでArduinoのポート確認
ser1.baudrate = 115200 #Arduinoと合わせる
ser1.setDTR(False)     #DTRを常にLOWにしReset阻止
ser1.open()            #COMポートを開く
while True:
    try:
        character_array = []
        read_line = ''
        while True:
            abc = ser.read()
            ch = abc.decode("UTF-8")
            if ch == ';' :
                break
            else:
                character_array.append(ch)
        map_c = map(str, character_array)
        read_line = ''.join(map_c)
        split_fields = read_line.split(',')
        value = split_fields[0] 
        #以下で他のarduinoに値を送信
        ser1.write(value.encode("UTF-8"))
        ser1.write(b";")
    except Exception as e:
        msg = 'false'
        print(msg)
ser.close()

 

■値を送る側Arduinoの準備

今回はジョイスティックのx成分の値だけをPCに送信します。

値;

という形式で連続的に送信しています。

int x_pin = 0; 
//両端の端子は,GNDと+5Vに接続
int x_val = 0;           //読み取った値を格納する変数

void setup()
{
  Serial.begin(115200);              //シリアルの設定
}

void loop()
{
  x_val = analogRead(x_pin);     //入力ピンの読み取り
  Serial.print(x_val);             //値の表示
  Serial.print(";");  
}

 

■値を受け取る側のArduinoの準備

値;

と連続的に送られてきたものを;区切りで受け取り値を取り出すようになっています。

#include <Servo.h>
Servo myServo;

String str;
String value;
int value1 = 525;
int angle;

void setup() {
  Serial.begin(115200);
  myServo.attach(11);
}

void loop() {
  if (Serial.available() > 0)
  {
    str = Serial.readStringUntil(';');

    value = str.substring(0, sizeof(str) - 1);
    value1 = value.toInt();

    angle = value1 / 1024.0 * 180;
  }

  myServo.write(angle);
}

 以上で(今回はかなり説明が雑ですが、、)、動くようになったかと思います。

動いた様子はこんな感じです。

 以上で、pythonを使った2台のArduinoの通信でした。

google colaboratoryを使ってgoogle画像検索から画像を一括ダウンロード

タイトルの通りcolaboratoryを使ってgoogle画像検索から大量の画像を取得する方法を書きます。

一年前くらいにやっていたことを思い出しながら書くので、間違っていたり古い情報だったりしたらすみません。

 

そもそもgoogle colaboratoryとは
cloud上で実行できるJupyterノートブック環境です。
環境構築などのめんどくさい作業がほとんどいらず、ブラウザとgoogleアカウントさえあれば使用できます。

また、無料でGPUを使用できるので、機械学習などで大量のデータを学習させるときなどに非常に便利です。

というわけで、今回はこのgoogle colaboratoryを使っていきます。

 

まずは、colaboratoryを開きます。

ブラウザ上でgoogle driveを開き、新規ファイルの追加ボタンで、Google colaboratoryを選びます。

このとき、表示されない方は「+アプリの追加」から追加してください。

f:id:goengine:20190805010625p:plain

 

開くとこのような画面になります。

ここにコードを書いていきます。

f:id:goengine:20190805010913p:plain

 以下のコードコピペしましょう。

import os
from urllib import request as req
from urllib import error
from urllib import parse
import bs4

#検索するワード
keyword ='犬'
#ディレクトリとファイル名を決めるためのワード
keyword2 = 'dog'

if not os.path.exists(keyword2):
    os.mkdir(keyword2)
    print(keyword2)

urlKeyword = parse.quote(keyword)
url = 'https://www.google.com/search?hl=jp&q=' + urlKeyword + '&btnG=Google+Search&tbs=0&safe=off&tbm=isch'

headers = {"User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:47.0) Gecko/20100101 Firefox/47.0",}
request = req.Request(url=url, headers=headers)
page = req.urlopen(request)

html = page.read().decode('utf-8')
html = bs4.BeautifulSoup(html, "html.parser")
elems = html.select('.rg_meta.notranslate')
counter = 0
for ele in elems:
    ele = ele.contents[0].replace('"','').split(',')
    eledict = dict()
    for e in ele:
        num = e.find(':')
        eledict[e[0:num]] = e[num+1:]
    imageURL = eledict['ou']

    pal = '.jpg'
    if '.jpg' in imageURL:
        pal = '.jpg'
    elif '.JPG' in imageURL:
        pal = '.jpg'
    elif '.png' in imageURL:
        pal = '.png'
    elif '.gif' in imageURL:
        pal = '.gif'
    elif '.jpeg' in imageURL:
        pal = '.jpeg'
    else:
        pal = '.jpg'

    try:
        img = req.urlopen(imageURL)
        #localfile = open('./'+keyword+'/'+keyword+str(counter)+pal, 'wb')
        localfile = open('./'+keyword2+ '/' +keyword2+str(counter)+pal, 'wb')
        localfile.write(img.read())
        img.close()
        localfile.close()
        counter += 1
    except UnicodeEncodeError:
        continue
    except error.HTTPError:
        continue
    except error.URLError:
        continue

 

こんな感じです。
f:id:goengine:20190805011610p:plain
コピペしたら、左にある矢印ボタンをクリックしましょう。
これで今コピペしたコードを実行することができます。
実行完了するのに1分ほどかかります。
これだけで画像を取得できました。
/root内にdogフォルダが生成され、dogフォルダ内に犬の画像を保存されています。
確認してみましょう。
左上の「+コード」を押し、先ほどコードをコピペしたのとは別のセルを出します。
以下をコピペして実行します。
ls /root/dog

以下のようにdog0.jpgのように画像ファイルの名前がたくさん表示されたらダウンロードがうまくいったということです。

f:id:goengine:20190805012613p:plain

 

ここまででダウンロードはうまくいったのですが、これを自分のgoogle driveなどに保存しなくてはいけません。

ですので、次にgoogle driveをマウントしていきます。

新しいセルを作って下を入力し、実行しましょう。

from google.colab import drive
drive.mount('/content/drive')

 するとこちらのようにURLができくるので、こちらをクリックします。

f:id:goengine:20190821234626p:plain

 

クリックすると、「Google Drive File Stream が Google アカウントへのアクセスをリクエストしています」と出てくるので許可を選びましょう。

すると、以下のような画面になりますので、枠内の英数字をコピーします。

f:id:goengine:20190821234851p:plain

そしてcolaboratoryの画面に戻って、Enter your authorization code:のところにコピーしてenterを押します。

そうすると、colaboratory上で自身のgoogleアカウントのフォルダが表示されファイルをいじったりコピーすることができます。

 

google driveは以下のMy Driveに同期がされています。

cd /content/drive/My Drive

 lsコマンドなどで確認すると自分のgoogle drive内のファイルがあるのが分かると思います。

同期ができてので、先ほどの犬の画像をコピーしていきましょう。

 

以下のコマンドでdogフォルダを自分のgoogle drive内に丸々コピーできます。

!cp -r /root/dog /content/drive/"My Drive"

 

 コピーすると以下のようにgoogle drive内の保存されていることが確認できます。

f:id:goengine:20190822000030p:plain

犬はかわいいですね。笑

 

以上です。