'Sensor'에 해당되는 글 16건

  1. 2020.08.11 Software | Blynk 사용해 보기
  2. 2018.12.02 Hardware | MAX30105 파티클 센서 - 2
  3. 2018.03.01 Hardware | HC-SR501 PIR motion sensor - 2 2
  4. 2017.08.20 Hardware | Gyroscope GY-521 MPU-6050 을 사용해 보자
  5. 2017.08.02 Hardware | Soil Moisture Sensor 구동해 보기
  6. 2017.07.29 Hardware | DS18B20 온도센서 17
  7. 2017.07.09 Hardware | Arduino 의 Sensor Shield 사용해 보기
  8. 2017.06.28 Hardware | YF-S201 water flow sensor 가지고 놀기 4
  9. 2017.05.07 Hardware | HC-SR501 PIR motion sensor
  10. 2017.05.07 Hardware | Arduino water level sensor

Software | Blynk 사용해 보기

|

Arduino 나 ESP8266 을 사용하면서, sensor 로부터 받은 데이터를 표현해주는 방법이 몇 가지 있습니다.

일전에는 ThingSpeak 라는 것을 사용해 봤었죠.


* Software | ThingSpeak 등록하여 IoT 데이터 펼처보기

https://chocoball.tistory.com/entry/Software-ThingSpeak-IoT-monitoring


어느 분께서 댓글 달아 주시길, Blynk 도 좋다고 합니다. 사용해 봤습니다.





1. Blynk 란?


Data 는 있지만, 그 값들을 이해하기 쉬운 방법으로 표시해 주고 모니터링 해주는 어플리케이션 이죠.



클라우드 펀딩으로 시작한 솔루션 입니다.


* Blynk - build an app for your Arduino project in 5 minutes

- https://www.kickstarter.com/projects/167134865/blynk-build-an-app-for-your-arduino-project-in-5-m



Arduino project 를 5분만에 시작할 수 있다고 하지만, 숙련된 사람 이야기 이고, 학습하는 시간이 필요합니다.

다만, 각 프로젝트에 따른 예시나 모듈이 잘 되어 있어서, 하다 보면, 아니... 이렇게 쉽게? 라는 생각이 잠시 드는 때도 있습니다.


KickStarater 클라우드 펀딩을 성공적으로 마무리 하고, 아래 사이트에서 정식 런칭하였습니다.


* Blynk Inc

https://blynk.io/





2. Library 설치


저는 Arduino / ESP8266 에서 받은 값을 전달할 목적이므로, Arduino IDE 에서 모듈을 인스톨 합니다.


Tools > Manage Libraries > Blynk


모듈이 인스톨 되면, Arduino > libraries 에 등록 되어 있는 것을 확인 할 수 있습니다.



자동으로 설치해 주는 방법 외에도, 수동으로 파일을 받아서 설치 할 수도 있습니다.


* Blynk Arduino Library

https://github.com/blynkkk/blynk-library/releases/latest





3. App 설치


프로그래밍을 위한 환경이나 라이브러리가 설치되었으면, 실제로 그 값들을 모니터링 하고 확인할 수 있는 인터페이스가 필요합니다.

Blynk 는 모바일 환경에 최적화가 되어 있으므로, 스마트폰에 관련 어플을 설치합니다.


평점이 좋네요.





4. Project 시작하기


모바일앱에서 어플을 시작하면, 등록이 나옵니다.



Facebook 계정 연동으로 시작해도 되나, 저는 그냥 email 로 사용자 등록 하였습니다.



계정을 만들고 로그인 합니다.



New Project 를 선택합니다. My Apps 메뉴를 이용해서, 개인 전용앱 처럼 꾸밀 수도 있다고 합니다.



시작할 새로운 Project 는 주로 어떤 IoT 기기와 연결될 것 인지를 선택합니다.

저는 ESP8266 을 이용하여, WiFi 연결 뿐만 아니라, arduino 처럼 처리도 시킬 것이기 때문에, ESP8266 을 선택 했습니다.



포름알데히드 센서를 이용한 그래프 모니터링용 이니, 그에 맞게 Title / Device / Connection Type 을 선택해 줍니다.

저는 Formaldehyde / ESP8266 / WiFi 를 선택 했습니다.



Create Project 를 최종적으로 누르면, 새로 생성한 project 에 대한 전용 인증 코드가 생성됩니다.

이 코드는 project 마다 유니크 하며, 메일로도 알려 줍니다.



계정 생성시 사용 했던 email 로 관련된 정보가 왔습니다.


Auth Token





5. 소스코드 생성


누가 5분만에 가능하다 했나... 5분은 여기까지 오느라 훨씬 지났습니다.

다만, 코딩을 쉽게 도와주기 위해 "Sketch generator" 라는 메뉴가 준비되어 있어요.


* Sketch generator

https://examples.blynk.cc/


접속하면, 아래처럼 Board (Device) / Connection 방법 / Auth Token 및 예시를 선택하면 소스코드를 만들어 줍니다!



이 페이지에서 만들어준 기본 코드에, 포름알데히드 측정에 사용되었던 코드를 살짝 추가 하였습니다.


Blynk 사용하지 않은 코드


#include "ze08_ch2o.h"
#include "SoftwareSerial.h"
 
// Instantiate a serial port, whatever Stream you have
// SoftwareSerial ch2oSerial(4, SW_SERIAL_UNUSED_PIN); // RX, TX
SoftwareSerial ch2oSerial(14, 14); // RX, TX
 
// Instantiate a sensor connected to the previous port
Ze08CH2O ch2o{&ch2oSerial};
 
void setup() {
    ch2oSerial.begin(9600);
    ch2oSerial.listen();
    Serial.begin(115200); // Serial Monitor
}
 
void loop() {
    Ze08CH2O::concentration_t reading;
     
    if (ch2o.read(reading)) {
        Serial.print("New value: ");
        Serial.println(reading);
    }
}



Blynk 기능을 입힌 코드


#include "ze08_ch2o.h"
#include "SoftwareSerial.h"

SoftwareSerial ch2oSerial(14, 14); // RX, TX
Ze08CH2O ch2o{&ch2oSerial};

int sensorData;

/* Comment this out to disable prints and save space */
#define BLYNK_PRINT Serial

#include "ESP8266WiFi.h"
#include "BlynkSimpleEsp8266.h"

// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "XXXXXXXXXXXX";
char pass[] = "YYYYYYYYYYYYYYYYYYY";

BlynkTimer timer;

// This function sends Arduino's up time every second to Virtual Pin (5).
// In the app, Widget's reading frequency should be set to PUSH. This means
// that you define how often to send data to Blynk App.
void myTimerEvent() {
	// You can send any value at any time.
	// Please don't send more that 10 values per second.
	
	Ze08CH2O::concentration_t reading;
	if (ch2o.read(reading)) {
		Serial.print("ZE08-CH2O : ");
		Serial.println(reading);
		
		sensorData = reading;
	}
	Blynk.virtualWrite(V5, sensorData);
}

void setup() {
	// Debug console
	Serial.begin(115200);
	
	ch2oSerial.begin(9600);
	ch2oSerial.listen();
	
	Blynk.begin(auth, ssid, pass);
	// You can also specify server:
	//Blynk.begin(auth, ssid, pass, "blynk-cloud.com", 80);
	//Blynk.begin(auth, ssid, pass, IPAddress(192,168,1,100), 8080);
	
	// Setup a function to be called every second
	timer.setInterval(5000L, myTimerEvent);
}

void loop() {
	Blynk.run();
	timer.run(); // Initiates BlynkTimer
}


위의 Before / After 를 비교해 보면, "Sketch generator" 코드에서 자동으로 만들어준 소스에, 원래 소스를 살짝 입히기만 했습니다.

참 쉽죠?! 제가 작업한 것은 다음 세 가지 뿐 입니다.


- 기본 소스 코드 생성 (이것 마저도 인터넷에서 따옴)

- Sketch generator 이용하여 Blynk 연결 소스 만듬

- Auth Token / WiFi 접근 SSID / Password 적용


가장 눈여겨 들여다 봐야 할 부분은 아래 코드 부분입니다.


	Blynk.virtualWrite(V5, sensorData);


Blynk 는 ESP8266 / ESP32 등에서 받는 data 값 들을, 가상의 Pin 으로 보내는 기능이 있습니다.

Analog / Digital 값들이 다양한 Pin 들을 통해 들어온다 하여도, Blynk 로 보낼 때에는 하나의 가상 Pin 으로 고정해서 보낼 수 있습니다.


이렇게 되면, Device 가 변경되더라도 Blynk 앱에서는 변경을 하지 않아도 됩니다. 자세한 내용은 아래 링크를 참고해 보세요.


* What is Virtual Pins

http://help.blynk.cc/en/articles/512061-what-is-virtual-pins


* How to display ANY sensor data in Blynk app

http://help.blynk.cc/en/articles/512056-how-to-display-any-sensor-data-in-blynk-app





6. ESP8266 에서 실행


ESP8266 에 소스를 입히고 실행시키면, 다음과 같은 화면이 Serial Monitor 에 출력 됩니다.


[5220] Connected to WiFi
[5221] IP: 192.168.1.90
[5221] 
    ___  __          __
   / _ )/ /_ _____  / /__
  / _  / / // / _ \/  '_/
 /____/_/\_, /_//_/_/\_\
        /___/ v0.6.1 on ESP8266

[5227] Connecting to blynk-cloud.com:80
[5586] Ready (ping: 125ms).
ZE08-CH2O : 66
ZE08-CH2O : 112
ZE08-CH2O : 114
ZE08-CH2O : 117
ZE08-CH2O : 116
ZE08-CH2O : 114
...


ASCII code 를 이용하여 Blynk 문자를 잘 만들었네요 :-)



Library 는 Heartbeat 를 통한 연결상태 확인도 해주는 군요. 잘 만들어져 있습니다.



여기까지 진행하면 ESP8266 에서 할 것은 이제 다 했습니다.




7. Blynk 모바일앱에서 설정


Blynk 로 데이터는 들어오고 있으니, 받을 수 있도록 연동 설정하면 됩니다.

데이터를 표현해주는 방법은 여러 가지가 있으나, 대략 Gauge / SuperChart 로 해결 됩니다.


