ミルククラウン・水面変化の観察撮影回路の作成メモ


事前確認

時間的なこと

初速度がなければ、$x=-1/2gt^2$から
1m落ちるのに450msec
0.5m落ちるのに319msec

滴る方法

上開放の升だと、表面張力?のせいで落ちない(穴直径 3mm)
スポイトを直接入れて押し出す方法に変更

水の検出

オムロン 透過型フォト・マイクロセンサ EE-SX460-P1(秋月電子 P-03050)は、検出できず。反射型フォトインタラプタ GP2A200LCS(秋月電子 I-02913)で検出できた。

構成図

使用した機材

(価格は2019/07/21現在)

カメラ

 Sony RX100M5A 
 https://www.sony.jp/cyber-shot/products/DSC-RX100M5A/
 30倍スローモーション(960fps)で最大3秒まで記録できます。
 下記のリモコンを使用するために”シャッターボタンで動画撮影”にします。
 https://helpguide.sony.net/dsc/1810/v1/ja/contents/TP0001228111.html
 フォーカスとか、シャッタースピードとかは適当に選ぶ。

カメラリモコン 

 SHOOT Rm-vpr1 ケーブルレリーズ AFロック機能付 コードリモートシャッター for Sony (@799-)
 https://www.amazon.co.jp/dp/B01NAPCAL5/ref=cm_sw_em_r_mt_dp_U_N1dnDbBGYBB6P
 中から配線を出す改造が必要です。下図 左の赤白青線

マイコン

 制御に使用するマイコン
 Arduino UNO R3 (秋月電子 M-07385 @2,940-)
 http://akizukidenshi.com/catalog/g/gM-07385/

フォトカプラ

 水滴の検出に利用します。 
 反射型フォトインタラプタ GP2A200LCS(秋月電子 I-02913 @350-)
 ただし、合うコネクタが入手困難なためコネクタのプラスチックを一部切って、配線を直接はんだ付けした。
 http://akizukidenshi.com/catalog/g/gI-02913/

温度センサ

 MAX31855 K型熱電対アンプモジュールadafruit PRODUCT ID: 269
 温度依存性を考えて温度を測定しています。
 別途K型熱電対が必要です。
 http://akizukidenshi.com/catalog/g/gM-08218/

距離センサ

 落とす高さを測っています。
 VL53L0X使用 レーザー測距センサモジュール(ToF) (秋月電子 M-12590 @1,080-)
 http://akizukidenshi.com/catalog/g/gM-12590/

ひずみゲージ(重量計)

 重さ(水深)を測っています。
 ロードセル シングルポイント(ビーム型) SC616C 500g(秋月電子 P-12532 @540-)
 http://akizukidenshi.com/catalog/g/gP-12532/
 HX711使用 ロードセル用ADコンバータ モジュール基板 (秋月電子 K-12370 @350-)
 http://akizukidenshi.com/catalog/g/gK-12370/

その他電子部品

回路図

スケッチ

