2015年11月7日土曜日

「机ドン!」検出デバイスw


■追記■

ESP-WROOM-02にも対応しました(リンク)。

■原因はWindows/Excel■

どっちも嫌い。Excelは使い慣れているGoogle SpreadsheetやNumbersと比べてUI特にモード遷移が不自然で違和感の塊だし、ASCIIキーボード愛用マカーなので日本語切り替えキーが変なところにあるのもイヤ。

そんなこんなで職場でのイライラは募るばかり。

そのせいか、ついついキーボードを「バン!」と叩いていたようで、同僚氏からクレームが来ましたです。辛く当たってごめんよ、Apple Wireless keyboard(自腹購入)。

しかし、気をつけていても直らず。

ということで、振動を検出・通知するデバイスを作りました。

■仕様■

手っ取り早くArduino nanoと加速度センサーADXL345マイコン内蔵LEDを使う。

一定以上の衝撃を検出したら、各軸に対応した色のLEDをペカペカ点滅させる。「一定以上」の値についてはボリュームで設定する。

手持ちで単純なRGB入りLEDもあるのでシリアルRGBを使う必要はないんだけど、当初ピンの少ないESP8266上で動かそうとしていたのです。しかしArduino用ライブラリでは動いてくれないので挫折、nanoにしました。

初めての秋月版、きれいにまとまったのに
なお、上の写真でADXL345(赤い基板)のハンダがすごく汚いですが、これは電子工作を再開した直後に作ったもの。隣の秋月ESPに免じて許してやってください。少しはきれいになったのは昔の勘を取り戻したというのもあるけど、大きなものでもルーペ使ってハンダ付けするようになったのが大きな要因だと思います。

■接続など■

Nano接続先
3.3v出力ブレッドボードの+ライン
GNDブレッドボードの-ライン
5v出力マイコン内蔵LEDのVdd
D2マイコン内蔵LEDのDin
A4ADXL345のSCL
A5ADXL345のSDA
A610KΩ半固定抵抗の真ん中

ADXL345接続先
SCLArduino A4
SDAArduino A5
SDOGND
CS3.3v
Vs3.3v
GNDGND
Vdd3.3v

その他、半固定抵抗の一端をGND, 他端を3.3v、マイコン内蔵LEDのGNDをGNDに接続します。あ、またパスコン入れ忘れた。

標準のArduinoだとA6って使えないんでしたっけ。その場合はA0-A3どれでも結構です。そしてソース上のanalogReadで指定しているピン番号をそれに合わせて変えてください…A0の場合は14です。

nanoではなくnanoパチ

■ソフトについて■

ADXL345のライブラリはAndroid Citiさんのライブラリ、マイコン内蔵LEDについてはAdafruitさんのライブラリを使用させていただきました。ありがとうございます。

あ、そろそろ年末だからAdafruitさんに何か注文しなきゃ(注:いつも同社が提供しているライブラリを他社製品でばかり使っているので、年に一度お礼代わりに何か買うことにしています)。

コードはsetupで各デバイスを初期化、点滅に必要なサインカーブ用テーブルを用意、装置の傾きなどを補正するために各軸からの値の平均値を取ってます。loopはぐるぐる回りながら加速度を読み込んで初期値との差分が一定値を超えていたら点滅用のカウンタをセットし、あとはカウンタをインクリメントしながら各軸の値をテーブルに従って変えています。無駄な演算多いけど許してください。

うーん、本当は「ドン!」のピーク値を算出し、それを元にして最大照度などを決定すべきなんですが・・・面倒くさいからやってません。また、現在は加速度で検出していますけど、重力加速度の影響で傾けたりしても誤動作してしまいます。それこそ毎度お馴染みFFTを実行して数Hz以上の加速度成分が一定値を超えたら作動する…って処理にすれば完璧だと思いますが・・・・面倒すぎるのでやってません。