스마트 폰에서 Create Project 후에 나오는 빈 화면 아무곳을 터치하면, Widget Box 가 아래처럼 뜹니다.

건전지 아이콘에 2000 크레딧이 미리 충전 (무료) 되어 있습니다.

이걸 다 쓰면, 돈을 충전해서 사용해야 합니다. 각 메뉴 추가시 크레딧이 차감되니 신중하게 위젯을 만들어야 합니다.



처음에 멋도 모르고 "Value Display" 를 설정 했더랬습니다. 그냥 조금하게 값만 표시됩니다.



역시 데이터 값 표현은 차트죠. SuperChart 만들어 봅니다.

PIN 정보는 항상 "Virtual 5 PIN" 으로 했습니다만, 다른 Pin 들도 다이렉트로 사용할 수 있나 봅니다.



만들어진 위젯에 손가락을 잠깐 동안 올려 놓으면, 위치를 이동 시킬 수 있습니다.



이제 센서 값들의 모니터링은 일상으로 사용하는 스마트폰에서 바로바로 확인이 가능하게 됩니다.

웹페이지를 띄울 필요도 없고, 인증을 걸 필요도 없이, 하나의 앱 처럼 사용할 수 있어서 편하긴 합니다.




FIN


And

Hardware | MAX30105 파티클 센서 - 2

|

이 글은 이전 MAX30105 파티클 센서를 활용하여 OLED 에 심전도를 그려보는 도전기 입니다.

이전 글은 아래 link 를 참고하세요.


* Hardware | MAX30105 파티클 센서 - 1

http://chocoball.tistory.com/entry/Hardware-MAX30105-particle-sensor-1





1. min, max 와 scalar


일단 MAX30105 에서 입력받는 값은 5만에서 많게는 10만도 넘어갑니다.

이를 32 pixel 너비를 갖는 OLED 에 표현하려면 그 값에 맞도록 축소시켜야 합니다.



이에 더하여, 값들의 기준이 아래 그림처럼 널을 뛰므로 기준값을 잡기가 여간 쉽지 않습니다.



기준값을 잡기 위해 min, max 값을 한 사이클당 판별하여 scale in 치환값을 잡아줘야 합니다.


이를 위해 일단, 이전 사이클에서 얻은 제일 작은 min 값을 이용하여,

입력받는 값에서 빼면 그래프가 아래 그림처럼 내려갑니다.



OLED 폭이 128 pixel 이므로, 이 폭을 한 사이클로 잡습니다.

EXCEL 을 통하여 위의 방식을 검증해 본 결과 문제 없이 표현되는 것을 확인할 수 있었습니다.



OLED 의 y 값에 해당하는 값을 EXCEL 에서 32 pixel 기준으로 변환된 값을 array 에 입력하고

순서대로 출력해서 OLED 에 맞는지 최종 확인해 봅니다.



요리조리 검증해 본 결과 아래 식을 통해서 min, max 값과 한 사이클을 OLED 폭인 128 에 표현하고

다시 0 부터 시작하는 - 화면이 바뀌는 방법을 확인하였습니다.


	irValue = particleSensor.getIR();
	
	if( x > 127) { //refresh OLED screen
		display.clearDisplay();
		lastx=0;
		x=1;
		
		scaler = (max_irValue - min_irValue) / 32;
		pre_min_irValue = min_irValue;
		
		// reset min, max value
		max_irValue = irValue;
		min_irValue = irValue - 1;
	}





2. y값 reverse


OLED 에 표현시, x/y 값은 우리가 일반적으로 배운 왼쪽 아래에서 시작되는 것이 아니라,

왼쪽 위로부터 값의 증가를 표현합니다.



즉, sensor 로부터 값을 입력 받으면, 상하 전치를 시켜줘야 합니다.

제가 쓰고 있는 것은 상하 32 pixel 이므로, 아래 한 pixel 을 빼면 31 이므로,

31 에서 입력받은 값을 빼주면 표현하고자 하는 위치로 바꿀 수 있습니다. 



	// invert y values to fit OLED display
	if ( pre_min_irValue > irValue) {
		y = 31;
	} else {
		y = 31 - ((irValue - pre_min_irValue) / scaler);
	}

값이 너무 적어지면, 값이 역전하여 아래 그림같이 튀어버립니다.

그래서 전 사이클에서 확인 되었던 min value 보다 적어지면 강제적으로 최저값을 할당합니다.

여기서 "y = 31" 은 OLED 상에서는 제일 밑에 표시되는, 일상의 0 값과 같습니다.






3. BPM 과 piezo buzzer


심전도의 값이 가장 높아지면 buzzer 를 울리게 하는 소스 입니다.

또한 BPM 값도 표현해 줍니다.


BPM 값은 심전도의 한 사이클 평균을 내어 1분동안 얼마나 맥박이 뛰는지를 수치화 한 값입니다.



소스는 다음과 같고, 아래 blog 를 전면 참고하였습니다.


* Heart beat Sensor and “ECG” Display

http://www.xtronical.com/basics/heart-beat-sensor-ecg-display/


	ThisTime=millis();
	if( y < UpperThreshold ) {
		if(BeatComplete) {
			BPM=ThisTime-LastTime;
			BPM=int(60/(float(BPM)/1000));
			BPMTiming=false;
			BeatComplete=false;
			tone(2,1000,250);
		}
		if(BPMTiming==false) {
			LastTime=millis();
			BPMTiming=true;
		}
	}
	if((y > LowerThreshold) && (BPMTiming))
		BeatComplete=true;






4. source


지금까지의 작업을 모두 합하여 하나의 소스로 만들었습니다.


#include "Wire.h"
#include "MAX30105.h"

#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_SSD1306.h"

// Hardware SPI
#define OLED_DC     6
#define OLED_CS     7
#define OLED_RESET  8
Adafruit_SSD1306 display(OLED_DC, OLED_RESET, OLED_CS);

MAX30105 particleSensor;

unsigned int irValue;
unsigned int max_irValue;
unsigned int min_irValue;
unsigned int x = 0;
unsigned int y;
unsigned int lastx = 0;
unsigned int lasty = 0;
unsigned int scaler;
unsigned int pre_min_irValue;
int BPM;
int LastTime = 0;
int ThisTime;
bool BPMTiming=false;
bool BeatComplete=false;
#define UpperThreshold 10
#define LowerThreshold 25

void setup() {
  Wire.begin();
  display.begin(SSD1306_SWITCHCAPVCC);
  display.clearDisplay();
  
  // initialize sensor
  if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) { //Use default I2C port, 400kHz speed
    display.println("MAX30105 was not found. Please check wiring/power.");
    while (1);
  }
  
  //Setup to sense a nice looking saw tooth on the plotter
  byte ledBrightness = 0x1F; //Options: 0=Off to 255=50mA
  byte sampleAverage = 8; //Options: 1, 2, 4, 8, 16, 32
  byte ledMode = 3; //Options: 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green
  int sampleRate = 1000; //Options: 50, 100, 200, 400, 800, 1000, 1600, 3200
  int pulseWidth = 411; //Options: 69, 118, 215, 411
  int adcRange = 4096; //Options: 2048, 4096, 8192, 16384
  
  particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); //Configure sensor with these settings
  
  // initiate min, max values
  irValue = particleSensor.getIR();
  max_irValue = irValue;
  min_irValue = max_irValue - 1; 
  for (int ini ; ini < 100 ; ini++) {
	  irValue = particleSensor.getIR();
	  
	  if (max_irValue < irValue) {max_irValue = irValue;}
	  if (min_irValue > irValue) {min_irValue = irValue;}
  }
  
  display.display();
}

void loop() {
	irValue = particleSensor.getIR();
	
	if( x > 127) { //refresh OLED screen
		display.clearDisplay();
		lastx=0;
		x=1;
		
		scaler = (max_irValue - min_irValue) / 32;
		pre_min_irValue = min_irValue;
		
		// reset min, max value
		max_irValue = irValue;
		min_irValue = irValue - 1;
	}
	
	display.setTextColor(WHITE);
	ThisTime=millis();

	// invert y values to fit OLED display
	if ( pre_min_irValue > irValue) {
		y = 31;
	} else {
		y = 31 - ((irValue - pre_min_irValue) / scaler);
	}
	
	// draw heartbeat lins
	display.drawLine(lastx, lasty, x, y, WHITE);
	lasty = y;
	lastx = x;
	
	// update min, max values
	if (max_irValue < irValue) {max_irValue = irValue;}
	if (min_irValue > irValue) {min_irValue = irValue;}
	
	ThisTime=millis();
	if( y < UpperThreshold ) {
		if(BeatComplete) {
			BPM=ThisTime-LastTime;
			BPM=int(60/(float(BPM)/1000));
			BPMTiming=false;
			BeatComplete=false;
			tone(2,1000,250);
		}
		if(BPMTiming==false) {
			LastTime=millis();
			BPMTiming=true;
		}
	}
	if((y > LowerThreshold) && (BPMTiming))
		BeatComplete=true;
	
	// display BMP
	display.fillRect(0,24,64,32,BLACK);
	display.setCursor(0,24);
	display.print("      BPM");
	display.setCursor(0,24);
	display.print(BPM);
	
	// check finger is on the sensor
	if (irValue < 10000) { display.setCursor(1,1); display.print("NO Finger?"); }
	
	// display all data to OLED
	display.display();
	x++;
}


결과 동영상을 올려 봅니다.







FIN


이걸 구현해 보려고 3주간 주말 = 토, 일 이틀간 x 3 = 6일 동안 삽질의 연속이었습니다.

이 문제는 소스에서 scalar 를 구하기 위한 나누기를 해야 하는데, % 연산자를 사용했기 때문이었습니다.


* Modulo

https://www.arduino.cc/reference/en/language/structure/arithmetic-operators/modulo/


% 연산자는 몫을 구하는 것이 아니라, 나머지를 구하는 연산자지요!!!

반대로 알고 있었던 것. 이걸 알아 차리는데 6일이나 걸렸습니다!!!



변수의 갯수도 줄여 보기도 하고, 각 값을 먼저 scale in 해서 결과를 내보기도 하고, 하여간 별짓 다 했습니다.