ロードセルは秋月電子のサンプルソース( http://akizukidenshi.com/download/ds/akizuki/ae_hx711.zip )を規格表のミニマム値に変更して使用。

#include <Wire.h>
#include <VL53L0X.h>
#include <SPI.h>
#include <Adafruit_MAX31855.h>
//ピンの設定
#define WaterIn 2
#define SW  3
#define LED 13
#define LED_Green 4
#define LED_Yellow 5
#define LED_Red 6

//カメラの制御で使用するピンの設定
#define CameraShutter 12
#define CameraAF 11

//温度計(熱電対アンプ)の設定
#define DO   10
#define CS   9
#define CLK  8
Adafruit_MAX31855 thermocouple(CLK, CS, DO);

//ロードセル(重量計)の設定
void AE_HX711_Init(void);
void AE_HX711_Reset(void);
long AE_HX711_Read(void);
long AE_HX711_Averaging(long adc, char num);
float AE_HX711_getGram(char num);
#define pin_dout  A3
#define pin_slk   A2
#define OUT_VOL   0.0007f   //定格出力 [V]
#define LOAD      500.0f    //定格容量 [g]
float LCoffset;

//距離計(VL053L0Xの設定
VL53L0X Lidar;

//広域変数の定義
volatile int state = LOW;
int tt = 0, xt = 0;

//初期化(Setup)のプログラム部分
void setup() { 
  Serial.begin(9600);  //PCとの通信設定
  //ピンモードの設定
  pinMode(LED, OUTPUT);
  pinMode(LED_Green, OUTPUT);
  pinMode(LED_Yellow, OUTPUT);
  pinMode(LED_Red, OUTPUT);
  pinMode(SW, INPUT_PULLUP);
  pinMode(WaterIn, INPUT);
  //カメラで使用するピンモードの設定
  pinMode(CameraShutter, OUTPUT);
  pinMode(CameraAF, OUTPUT);
  //ロードセル(重量計)の初期化
  AE_HX711_Init();
  AE_HX711_Reset();
  LCoffset = AE_HX711_getGram(30);  //最初の重量を計測しオフセットに設定
  //距離計(VL053L0X)の初期化
  Wire.begin();
  Lidar.init();
  Lidar.setTimeout(500);
  Lidar.startContinuous();

//水を検知した時の割込みの設定
  attachInterrupt(digitalPinToInterrupt(WaterIn), shutter_on, FALLING); 
}

//水を検知した時の動作プログラム部分
void shutter_on() {           
  digitalWrite(LED_Red, HIGH);
  noInterrupts();  //割込みの禁止
  for (int i = 0 ; i < tt - 70; i++)  delayMicroseconds(1000);
  //開始のシャッターを押すまでの待ち時間 (距離から求めた時間-0.07秒に設定)
  shutter();  //開始のシャッターを押す
  for (int i = 0 ; i < 200; i++)  delayMicroseconds(1000);  //撮影時間(0.2秒)
  shutter();  //撮影終了のシャッターを押す
  interrupts();  //割込みの再開
  digitalWrite(LED_Red, LOW);
}

//シャッターの動作  (スローモーション撮影ではAFの操作は不要)
void shutter() {
  digitalWrite(CameraShutter, HIGH);   //シャッターを押すのと同等
  delayMicroseconds(2000);
  digitalWrite(CameraShutter, LOW);   //シャッターを離すのと同等
}

//通常動作(Loop)のプログラム部分
void loop() {
  //温度計測の部分
  double c = thermocouple.readCelsius();  //温度を摂氏で計測
  if (isnan(c)) {
    Serial.print("Temp Error");
  } else {
    Serial.print("C = ");
    Serial.print(c);
  }
  Serial.print(" ; ");
  //ロードセル(重量計)の部分
  float data;
  char S1[20];
  char s[20];
  data = AE_HX711_getGram(1);
  sprintf(S1, "%s [g]", dtostrf((data - LCoffset), 5, 3, s));
  Serial.print(S1);
  Serial.print(" ; ");
  //距離計(VL53l0X)の部分
  xt = Lidar.readRangeContinuousMillimeters();  //距離を計測
  if (Lidar.timeoutOccurred()) {
    Serial.print("Lidar TIMEOUT");
  } else {
    Serial.print(xt);
    tt = sqrt(204.1 * (float)xt); //距離から落ちるまでの時間を計算
    Serial.print(" ; ");
    Serial.print(tt);
    Serial.print("ms ");
  }
  Serial.println();
}
//*****これ以降は、秋月電子のロードセルのサンプルを使用****
void AE_HX711_Init(void)
{
  pinMode(pin_slk, OUTPUT);
  pinMode(pin_dout, INPUT);
}

void AE_HX711_Reset(void)
{
  digitalWrite(pin_slk, 1);
  delayMicroseconds(100);
  digitalWrite(pin_slk, 0);
  delayMicroseconds(100);
}

long AE_HX711_Read(void)
{
  long data = 0;
  while (digitalRead(pin_dout) != 0);
  delayMicroseconds(10);
  for (int i = 0; i < 24; i++)
  {
    digitalWrite(pin_slk, 1);
    delayMicroseconds(1);
    digitalWrite(pin_slk, 0);
    delayMicroseconds(1);
    data = (data << 1) | (digitalRead(pin_dout));
  }
  digitalWrite(pin_slk, 1);
  delayMicroseconds(2);
  digitalWrite(pin_slk, 0);
  delayMicroseconds(2);
  return data ^ 0x800000;
}

long AE_HX711_Averaging(long adc, char num)
{
  long sum = 0;
  for (int i = 0; i < num; i++) sum += AE_HX711_Read();
  return sum / num;
}

float AE_HX711_getGram(char num)
{
#define HX711_R1  20000.0f
#define HX711_R2  8200.0f
#define HX711_VBG 1.25f
#define HX711_AVDD      4.2987f//(HX711_VBG*((HX711_R1+HX711_R2)/HX711_R2))
#define HX711_ADC1bit   HX711_AVDD/16777216 //16777216=(2^24)
#define HX711_PGA 128
#define HX711_SCALE     (OUT_VOL * HX711_AVDD / LOAD *HX711_PGA)
  float data;
  data = AE_HX711_Averaging(AE_HX711_Read(), num) * HX711_ADC1bit;
  data =  data / HX711_SCALE;
  return data;
}

子供向けイベントの結果で動画が見れます。

https://nwws.jpn.org/creativekidz2019/
※画像の転送にFlash Air を使用したのですが、遅かったです。カメラのマルチ端子からUSB+シャッターが引き出せるケーブルが欲しい。
※カメラが熱くなって調子悪くなるので、休憩が必要。