#include <Wire.h>
#include <Adafruit_NeoPixel.h>
#include <ADXL345.h>
#include <Time.h>
//
// NeoPixel
//
#ifdef __AVR__
#include <avr/power.h>
#endif
#define PIN 2
#define NUMPIXELS 1
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
//
// ADXL345
//
ADXL345 adxl; //variable adxl is an instance of the ADXL345 library
#define MaxWaves 64
int wave[MaxWaves];
int aveX, aveY, aveZ;
void setup() {
Serial.begin(115200);
//
// NeoPixels
//
#if defined (__AVR_ATtiny85__)
if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
#endif
// End of trinket special code
pixels.begin(); // This initializes the NeoPixel library.
//
// ADXL345
//
adxl.powerOn();
adxl.setActivityX(1);
adxl.setActivityY(1);
adxl.setActivityZ(1);
adxl.setInactivityX(1);
adxl.setInactivityY(1);
adxl.setInactivityZ(1);
int sumX = 0, sumY = 0, sumZ = 0;
const int times = 10;
for (int i = 0; i < times; i++) {
int x,y,z;
adxl.readAccel(&x, &y, &z); //read the accelerometer values and store them in variables x,y,z
sumX += x;
sumY += y;
sumZ += z;
delay(100);
}
aveX = sumX / times;
aveY = sumY / times;
aveZ = sumZ / times;
//
// others
//
for (int i = 0; i < MaxWaves; i++) {
wave[i] = sin((float)i * 3.14159265 / (float)MaxWaves) * 255;
}
}
// loop counter
int xStep = -1;
int yStep = -1;
int zStep = -1;
// max loop counter
const int MaxSteps = MaxWaves * 5;
// minimum movement
int sensitive;
// range of brightness
int magX, magY, magZ;
//
// calc brightness by range and step in loop
//
int brightness(int inMag, int inStep) {
int ret = wave[inStep % MaxWaves] * inMag / 100;
if (ret < 0) ret = 0;
if (ret > 255) ret = 255;
return ret;
}
//
// set brightness range
//
int calcMag(int inDiff) {
int ret = 10;
if (inDiff > sensitive * 2) {
ret = 100;
} else if (inDiff > sensitive * 2) {
ret = 20;
}
return ret;
}
// average value of volume
int aveVol = 0;
void loop() {
//
// RGB each brightness
//
int red = 0, green = 0, blue = 0;
//
// read volume and set sensitivity
//
aveVol = (aveVol * 9 + analogRead(20)) /10;
sensitive = aveVol / 10;
Serial.println(sensitive);
//
// read accelometer and detect movement
//
int x,y,z;
adxl.readAccel(&x, &y, &z); //read the accelerometer values and store them in variables x,y,z
int diffX = abs(aveX - x);
int diffY = abs(aveY - y);
int diffZ = abs(aveZ - z);
//
// if movement is harder than expected, start flashing!
//
if (diffX > sensitive) {
if (xStep == -1) {
xStep = 0;
magX = calcMag(diffX);
}
}
if (diffY > sensitive) {
if (yStep == -1) {
yStep = 0;
magY = calcMag(diffY);
}
}
if (diffZ > sensitive) {
if (zStep == -1) {
zStep = 0;
magZ = calcMag(diffZ);
}
}
//
// manage flashing
//
if (xStep != -1) {
if (xStep > MaxSteps) {
xStep = -1;
} else {
green = brightness(magX, xStep++);
}
}
if (yStep != -1) {
if (yStep > MaxSteps) {
yStep = -1;
} else {
blue = brightness(magY, yStep++);
}
}
if (zStep != -1) {
if (zStep > MaxSteps) {
zStep = -1;
} else {
red = brightness(magZ, zStep++);
Serial.print(zStep);
Serial.print(",");
Serial.println(red);
}
}
//
// controll WS2811
//
pixels.setPixelColor(0, pixels.Color(green, red, blue));
pixels.show();
// wait for 5mSec
//
delay(5);
}
view raw ADXL_WS2811.cpp hosted with ❤ by GitHub

0 件のコメント:

コメントを投稿

注: コメントを投稿できるのは、このブログのメンバーだけです。