처음에 디버깅만 잘 했어도 이렇게 오래 걸리지는 않았을 듯 하네요.

디버깅 작업이 얼마나 중요한지 새삼 깨닳았습니다.



이렇게 하면 Serial Monitor 에도 이렇게 나오니 환장할 노릇이었습니다.


이 덕에 Hardware SPI 활용과 OLED refresh rate 등등을 공부하게 되었네요.

아이고야... 좀 쉬자.


SpO2 농도 값이나, 그래프를 좀더 안정적으로 보여줄 수 있도록 소스를 더 다듬고 싶었지만,

에너지를 너무 많이 써서 이번 작업은 여기까지 하겠습니다.


나중에 다시 생각나면, 소스코드를 다시 잡아 볼께요.


And

Hardware | HC-SR501 PIR motion sensor - 2

|

1. 시작


HC-SR501 을 가지고 움직임이 있을 시 반응하는 센서를 가지고 놀아 봤더랬습니다.


* Hardware | HC-SR501 PIR motion sensor

http://chocoball.tistory.com/entry/Hardware-HCSR501-PIR-motion-sensor


그러던 중, Photoresistor 단자를 발견합니다.



아래는 HC-SR501 회로도 입니다.



제조사의 사이트에 올라와 있는 회로도와 실제 기판을 봐도 이미 R3 (1MΩ) 이 실장되어 있어서,

제대로 된 값의 photoresistor 만 달면 기능하게 되어 있네요.


좀더 찾아 보니, 아예 세트로 파는 업자도 있습니다.



요는 photoresistor 를 이용하여, 항상 모션 탐지를 하는 것이 아니라,

어두워졌을 때에만 작동하도록 하는 것 입니다.


흠흠, 그럼 photoresistor 를 구입해야 겠죠?





2. Photoresistor 가지고 놀기


HC-SR501 에 photoresistor 를 붙여서 구동하기 위해, 우선 photoresistor 를 가지고 놀아봅니다.


* Hardware | Arduino 로 Photoresister 가지고 놀기 - 1

http://chocoball.tistory.com/entry/Hardware-Arduino-Photoresister-1


이때 구입한 제품이 GL5528.

간단한 동작을 확인 했으니, 본격적으로 HC-SR501 에 붙여 봅니다.





3. HC-SR501 에 납땜하기


Photoresistor 는 RL 이라는 자리에 납땜하면 됩니다.

+/- 전극 구분이 없어서 그냥 두 다리 고정하고 납땜하면 됩니다.



높이 잘 계산해서 올려주고요.



장착되면 위와 같은 모습이 됩니다.



다리를 옆으로 벌려서 흔들리지 않게 하고 납땜합니다.



짜잔 !!!




4. Layout 및 Sketch


구성은 예전 글에서 사용했던 구성과 sketch 와 완벽히 동일합니다.


HC-SR501 PIR sensor | Arduino Nano
----------------------------------
         S          |     D8
         +          |     5V
         -          |     GND
----------------------------------
 
    Piezo busser    | Arduino Nano
----------------------------------
         S          |     D11
         +          |     5V
         -          |     GND
----------------------------------


회로 구성입니다.



Sketch 입니다.


/*******************************************************
 
Uses a PIR sensor to detect movement, sounds a buzzer
 
*******************************************************/
//the time we give the sensor to calibrate (10-60 secs according to the datasheet)
int calibrationTime = 30;
 
int ledPin = 13; // choose the pin for the LED
int inputPin = 8; // choose the input pin (for PIR sensor)
int pirState = LOW; // we start, assuming no motion detected
int val = 0; // variable for reading the pin status
int pinSpeaker = 11; //Set up a speaker on a PWM pin (digital 9, 10, or 11)
 
void setup() {
pinMode(ledPin, OUTPUT); // declare LED as output
pinMode(inputPin, INPUT); // declare sensor as input
pinMode(pinSpeaker, OUTPUT);
 
//give the sensor some time to calibrate
Serial.begin(9600);
Serial.print("Calibrating sensor ");
  for(int i = 0; i < calibrationTime; i++) {
    Serial.print(".");
    delay(1000);
  }
  Serial.println(" Done!");
  Serial.println("SENSOR is ACTIVE now");
  delay(50);
}
 
void loop() {
  val = digitalRead(inputPin); // read input value
  if (val == HIGH) { // check if the input is HIGH
    blinky(); // blink LED when motion haas been detected
    // digitalWrite(ledPin, HIGH); // turn LED ON
    playTone(300, 160);
    delay(150);
     
    if (pirState == LOW) {
    // we have just turned on
      Serial.println("Motion detected!");
      // We only want to print on the output change, not state
      pirState = HIGH;
    }
  } else {
    digitalWrite(ledPin, LOW); // turn LED OFF
    playTone(0, 0);
    delay(300);
 
    if (pirState == HIGH){
    // we have just turned off
      Serial.println("Motion ended!");
      // We only want to print on the output change, not state
      pirState = LOW;
    }
  }
}
 
void playTone(long duration, int freq) {
  // duration in mSecs, frequency in hertz
  duration *= 1000;
  int period = (1.0 / freq) * 1000000;
  long elapsed_time = 0;
 
  while (elapsed_time < duration) {
    digitalWrite(pinSpeaker,HIGH);
    delayMicroseconds(period / 2);
    digitalWrite(pinSpeaker, LOW);
    delayMicroseconds(period / 2);
    elapsed_time += (period);
  }
}
 
void blinky() {
  for(int i=0; i<3; i++) {
    digitalWrite(13, HIGH);
    delay(200);
    digitalWrite(13, LOW);
    delay(200);
  }
}





5. 흠...


손으로 photoresistor 를 가리면 동작은 하는데, 기민하게 동작하지 않았습니다.


원래 회로는 short 된 회로인데,

photoresistor 를 연결하면 광원이 있는 곳에서 close 상태로 만들어 주어 모션 감지를 하지 않게 (disable) 됩니다.


주위가 어두워 지면 photoresistor 의 dark resistance 가 올라가

원래 회로가 가지고 있던 short 상태를 만들어 주는 것인데,

어정쩡하게 저항이 발생하면 제대로 short 된 상태로 넘어가지 못하는 것이었습니다.


뭔가 Photoresistor 가 망가졌나? 생각하고 다른 GL5528 센서로 교환하다, 옆에 있던 캐패시터 옆구리를 지져버렸습니다.

아놔...


다행히 기존에 구입해 놨던 capacitor 가 있어서 교체합니다.


* Hardware | AliExpress 에서 condenser 를 구입해 보자

http://chocoball.tistory.com/entry/Hardware-AliExpress-condenser-buy



기존의 capacitor 보다는 굵은 소자라 뭔가 신뢰가 가네요.






6. 다른 Photoresistor


Capacitor 를 교환했고, photoresistor 도 교환했음에도 불구하고 여전히 기민하게 동작하지 않습니다.

Photoresistor 를 가리고 한참 기다리고 있어도 운 좋으면 detecting 하고, 그렇지 않으면 아무 반응이 오지 않았습니다.


결국 구입한 photoresistor 의 수치적인 한계라고 확신하고, 다른 photoresistor 를 구입해서 테스트 해보기로 합니다.


처음 구입할때는 보이지 않았던, 5가지 묶음 세트가 있네요.

바로 구입합니다. (아니 왜 저 세트로 처음부터 안파냐고...)


* Photoresistor Kit 5Kindsx10pcs 5506 5516 5528 5537 5539 Light Dependent Resistor LDR Pack Photoresistor Package for Arduino

- https://ko.aliexpress.com/item/Photoresistor-Kit-5Kindsx10pcs-5506-5516-5528-5537-5539-Light-Dependent-Resistor-LDR-Pack-Photoresistor-Package-for/32812625860.html



각 소자 번호에 따라 어떤 값을 보이는지 테스트 해봤습니다.


* Hardware | Arduino 로 Photoresister 가지고 놀기 - 2

http://chocoball.tistory.com/entry/Hardware-Arduino-Photoresister-2


수치를 그래프화 해본 결과, 처음 구입한 GL5528 (녹색) 은 가장 어둡게 해도

dark resistance 가 조금 높게 나옵니다. (스펙상으로는 1MΩ 이긴 한데...)



확인 결과 새로 구입한 세트에 있는 5539 (하늘색) 이 더 높은 dark resistance 를 보여 줬습니다.

어둡게 하면 거의 short 상태를 만들어 줄 수 있을 것 같습니다.



수치적으로도 5MΩ 정도면 short 상황을 만들 수 있겠네요. 





7. 구동 확인


기존 GL5528을 제거하고 새로 구입한 5539 를 납땜해 주었습니다.

이제 대망의 마지막 확인 입니다.



5539 photoresistor 는 센서의 구불구불이 더 촘촘하네요.



어둡게 하면 의도대로 잘 동작합니다.



Photoresistor 에 샤프심 캡을 씌워, 어두운 상황을 만들어 동작 시키니 예상대로 반응합니다.




FIN


작년 7월에 처음 photoresistor 를 구매하여 실패의 실패를 거듭하여 겨우 확인 했습니다.

HC-SR501 센서는 이제 서랍으로 들어갈 수 있게 되었습니다.


Photoresistor 는 종류와 가용 범위가 많아서 잘 선택하고 사용해야겠습니다.


이제야 마음 편하게 다른 센서들 공부를 할 수 있겠네요.


And

Hardware | Gyroscope GY-521 MPU-6050 을 사용해 보자

|

1. 자이로스코프

드론이 호버링 하거나 방향전환시 필요한 것중 하나가 위치조정 일것 같습니다.

이런걸 가능하게 하는 센서가 "Gyroscope" 입니다.


중력을 이용하여 자기의 위치를 알아내는 센서가 있다는게 신기할 따름입니다.


AliExpress 에서 검색해 보니, 1.09 USD!

아니 이게 1천원정도의 가격이라고?





2. 원리

전통적인 자이로스코프는 원심력을 이용하여 자기 위치를 되돌리려는 성질의 기구가 있습니다.


https://en.wikipedia.org/wiki/Gyroscope



그런데, 이걸 반도체 안에 센싱하는 소자들을 구성하여 만든게 이번에 리뷰하는 MPU-6050 칩 입니다.



그림을 보니 중력을 이용하여 이동하는 mass 와 그걸 감지하고 원래로 복원하려고 하는 스프링 등으로 구성되었네요.

그 작은 반도체 안에 저런것을 만들어 놓다니. 거기에 1.09 USD 처럼 저렴하다는 것에 한번 더 놀랍니다.


관련된 문서는 아래에 있습니다.


IMU_Wk8.pptx

AN3461.pdf


어디선가 배웠던 "코리올리 효과"를 이용한다고 합니다.

참고해 보세요.




3. 도착

잊을만 하고 있을 적에 도착하였습니다. 거진 한달 걸린것 같습니다.



구성품은 GY-521 breakout 보드와 구부러진 male pin 과 똑바른 male pin 이 각각 들어있습니다.



Chip 을 보면 중간 부분에 희미하게 MPU-6050 이라고 적혀 있습니다.



좀더 잘 찍힌 제품사진은 다음과 같습니다. Chip 이 잘 보이네요.



뒷면입니다. MPU-6050 을 사용한 제품 중, 가장 일반적으로 사용되는 breakout 보드는 GY-521 이라고 하네요.



구부러진 pin 을 납땜하느냐, 곧은 pin 을 납땜하느냐 고민했습니다.

향후 어떤 보드 위에 설치하게 될 것이냐를 상상하여, 그 보드가 평평할 듯 하여 곧은 pin 을 납땜하였습니다.





4. Pinout

Breakout 보드에는 8개의 pinout이 있지만, 실제로 사용되는 것은 5개, 또는 6개만 사용됩니다.


    GY-521   | Arduino Nano
----------------------------
     VCC     |     3.3V
     GND     |     GND
     SCL     |     A5
     SDA     |     A4
     AD0     |     GND
     INT     |     D2
----------------------------


GY-521 pinout 에 대한 몇가지 지식을 적어 봅니다.

- 원래 3.3V 가 구동 voltage 이지만, GY-521 은 자체 레귤레이터가 있어서 5V 도 가능합니다.

- Arduino 에는 2개의 MPU-6050 을 연결할 수 있게 되어 있고, AD0 의 high/low voltage 로 구분합니다.

- SCL 은 I2C 의 clock 담당이고, SDA 는 data 를 담당합니다.


관련된 내용을 영문 페이지들에서 가져와 봤습니다.


The MPU-6050 can have address of 0x68 or 0x69, depending on if the AD0 pin is held high or low.

Without anything connected, it was at 0x68 for me.


AD0 can be used to control the I2C-address. If it is connected to ground then the address is 0x68 and if it is connected to VLOGIC then the address is 0x69. The data sheet for the chip states that VLOGIC ranges from 1.71V to the working voltage of the chip. To find out the address the I2C scanner sketch can be uploaded to the Arduino when it is connected to the GY-521. The result can be viewed through the serial monitor. For the GY-521 the I2C device is found at address 0x68. This means that ADO must be connected to a pull down resistor. This holds the signal at 0V.


The gyro module communicates with the Arduino through I2C serial communication via the serial clock (SCL) and data (SDA). The MPU6050 chip needs 3.3V but a voltage regulator on the GY-521 board allows you to give it up to 5V.


Layout 은 다음과 같습니다.



실제 연결한 사진입니다.






5. I2C

Arduino 와의 인터페이스가 I2C 입니다.

우선 잘 인식 되는지 확인해 보도록 합니다.


Arduino IDE 의 Library Manager 에서 "i2cdetect" 를 인스톨 하여 돌려봅니다.



소스는 간단합니다.


#include "Wire.h"
#include "i2cdetect.h"

void setup() {
	Wire.begin();
	Serial.begin(9600);
	Serial.println("i2cdetect example\n");
	Serial.print("Scanning address range 0x03-0x77\n\n");
}

void loop() {
	i2cdetect(); // default range from 0x03 to 0x77
	delay(2000);
}

결과는 다음과 같이 잘 나옵니다.

잘 인식 되었네요.



다만 MPU6050 전용 sketch 를 돌리기 위해서는 "I2Cdev.h" 가 IDE 에 등록이 되어야 합니다.

필요한 파일은 아래 링크에서 다운로드 받을 수 있습니다.


https://github.com/jrowberg/i2cdevlib



다운로드 받은 zip 파일 내부를 보면 "I2Cdev" 라는 폴더가 있습니다.

이 "I2Cdev" 폴더를 IDE 의 library 폴더 하위에 copy 하면 library 등록이 됩니다.


- I2Cdev path : i2cdevlib-master > Arduino > I2Cdev

- library path : Arduino > library


아래는 다운로드 받은 zip 파일의 path 입니다.



아래는 Arduino 의 library path 입니다.



이제 I2C 준비는 완료 되었습니다.




5. MPU-6050 sketch

이제 MPU-6050 을 구동해 볼 차례 입니다.


위에서 다운로드 받았던 zip 파일인 "i2cdevlib-master.zip" 에서 다음 path 에서 찾아보면,

"MPU6050" 이라는 폴더가 있습니다.


- I2Cdev path : i2cdevlib-master > Arduino > MPU6050


이 폴더를 I2Cdev 와 동일한 library 폴더에 옮겨 놓으면 sketch example 을 사용할 수 있게 됩니다.

 


소스는 다음과 같습니다.


// I2C device class (I2Cdev) demonstration Arduino sketch for MPU6050 class using DMP (MotionApps v2.0)
// 6/21/2012 by Jeff Rowberg 
// Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
//
// Changelog:
//      2013-05-08 - added seamless Fastwire support
//                 - added note about gyro calibration
//      2012-06-21 - added note about Arduino 1.0.1 + Leonardo compatibility error
//      2012-06-20 - improved FIFO overflow handling and simplified read process
//      2012-06-19 - completely rearranged DMP initialization code and simplification
//      2012-06-13 - pull gyro and accel data from FIFO packet instead of reading directly
//      2012-06-09 - fix broken FIFO read sequence and change interrupt detection to RISING
//      2012-06-05 - add gravity-compensated initial reference frame acceleration output
//                 - add 3D math helper file to DMP6 example sketch
//                 - add Euler output and Yaw/Pitch/Roll output formats
//      2012-06-04 - remove accel offset clearing for better results (thanks Sungon Lee)
//      2012-06-01 - fixed gyro sensitivity to be 2000 deg/sec instead of 250
//      2012-05-30 - basic DMP initialization working

/* ============================================
I2Cdev device library code is placed under the MIT license
Copyright (c) 2012 Jeff Rowberg

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
===============================================
*/

// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
#include "I2Cdev.h"

#include "MPU6050_6Axis_MotionApps20.h"
//#include "MPU6050.h" // not necessary if using MotionApps include file

// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    #include "Wire.h"
#endif

// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for SparkFun breakout and InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 mpu;
//MPU6050 mpu(0x69); // <-- use for AD0 high

/* =========================================================================
   NOTE: In addition to connection 3.3v, GND, SDA, and SCL, this sketch
   depends on the MPU-6050's INT pin being connected to the Arduino's
   external interrupt #0 pin. On the Arduino Uno and Mega 2560, this is
   digital I/O pin 2.
 * ========================================================================= */

/* =========================================================================
   NOTE: Arduino v1.0.1 with the Leonardo board generates a compile error
   when using Serial.write(buf, len). The Teapot output uses this method.
   The solution requires a modification to the Arduino USBAPI.h file, which
   is fortunately simple, but annoying. This will be fixed in the next IDE
   release. For more info, see these links:

   http://arduino.cc/forum/index.php/topic,109987.0.html
   http://code.google.com/p/arduino/issues/detail?id=958
 * ========================================================================= */



// uncomment "OUTPUT_READABLE_QUATERNION" if you want to see the actual
// quaternion components in a [w, x, y, z] format (not best for parsing
// on a remote host such as Processing or something though)
//#define OUTPUT_READABLE_QUATERNION

// uncomment "OUTPUT_READABLE_EULER" if you want to see Euler angles
// (in degrees) calculated from the quaternions coming from the FIFO.
// Note that Euler angles suffer from gimbal lock (for more info, see
// http://en.wikipedia.org/wiki/Gimbal_lock)
//#define OUTPUT_READABLE_EULER

// uncomment "OUTPUT_READABLE_YAWPITCHROLL" if you want to see the yaw/
// pitch/roll angles (in degrees) calculated from the quaternions coming
// from the FIFO. Note this also requires gravity vector calculations.
// Also note that yaw/pitch/roll angles suffer from gimbal lock (for
// more info, see: http://en.wikipedia.org/wiki/Gimbal_lock)
#define OUTPUT_READABLE_YAWPITCHROLL

// uncomment "OUTPUT_READABLE_REALACCEL" if you want to see acceleration
// components with gravity removed. This acceleration reference frame is
// not compensated for orientation, so +X is always +X according to the
// sensor, just without the effects of gravity. If you want acceleration
// compensated for orientation, us OUTPUT_READABLE_WORLDACCEL instead.
//#define OUTPUT_READABLE_REALACCEL

// uncomment "OUTPUT_READABLE_WORLDACCEL" if you want to see acceleration
// components with gravity removed and adjusted for the world frame of
// reference (yaw is relative to initial orientation, since no magnetometer
// is present in this case). Could be quite handy in some cases.
//#define OUTPUT_READABLE_WORLDACCEL

// uncomment "OUTPUT_TEAPOT" if you want output that matches the
// format used for the InvenSense teapot demo
//#define OUTPUT_TEAPOT



#define INTERRUPT_PIN 2  // use pin 2 on Arduino Uno & most boards
#define LED_PIN 13 // (Arduino is 13, Teensy is 11, Teensy++ is 6)
bool blinkState = false;

// MPU control/status vars
bool dmpReady = false;  // set true if DMP init was successful
uint8_t mpuIntStatus;   // holds actual interrupt status byte from MPU
uint8_t devStatus;      // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize;    // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount;     // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer

// orientation/motion vars
Quaternion q;           // [w, x, y, z]         quaternion container
VectorInt16 aa;         // [x, y, z]            accel sensor measurements
VectorInt16 aaReal;     // [x, y, z]            gravity-free accel sensor measurements
VectorInt16 aaWorld;    // [x, y, z]            world-frame accel sensor measurements
VectorFloat gravity;    // [x, y, z]            gravity vector
float euler[3];         // [psi, theta, phi]    Euler angle container
float ypr[3];           // [yaw, pitch, roll]   yaw/pitch/roll container and gravity vector

// packet structure for InvenSense teapot demo
uint8_t teapotPacket[14] = { '$', 0x02, 0,0, 0,0, 0,0, 0,0, 0x00, 0x00, '\r', '\n' };



// ================================================================
// ===               INTERRUPT DETECTION ROUTINE                ===
// ================================================================

volatile bool mpuInterrupt = false;     // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
    mpuInterrupt = true;
}



// ================================================================
// ===                      INITIAL SETUP                       ===
// ================================================================

void setup() {
    // join I2C bus (I2Cdev library doesn't do this automatically)
    #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
        Wire.begin();
        Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
    #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
        Fastwire::setup(400, true);
    #endif

    // initialize serial communication
    // (115200 chosen because it is required for Teapot Demo output, but it's
    // really up to you depending on your project)
    Serial.begin(115200);
    while (!Serial); // wait for Leonardo enumeration, others continue immediately

    // NOTE: 8MHz or slower host processors, like the Teensy @ 3.3v or Ardunio
    // Pro Mini running at 3.3v, cannot handle this baud rate reliably due to
    // the baud timing being too misaligned with processor ticks. You must use
    // 38400 or slower in these cases, or use some kind of external separate
    // crystal solution for the UART timer.

    // initialize device
    Serial.println(F("Initializing I2C devices..."));
    mpu.initialize();
    pinMode(INTERRUPT_PIN, INPUT);

    // verify connection
    Serial.println(F("Testing device connections..."));
    Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));

    // wait for ready
    Serial.println(F("\nSend any character to begin DMP programming and demo: "));
    while (Serial.available() && Serial.read()); // empty buffer
    while (!Serial.available());                 // wait for data
    while (Serial.available() && Serial.read()); // empty buffer again

    // load and configure the DMP
    Serial.println(F("Initializing DMP..."));
    devStatus = mpu.dmpInitialize();

    // supply your own gyro offsets here, scaled for min sensitivity
    mpu.setXGyroOffset(220);
    mpu.setYGyroOffset(76);
    mpu.setZGyroOffset(-85);
    mpu.setZAccelOffset(1788); // 1688 factory default for my test chip

    // make sure it worked (returns 0 if so)
    if (devStatus == 0) {
        // turn on the DMP, now that it's ready
        Serial.println(F("Enabling DMP..."));
        mpu.setDMPEnabled(true);

        // enable Arduino interrupt detection
        Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
        attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
        mpuIntStatus = mpu.getIntStatus();

        // set our DMP Ready flag so the main loop() function knows it's okay to use it
        Serial.println(F("DMP ready! Waiting for first interrupt..."));
        dmpReady = true;

        // get expected DMP packet size for later comparison
        packetSize = mpu.dmpGetFIFOPacketSize();
    } else {
        // ERROR!
        // 1 = initial memory load failed
        // 2 = DMP configuration updates failed
        // (if it's going to break, usually the code will be 1)
        Serial.print(F("DMP Initialization failed (code "));
        Serial.print(devStatus);
        Serial.println(F(")"));
    }

    // configure LED for output
    pinMode(LED_PIN, OUTPUT);
}



// ================================================================
// ===                    MAIN PROGRAM LOOP                     ===
// ================================================================

void loop() {
    // if programming failed, don't try to do anything
    if (!dmpReady) return;

    // wait for MPU interrupt or extra packet(s) available
    while (!mpuInterrupt && fifoCount < packetSize) {
        // other program behavior stuff here
        // .
        // .
        // .
        // if you are really paranoid you can frequently test in between other
        // stuff to see if mpuInterrupt is true, and if so, "break;" from the
        // while() loop to immediately process the MPU data
        // .
        // .
        // .
    }

    // reset interrupt flag and get INT_STATUS byte
    mpuInterrupt = false;
    mpuIntStatus = mpu.getIntStatus();

    // get current FIFO count
    fifoCount = mpu.getFIFOCount();

    // check for overflow (this should never happen unless our code is too inefficient)
    if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
        // reset so we can continue cleanly
        mpu.resetFIFO();
        Serial.println(F("FIFO overflow!"));

    // otherwise, check for DMP data ready interrupt (this should happen frequently)
    } else if (mpuIntStatus & 0x02) {
        // wait for correct available data length, should be a VERY short wait
        while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();

        // read a packet from FIFO
        mpu.getFIFOBytes(fifoBuffer, packetSize);
        
        // track FIFO count here in case there is > 1 packet available
        // (this lets us immediately read more without waiting for an interrupt)
        fifoCount -= packetSize;

        #ifdef OUTPUT_READABLE_QUATERNION
            // display quaternion values in easy matrix form: w x y z
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            Serial.print("quat\t");
            Serial.print(q.w);
            Serial.print("\t");
            Serial.print(q.x);
            Serial.print("\t");
            Serial.print(q.y);
            Serial.print("\t");
            Serial.println(q.z);
        #endif

        #ifdef OUTPUT_READABLE_EULER
            // display Euler angles in degrees
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetEuler(euler, &q);
            Serial.print("euler\t");
            Serial.print(euler[0] * 180/M_PI);
            Serial.print("\t");
            Serial.print(euler[1] * 180/M_PI);
            Serial.print("\t");
            Serial.println(euler[2] * 180/M_PI);
        #endif

        #ifdef OUTPUT_READABLE_YAWPITCHROLL
            // display Euler angles in degrees
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetGravity(&gravity, &q);
            mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
            Serial.print("ypr\t");
            Serial.print(ypr[0] * 180/M_PI);
            Serial.print("\t");
            Serial.print(ypr[1] * 180/M_PI);
            Serial.print("\t");
            Serial.println(ypr[2] * 180/M_PI);
        #endif

        #ifdef OUTPUT_READABLE_REALACCEL
            // display real acceleration, adjusted to remove gravity
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetAccel(&aa, fifoBuffer);
            mpu.dmpGetGravity(&gravity, &q);
            mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
            Serial.print("areal\t");
            Serial.print(aaReal.x);
            Serial.print("\t");
            Serial.print(aaReal.y);
            Serial.print("\t");
            Serial.println(aaReal.z);
        #endif

        #ifdef OUTPUT_READABLE_WORLDACCEL
            // display initial world-frame acceleration, adjusted to remove gravity
            // and rotated based on known orientation from quaternion
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetAccel(&aa, fifoBuffer);
            mpu.dmpGetGravity(&gravity, &q);
            mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
            mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &q);
            Serial.print("aworld\t");
            Serial.print(aaWorld.x);
            Serial.print("\t");
            Serial.print(aaWorld.y);
            Serial.print("\t");
            Serial.println(aaWorld.z);
        #endif
    
        #ifdef OUTPUT_TEAPOT
            // display quaternion values in InvenSense Teapot demo format:
            teapotPacket[2] = fifoBuffer[0];
            teapotPacket[3] = fifoBuffer[1];
            teapotPacket[4] = fifoBuffer[4];
            teapotPacket[5] = fifoBuffer[5];
            teapotPacket[6] = fifoBuffer[8];
            teapotPacket[7] = fifoBuffer[9];
            teapotPacket[8] = fifoBuffer[12];
            teapotPacket[9] = fifoBuffer[13];
            Serial.write(teapotPacket, 14);
            teapotPacket[11]++; // packetCount, loops at 0xFF on purpose
        #endif

        // blink LED to indicate activity
        blinkState = !blinkState;
        digitalWrite(LED_PIN, blinkState);
    }
}


Arduino 에 업로드 하여 확인해 봅니다.

Arduino IDE > Tools > Serial Monitor 를 열어서 확인해 봅니다.


Initializing 이 끝나고 준비상태가 되면, 어떤 character 든 보내면 측정이 시작됩니다.



Gyroscope 의 위치값들이 실시간으로 순식간에 측정이 되기 시작합니다.



잘 되네요.




6. Processing

3D 모델링을 통하여 Gyroscope 의 위치가 어떻게 보여지는지를 해봅니다.


다만, 우선 먼저 업로드 했던 sketch 를 조금 바꾸어서 업로드 해 놓을 필요가 있습니다.


- 코멘트 아웃 : #define OUTPUT_READABLE_YAWPITCHROLL

- 코멘트 제거 : #define OUTPUT_TEAPOT


이제 3D 가시화 하기 위해 "Processing IDE" 라는 프로그램을 다운로드 받고 인스톨 합니다.


https://processing.org/download/?processing



사용하는 OS 에 맞는 파일을 다운로드 받고 인스톨 합니다.



이제 Arduino MPU 6050 processing example 을 실행에 필요한 "Toxi" library 를 다운로드 받습니다.


https://bitbucket.org/postspectacular/toxiclibs/downloads/


지금 올라와 있는 최신 버전은 "toxiclibs-complete-0020.zip" 입니다.

다운로드 받으면 processing 폴더의 libraries 안에 copy 합니다.


- Program Files > processing > modes > java > libraries



아래는 copy 완료된 후의 libraries 폴더의 모습.



이제 processing 을 실행시킨 후, Arduino IDE libraries 폴더에 있는 MPU6050 example 에 있는 processing 용 파일을 엽니다.


- Arduino > libraries > MPU6050 > examples > MPU6050_DMP6 > Processing > MPUTeapot > MPUTeapot.pde



이것을 실행하기 전에 마지막으로 port 를 수정합니다.

저는 "COM6" 에 arduino 가 연결되어 있으므로 다음과 같이 수정하였습니다.


- String portName = "COM6";


Linux 의 경우는 "String portName = Serial.list()[0];" 을 활성화 하거나,

"String portName = /dev/ttyUSB0" 등과 같이 직접 기술해 주면 됩니다.



이제 준비는 완료 되었습니다.




7. 3D 결과

Processing 프로그램의 플레이 버튼인 "run" 을 실행시키면 다음 동영상 같이 비행체를 통하여 확인할 수 있습니다.



오오오오오!!! 정말 되었어!

동영상으로 찍어 봤습니다.



신기한 센서를 이용하여 가시화 하니 재미 있네요.




8. 3D object 변경해 보기

못생긴 비행기 모양은 112 ~ 139 라인에서 구현해 놨습니다.

이 모양을 바꾸고 싶으면 이 부분을 수정하면 됩니다.


수정하는 내용은 아래 URL 을 참고하면 되겠습니다.


https://processing.org/tutorials/p3d/


translate(width/2, height/2, 0);
stroke(255);
rotateX(PI/2);
rotateZ(-PI/6);
noFill();

beginShape();
vertex(-100, -100, -100);
vertex( 100, -100, -100);
vertex(   0,    0,  100);

vertex( 100, -100, -100);
vertex( 100,  100, -100);
vertex(   0,    0,  100);

vertex( 100, 100, -100);
vertex(-100, 100, -100);
vertex(   0,   0,  100);

vertex(-100,  100, -100);
vertex(-100, -100, -100);
vertex(   0,    0,  100);
endShape();


적용하면 다음과 같이 변경됩니다. :-)






FIN

주말에 GY-521 센서 가지고 잘 놀았습니다.

향후 드론을 만들게 되면 사용하게 될까요?

And

Hardware | Soil Moisture Sensor 구동해 보기

|

1. 농작물 automation

향후 나이를 먹으면, 농사를 지을 생각입니다.

다만, 전자 기기 경험과 IT 경력을 이용하여 가능한 전자동으로 하고싶습니다.


일조량, 물주기, 항온 항습, 통풍, 영양소 확인 등등...

그 목적을 위해 오늘도 Arduino 를 이용하여 열씸히 놀고 있습니다.


이 농사 automation 에서 토양의 수분 확인은 필수겠죠?

그래서 관련 센서들을 평소 찾아 다녔습니다.




2. Soil Moisture Sensor

네, 맞습니다. 한글로 번역하면 "토양 수분 감지기" 정도가 되겠습니다.

토양에 자동으로 물을 주려면 수분의 level 을 잘 감지해 내야겠죠?


AliExpress 에서 찾아 봅니다.



센서부에 금박이 칠해져 있고, 품질 좋은 것으로 호평받는 RobotDyn 사의 제품이 있습니다.

1.28 USD !!! 배송비 무료. 감사합니닷.




3. 도착

잊고 있었더니만 어느샌가 도착했습니다.



비닐 포장도 깔끔하게 되어 있고, 프린팅도 괜찮습니다.

간만에 괜찮은 품질의 제품을 만난것 같습니다.



개봉한 샷 입니다.



금빛 찬란하군요.





4. Layout

Pin 접속은 다음과 같습니다.


 Soil Moisture Sensor | Arduino Nano
-------------------------------------
          OUT         |     5V
          GND         |     GND
          VCC         |     D2
-------------------------------------


 128X64 OLED | Arduino Nano
----------------------------
     GND     |     GND
     VCC     |     3.3V
     SDA     |     A4
     SDL     |     A5
----------------------------

RobotDyn 제품의 원래 오리지날은 SparkFun 사의 "Soil Moisture Sensor" 일지도 모르겠습니다.


https://learn.sparkfun.com/tutorials/soil-moisture-sensor-hookup-guide


외관이 너무 비슷합니다.

그래서 고맙게도 IDE sketch 를 그대로 가져다 써도 잘 동작합니다.






5. Source

Sketch 는 다음과 같습니다.

OLED 를 붙여서 동작시키게 조금 수정하였습니다.


/*  Soil Mositure Basic Example
    This sketch was written by SparkFun Electronics
    Joel Bartlett 
    August 31, 2015

    Basic skecth to print out soil moisture values to the Serial Monitor 

    Released under the MIT License(http://opensource.org/licenses/MIT)
*/

#include "SPI.h"
#include "Wire.h"
#include "Adafruit_GFX.h"
#include "Adafruit_SSD1306.h"
#include "stdint.h"
 
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);


int val = 0; // value for storing moisture value 
int soilPin = A0; // declare a variable for the soil moisture sensor 
int soilPower = 7; // variable for Soil moisture Power

// rather than powering the sensor through the 3.3V or 5V pins, 
// we'll use a digital pin to power the sensor. This will 
// prevent corrosion of the sensor as it sits in the soil. 

void setup() {
	Serial.begin(57600); // open serial over USB
	
	pinMode(soilPower, OUTPUT); // set D7 as an OUTPUT
	digitalWrite(soilPower, LOW); // set to LOW so no power is flowing through the sensor
	display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
}

void loop() {
	// get soil moisture value from the function below and print it
	int result = readSoil();
	Serial.print("Soil Moisture = ");    
	Serial.println(result);

	// clear the buffer
	display.clearDisplay();
	
	// text display tests
	display.setTextSize(2);
	display.setTextColor(WHITE);
	display.setCursor(0,0);
	display.print("Soil\n");
	display.print("Moisture\n");
	isplay.print("\n  == ");
	display.print(result);
	
	display.display();

	// this 1 second timefrme is used so you can test the sensor and see it change in real-time.
	// for in-plant applications, you will want to take readings much less frequently.
	delay(1000); // take a reading every second
}

// this is a function used to get the soil moisture content
int readSoil() {
	digitalWrite(soilPower, HIGH); // turn D7 "On"
	delay(10); // wait 10 milliseconds 
	val = analogRead(soilPin); // read the SIG value form sensor 
	digitalWrite(soilPower, LOW); // turn D7 "Off"
	return val; // send current moisture value
}


출처는 SparkFun 사의 위의 사이트 입니다.




6. 동작 확인

Pin 을 연결하고 sketch 를 업로드 한다음 제대로 동작하는지 확인해 봅니다.



화분에 물주고 확인해야 하는데, 일이 커지므로 손기운으로 측정으로 해봅니다.

잘 되네요!!!



실측값을 토대로 실제로 흙속에 넣고 해봐야겟지만, 동작확인이 되었으니 충분합니다.


아마 흙속에 계속 넣고 있으면, 금박 등이 다 삵아서 제대로 동작되지 않겠죠?

지속적인 사용은 못할 듯 합니다.

실제 농작물 automation 에 사용하려면 수분이 직접 닫지 않고도 측정되는 센서가 필요할 듯 합니다.


동영상도 한번 찍어봤습니다.


간단하게 잘 동작하네요.




FIN

아~ 나의 농작 automation~!!!

And

Hardware | DS18B20 온도센서

|

1. 온도 센서

지금까지 온도센서를 4개 구동시켜 봤습니다.


* Hardware | AM2322 Temperature & Humidity Sensor

http://chocoball.tistory.com/entry/Hardware-AM2322-Temperature-Humidity-Sensor


* Hardware | Arduino 비접촉 온도센서 GY-906 MLX90614

http://chocoball.tistory.com/entry/HardwareArduinoMLX90614


* Hardware | Arduino BMP280 고도/온도/기압 센서

- http://chocoball.tistory.com/entry/HardwareArduinoBMP280


* Hardware | BME280 sensor

- http://chocoball.tistory.com/entry/HardwareBME280


온도라는 것은 생물이 살아가는 지구 환경의 특성을 나타내주는 중요한 바로메터 이기 때문에

시장에는 사용 용도에 따라서 여러 센서가 존재하는 듯 합니다.


이제 5번째 센서를 구동시켜보기로 합니다.




2. 수온 측정용 온도센서

물의 온도를 측정하기 위해서는 방수가 되어야 합니다.

알루미늄 방수캡으로 커버된 온도센서가 "DS18B20" 입니다.


원래는 아래 그림처럼 Dallas사에서 만든 세발달린 칩으로 되어 있습니다.



그것을 알루미늄 캡과 고무로 실링을 한 제품입니다.



데이터쉬트는 다음과 같습니다.


DS18B20.pdf


사양을 보면, 중간에 저항을 넣어줘야 하는 군요.

센서가 타버리지 않게 꼭 저항을 챙기도록 합니다.





3. 주문

오늘도 AliExpress 에서 구매합니다.


https://ko.aliexpress.com/item/1pcs-DS18B20-Stainless-steel-package-1-meters-waterproof-DS18b20-temperature-probe-temperature-sensor/32467815969.html





4. Layout

데이터쉬트에 표기되어 있듯이 "저항"을 꼭 챙기도록 합니다.



Datasheet 를 보면 3~5V 에서 구동한다고 되어 있으므로, Arduino Nano 에서는 3.3V 단자에 연결했습니다.


  DS18B20 | Arduino Nano
------------------------------
   Black  |     GND
    Red   |     3.3V (4.7k Ohms)
   White  |     D2 (4.7k Ohms)
------------------------------


빵판 모습은 다음과 같습니다.



Pullup 저항도 달아 줍니다. 이 pullup 저항이 왜 중요한지는 이 글의 마지막에 적어 놨습니다.

AliExpress 에서 구매한것 치고 4.7k Ohms 는 꽤나 정확하네요.



미지근한 물, 냉장고의 물, 급탕기로 뎁힌 뜨거운 물을 준비합니다.

자, 이제 준비 완료 입니다.







5. IDE Sketch

유명한 센서라서 여러 사이트에서 소개되고 있습니다.


가장 간단한 스케치는 다음과 같습니다.

https://create.arduino.cc/projecthub/TheGadgetBoy/ds18b20-digital-temperature-sensor-and-arduino-9cc806


- OneWire Library : https://github.com/PaulStoffregen/OneWire

- DallasTemperature Library : https://github.com/milesburton/Arduino-Temperature-Control-Library


/********************************************************************/
// First we include the libraries
#include <OneWire.h>
#include <DallasTemperature.h>
/********************************************************************/
// Data wire is plugged into pin 2 on the Arduino
#define ONE_WIRE_BUS 2
/********************************************************************/
// Setup a oneWire instance to communicate with any OneWire devices 
// (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
/********************************************************************/
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
/********************************************************************/
void setup(void)
{
 // start serial port
 Serial.begin(9600);
 Serial.println("Dallas Temperature IC Control Library Demo");
 // Start up the library
 sensors.begin();
}
void loop(void)
{
 // call sensors.requestTemperatures() to issue a global temperature
 // request to all devices on the bus
/********************************************************************/
 Serial.print(" Requesting temperatures...");
 sensors.requestTemperatures(); // Send the command to get temperature readings
 Serial.println("DONE");
/********************************************************************/
 Serial.print("Temperature is: ");
 Serial.print(sensors.getTempCByIndex(0)); // Why "byIndex"? 
   // You can have more than one DS18B20 on the same bus. 
   // 0 refers to the first IC on the wire
   delay(1000);
}



cactus.io 에서 제품 자체의 시리얼 넘버까지 친절하게 보여주는 소스는 다음과 같습니다.

http://cactus.io/hookups/sensors/temperature-humidity/ds18b20/hookup-arduino-to-ds18b20-temperature-sensor


"cactus_io_DS18B20.h" 라이브러리는 다음 링크에서 다운받으면 됩니다.

cactus_io_DS18B20.zip


/* Example sketch for Maxim Integrated DS18B20 temperature sensor Written by cactus.io, and requires the cactus_io_DS18B20 library. This sketch was tested using the Adafruit Prewired DS18B20 Sensor. For hookup details using this sensor then visit http://cactus.io/hookups/sensors/temperature-humidity/ds18b20/hookup-arduino-to-ds18b20-temperature-sensor */ #include <cactus_io_DS18B20.h> int DS18B20_Pin = 2; //DS18S20 Signal pin on digital 2 // Create DS18B20 object DS18B20 ds(DS18B20_Pin); void setup() { ds.readSensor(); Serial.begin(9600); Serial.println("Maxim Integrated DS18B20 Temperature Sensor | cactus.io"); Serial.println("DS18B20 Serial Number: "); // we pass the serial number byte array into the printSerialNumber function printSerialNumber(ds.getSerialNumber()); Serial.println(""); Serial.println(""); Serial.println("Temp (C)\tTemp (F)"); } void loop() { ds.readSensor(); Serial.print(ds.getTemperature_C()); Serial.print(" *C\t"); Serial.print(ds.getTemperature_F()); Serial.println(" *F"); // Add a 2 second delay. delay(2000); } // We call this function to display the DS18B20 serial number. // It takes an array of bytes for printing void printSerialNumber(byte *addr) { byte i; for( i = 0; i < 8; i++) { Serial.print("0x"); if (addr[i] < 16) { Serial.print('0'); } Serial.print(addr[i], HEX); if (i < 7) { Serial.print(", "); } } }




6. 결과

실제로 "실내 공기 > 미지근한 물 > 냉장고의 차가운 물 > 급탕기로 뎁힌 물" 을 차례로 측정한 온도 변화 입니다.



동영상으로도 찍어 봤습니다.



전체 과정은 아래 동영상 입니다.



잘 되네요!




7. 주의

처음에 GND 와 VCC를 서로 바꿔 연결했더니만, 온도센서쪽이 불덩이가 되었습니다.

잠깐 만지기만 해도 손이 데일 정도였으니, 100도이상 순식간에 올라갔던 것 같습니다.


다행이 식힌 다음 제대로 연결했더니 센서 동작에는 문제가 없었습니다.

다른 센서들은 핀 연결을 잘못해도 문제가 생길 여지가 없는데, 이 센서는 왜 pullup 저항을 달아 놓는지 조금 이해가 갈 것 같습니다.




FIN

5개째 온돈세서 구동기였습니다.

더이상 다른 온도 센서는 없겠지?


And

Hardware | Arduino 의 Sensor Shield 사용해 보기

|

1. 가위손

Arduino 를 하면서 빵판에 선을 꼽고 있으면 스파게티가 됩니다.


이를태면 이런거거죠.


- 출처 : http://anycpu.org/forum/viewtopic.php?t=143




2. Sensor Shield

하나의 Arduino nano 에 여러 센서들을 연결하게 되면, GND / 5V 를 여러 센서들이 공유해서 사용해야 해서

다음과 같은 문제가 발생할 수 있습니다.


- 선이 복잡해 진다

- 전원의 전압 강하될 가능성이 있다

- Arduino 의 전력부에 부하를 준다


등의 문제가 될 수 있겠습니다.


이를 해결하기 위한 쉴드가 다음 사진 입니다.



Arduino nano 전용 sheild 입니다.




3. 주문

Aliexpress 에서 주문합니다.


- URL : https://ko.aliexpress.com/item/For-Arduino-Nano-V3-0-Prototype-Shield-I-O-Extension-Board-Expansion-New-Module/32459623962.html




eBay 에서는 약 3~9 USD 정도 합니다.

그럼 Aliexpress 에서도 찾아 봅니다.


1.12 USD 에 무료 배송... 갓알리 입니다.




4. 도착

도착후 샷 입니다.

메뉴얼은 없고 단순히 보드 하나만 있습니다.



뒷면입니다.

Deek-Robot / DK-NANO-003 V3.0 이라고 적혀 있습니다.





5. 체결

결합전 샷 입니다.



합체 ~~!!!



전원 인가 모습.

잘 동작되는 것 같습니다.





6. 사양

Aliexpress 에서는 clone 제품을 많이 팔지만, 메뉴얼이나 자세한 설명은 없습니다.


어떤 전원을 꼽아야 하는지 알지 못하여 Googling 하였습니다.

완전히 같은 제품은 아니지만, 구성품이 거의 동일하여 동일한 사양일 듯 합니다.


Keyes - Funduino Uno and Nano Multi Purpose Shield V3.pdf




입력은 7~12V 사이가 적정하네요.




7. 연결해 보기

Servo 모터 두개를 달고 있는 Gimbal 미조립품이 있습니다.

이는 Kickstarter 에서 펀딩하고 받은 prototype 입니다.


- Servo 소개 글 : http://chocoball.tistory.com/entry/Hardware-Arduino-Servo


이 Gimbal 에는 두개의 Servo 모터가 들어갑니다.

각 Servo 모터는 5V / GND 와 digital pin 하나가 필요합니다.


이번에 구입한 Sensor Shield를 이용하여 간단하게 연결해 볼까요?



사진에서 보이듯, 각 signal pin 에 GND / 5V 핀이 바로 옆에 있어

배선이 깔끔해 집니다.


두개의 Servo 를 연결했을 때의 사진 입니다.

깔끔하죠?!!!



전원을 넣으면 각 pin 을 통해 5V 전원도 인가되고 GND 도 동작합니다.

그래서 각 센서에서 Arduino 의 5V / GND 에 따로 연결할 필요가 없습니다.


전원 인가하니 잘 동작 합니다.


동시에 두개의 Servo 를 구동시킨 동영상 입니다.



좋네요 !!!




FIN

OLDE / 여러 Sensor / Motor 등을 하나의 Arduino 로 제어하고 싶을 때, 배선이 깔끔해 지겠습니다.

다른것도 해봐야지.

And

Hardware | YF-S201 water flow sensor 가지고 놀기

|

1. 이런 센서도 있네?

향후 집도 짓고 배관 시설도 공사도 해야 해서 "Water Flow Sensor" 를 익힐 필요가 있습니다.


...라는건 뻥이구요 (집 짓는게 장래 희망은 사실), Arduino 로 할 수 있는 센서는 어떤게 있을까 찾아 봤습니다.

"Water Flow Sensor" 라는게 있네요.


쓰임새는 액체가 흐르는 파이프에 설치하여 흐르는 양을 검출할 수 있는 센서 입니다.

요런거죠.





2. 구입

역시 Aliexpress 에서 구입 했습니다.

없는게 없죠?


https://ko.aliexpress.com/item/Water-flow-sensor-flowmeter-Hall-flow-sensor-Water-control-1-30L-min-2-0MPa-YF-S201/32583680601.html



3천원 미만으로 무료 배송이면 괜찮츄?




3. 도착 및 분해

도착 기념 샷 입니다.

구성은 단순하네요.



뒷면을 보니 흐르는 방향이 표시되어 있습니다.



내부가 궁금해 졌습니다.

나사 4개가 너무 눈에 띄게 만들어 졌네요. 분리해 봅니다.



물이 들어갈까봐 고무 패킹에 잘 둘러쌓여 있습니다.



호스 부분은 프로펠러가 달려 있어서 회전하게 되어 있습니다.

회전축에 자석같은게 붙어 있어서, 이 부분이 상판 회로의 센서와 hall effect 를 검출하는 것 같습니다.



상판 회로는 잘 분리되어 있습니다.




4. Layout

Pin 연결은 다음과 같습니다.


  YF-S201 | Arduino Nano
-------------------------
  Red     |      5V
  Black   |      GND
  Yellow  |      D2
-------------------------



Hall effect 를 이용한 센서라고 하는데, 전자기를 이용한 방식인 듯 합니다.

그래서 그런지 digital 단자와 연결됩니다.


Hall effect 는 다음 Wikipedia 를 참고해 보세요.

https://en.wikipedia.org/wiki/Hall_effect




5. Source

Code 는 다음과 같습니다.


출처는 아래 link 입니다.

https://diyhacking.com/arduino-flow-rate-sensor/

Code 소스는 아래 link 입니다.

http://diyhacking.com/projects/FlowMeterDIY.ino


/*
Liquid flow rate sensor -DIYhacking.com Arvind Sanjeev

Measure the liquid/water flow rate using this code. 
Connect Vcc and Gnd of sensor to arduino, and the 
signal line to arduino digital pin 2.
 
 */

byte statusLed    = 13;

byte sensorInterrupt = 0;  // 0 = digital pin 2
byte sensorPin       = 2;

// The hall-effect flow sensor outputs approximately 4.5 pulses per second per
// litre/minute of flow.
float calibrationFactor = 4.5;

volatile byte pulseCount;  

float flowRate;
unsigned int flowMilliLitres;
unsigned long totalMilliLitres;

unsigned long oldTime;

void setup()
{
  
  // Initialize a serial connection for reporting values to the host
  Serial.begin(38400);
   
  // Set up the status LED line as an output
  pinMode(statusLed, OUTPUT);
  digitalWrite(statusLed, HIGH);  // We have an active-low LED attached
  
  pinMode(sensorPin, INPUT);
  digitalWrite(sensorPin, HIGH);

  pulseCount        = 0;
  flowRate          = 0.0;
  flowMilliLitres   = 0;
  totalMilliLitres  = 0;
  oldTime           = 0;

  // The Hall-effect sensor is connected to pin 2 which uses interrupt 0.
  // Configured to trigger on a FALLING state change (transition from HIGH
  // state to LOW state)
  attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
}

/**
 * Main program loop
 */
void loop()
{
   
   if((millis() - oldTime) > 1000)    // Only process counters once per second
  { 
    // Disable the interrupt while calculating flow rate and sending the value to
    // the host
    detachInterrupt(sensorInterrupt);
        
    // Because this loop may not complete in exactly 1 second intervals we calculate
    // the number of milliseconds that have passed since the last execution and use
    // that to scale the output. We also apply the calibrationFactor to scale the output
    // based on the number of pulses per second per units of measure (litres/minute in
    // this case) coming from the sensor.
    flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;
    
    // Note the time this processing pass was executed. Note that because we've
    // disabled interrupts the millis() function won't actually be incrementing right
    // at this point, but it will still return the value it was set to just before
    // interrupts went away.
    oldTime = millis();
    
    // Divide the flow rate in litres/minute by 60 to determine how many litres have
    // passed through the sensor in this 1 second interval, then multiply by 1000 to
    // convert to millilitres.
    flowMilliLitres = (flowRate / 60) * 1000;
    
    // Add the millilitres passed in this second to the cumulative total
    totalMilliLitres += flowMilliLitres;
      
    unsigned int frac;
    
    // Print the flow rate for this second in litres / minute
    Serial.print("Flow rate: ");
    Serial.print(int(flowRate));  // Print the integer part of the variable
    Serial.print(".");             // Print the decimal point
    // Determine the fractional part. The 10 multiplier gives us 1 decimal place.
    frac = (flowRate - int(flowRate)) * 10;
    Serial.print(frac, DEC) ;      // Print the fractional part of the variable
    Serial.print("L/min");
    // Print the number of litres flowed in this second
    Serial.print("  Current Liquid Flowing: ");             // Output separator
    Serial.print(flowMilliLitres);
    Serial.print("mL/Sec");

    // Print the cumulative total of litres flowed since starting
    Serial.print("  Output Liquid Quantity: ");             // Output separator
    Serial.print(totalMilliLitres);
    Serial.println("mL"); 

    // Reset the pulse counter so we can start incrementing again
    pulseCount = 0;
    
    // Enable the interrupt again now that we've finished sending output
    attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
  }
}

/*
Insterrupt Service Routine
 */
void pulseCounter()
{
  // Increment the pulse counter
  pulseCount++;
}



6. 측정

당장 물 호스를 연결할 수가 없어, 입으로 바람을 불어 봅니다.

잘 되네요 !!!



Serial Monitor 로 결과를 보면 아래와 같습니다.

신기하게 잘 잡힙니다.



Flow rate / 흐르는 양 / 총량을 계산해 줍니다.

원작자가 소스코드를 잘 짜신것 같습니다.




FIN

이제 집만 지으면 될 것 같습니다.

And

Hardware | HC-SR501 PIR motion sensor

|

1. 시작하기

Motion sensor 를 이용하여, 사람을 감지하는 모듈을 만들어 보고싶었습니다.

오늘은 기본 구동 확인만 해 봅니다.


역시 구입은 AliExpress 죠!

이게 어떻게 1000원정도로 구입할 수 있는지, 감사할 따름입니다.



원리는 이렇다고 합니다.



Datasheet 입니다.

HC-SR501-PIR-Sensor-Datasheet.pdf



2. 외관

도착한 센서를 찍어 봤습니다.



커버 안에 센서가 보입니다.

커버를 통하여 넓은 범위를 커버하기 위함이라 합니다.





뒷면




3. 참고

보드를 보면 부품 실장이 되지 않은 부분이 있습니다.



바로 Photoresistor socket 과 Thermistor socket 입니다.

Photoresistor 를 실장하면, 동작하는 조건을 낮/밤 구분해서도 할 수 있을것 같습니다.


좀더 찾아보니, Photoresistor 를 같이 파는 사이트도 있는걸 보니, 실 구동도 가능해 보입니다.



Photoresistor 는 GL5528 이라는 규격을 사용하면 되겠네요.

다른 규격들을 살펴 보면, Ligth Resistance 와 Dark Resistance 가 다르네요.

나중에 기회되면 Photoresistor 를 추가하여 구축해보겠습니다.



Photoresistor 의 datasheet 입니다.

GL55 Series Photoresistor.pdf


Thermistor 에 대한 정보는 찾을 수가 없었습니다.

뭔가 알게되면 update 할께요.


또한, jumper 를 이용하여 모드를 변경할 수 있습니다.

여러 회사에서 제조되는 관계로 이 jumber 부분에 pin 이 실장되지 않는 제품들도 있더군요.

다행히 제가 구매한 제품은 점퍼가 살장되어 있었습니다.



Sensitivity 와 Time Delay 조정은 다음과 같이 합니다.






4. Sketch

회로 구성 및 정보는 아래 사이트를 참고하였습니다.

http://henrysbench.capnfatz.com/henrys-bench/arduino-sensors-and-input/arduino-hc-sr501-motion-sensor-tutorial/


Pin 배열 정보 입니다.

HC-SR501 PIR sensor | Arduino Nano
----------------------------------
         S          |     D8
         +          |     5V
         -          |     GND
----------------------------------

    Piezo busser    | Arduino Nano
----------------------------------
         S          |     D11
         +          |     5V
         -          |     GND
----------------------------------

Sketch 정보입니다. 여기저기 source 보고 짜집기 했습니다.

/*******************************************************

Uses a PIR sensor to detect movement, sounds a buzzer

*******************************************************/
//the time we give the sensor to calibrate (10-60 secs according to the datasheet)
int calibrationTime = 30;

int ledPin = 13; // choose the pin for the LED
int inputPin = 8; // choose the input pin (for PIR sensor)
int pirState = LOW; // we start, assuming no motion detected
int val = 0; // variable for reading the pin status
int pinSpeaker = 11; //Set up a speaker on a PWM pin (digital 9, 10, or 11)

void setup() {
pinMode(ledPin, OUTPUT); // declare LED as output
pinMode(inputPin, INPUT); // declare sensor as input
pinMode(pinSpeaker, OUTPUT);

//give the sensor some time to calibrate
Serial.begin(9600);
Serial.print("Calibrating sensor ");
  for(int i = 0; i < calibrationTime; i++) {
    Serial.print(".");
    delay(1000);
  }
  Serial.println(" Done!");
  Serial.println("SENSOR is ACTIVE now");
  delay(50);
}

void loop() {
  val = digitalRead(inputPin); // read input value
  if (val == HIGH) { // check if the input is HIGH
    blinky(); // blink LED when motion haas been detected
    // digitalWrite(ledPin, HIGH); // turn LED ON
    playTone(300, 160);
    delay(150);
    
    if (pirState == LOW) {
    // we have just turned on
      Serial.println("Motion detected!");
      // We only want to print on the output change, not state
      pirState = HIGH;
    }
  } else {
    digitalWrite(ledPin, LOW); // turn LED OFF
    playTone(0, 0);
    delay(300);

    if (pirState == HIGH){
    // we have just turned off
      Serial.println("Motion ended!");
      // We only want to print on the output change, not state
      pirState = LOW;
    }
  }
}

void playTone(long duration, int freq) {
  // duration in mSecs, frequency in hertz
  duration *= 1000;
  int period = (1.0 / freq) * 1000000;
  long elapsed_time = 0;

  while (elapsed_time < duration) {
    digitalWrite(pinSpeaker,HIGH);
    delayMicroseconds(period / 2);
    digitalWrite(pinSpeaker, LOW);
    delayMicroseconds(period / 2);
    elapsed_time += (period);
  }
}

void blinky() {
  for(int i=0; i<3; i++) {
    digitalWrite(13, HIGH);
    delay(200);
    digitalWrite(13, LOW);
    delay(200);
  }
}

빵판 구성입니다.



실제 구동하면서 Serial Monitor 입니다.



잘 동작합니다. 소리도 잘 나네요.



5. 실제 구성

실제 구성샷 입니다.




구동 동영상 입니다.





FIN

이제 뭘하지?


And

Hardware | Arduino water level sensor

|

1. 시작하기

어항을 시작하면서 물 수위에 대한 자도 조절 기능을 만들고 싶었습니다.

물론 부레가 달린 물탱크를 사용하면 수위가 내려가면 자동으로 물 충전을 시켜주기는 하지만,

뭔가 전자적으로 만들고 싶습니다.



또한, IoT 하면 수위 변동시 alert 등도 스마트폰으로 알람을 띄워 줄 수 있겠죠.


여기선, 우선 단순 구동 확인만 해보겠습니다.



2. 구입하기

AliExpress 에서 "water sensor" 를 검색하면 아래와 같은 센서가 보입니다.

구입합니다.



실제 사진입니다.



뒷면





3. layout

Pin은 다음과 같이 연결합니다.

Water Level Sensor | Arduino Nano
---------------------------------
         S         |     A0
         +         |    3.3V
         -         |     GND
---------------------------------


빵판 layout



실제 연결한 장면입니다.




4. sketch

/*Code for Liquid Level Sensor Circuit Built with an Arduino*/

const int sensorPin= 0; //sensor pin connected to analog pin A0
int liquid_level;

void setup() {
Serial.begin(9600); //sets the baud rate for data transfer in bits/second
pinMode(sensorPin, INPUT); //the liquid level sensor will be an input to the arduino
}

void loop() {
liquid_level= analogRead(sensorPin); //arduino reads the value from the liquid level sensor
Serial.println(liquid_level); //prints out liquid level sensor reading
delay(100); //delays 100ms
}


5. 측정

구동 잘 되고, 물컵 이용하여 측정해 봤습니다.



센서 끝부터 물에 담구면 수치가 변하는 것을 볼 수 있습니다.



센서 끝단은 측정치가 많이 올라가고 (0~200), 그 위에는 (200~400) 천천히 올라갑니다.

일정한 피치로 측정이 될려면 좀더 정확한 sensor 를 구입해야 할 듯 합니다.



한가지 좋은 점은 작은 LED 가 있어서, 구동중이라는 것을 보여주는 것 정도?



FIN

이제 뭘하지?


And
prev | 1 | 2 | next