반응형

【 아두이노모듈#30】 #1.기울기 센서(6축 가속도&자이로)에 대해 알아봅시다. 

【 기울기 센서 개요 】

자이로 센서(Gyro Sensor)의 원리는  자이로스코프가 내장된 물체가 회전 운동을 하면 생기는 회전 반발력을 측정하여 전기신호로 바꾸어 출력하고 이를 수치화하여 활용하게 됩니다.  그래서 기울기 센서는 가속도 센서와 자이로 센서의 기능을 통합하여 자세나 위치를 추정할 수 있는 장치를 말하며,  이를 활용한 항공기 및 배(Ship) 등에 사용되는 관성항법장치(INS)는 이동거리와 방향까지 추정할 수 있도록 되어 있습니다.

▶ 주요 활용분야 :

센서 주요활용분야: 드론/AR스마트안경/VR고글/나인봇/핏빗, 미밴드/스마트워치/전자수평계 등

 - 드론 : 비행 중인 드론은 현재의 기울기나 위치 파악은 물론이며,  특정 위치에서의 고정 비행을 할 경우 바람 등으로 인하여 원래의 위치와 자세를 유지하는 기능이 필요한데, 가속도 센서와 자이로 센서가 각각 중력가속도와 각속도를 측정하여 얼마나 기울어졌는지를 파악하여 보정할 수 있도록 해줍니다. 
 - VR/AR :  대표적 VR제품인 오큘러스 고글이나 구글 스마트 안경과 같은 AR 제품의 경우 사용자의 머리(얼굴 방향) 움직임이 있을 경우 자이로 센서를 이용하여 회전을 인식하거나 물체와의 위치를 파악하게 해주는 등의 중요한 역할을 합니다.
- 세그웨이나 나인봇 : 사람의 몸이 기울이는 정도와 방향에 따라 세그웨이/나인봇을 제어할 수 있도록 하는 곳에 자이로(가속도) 센서가 사용됩니다.
- 운동 관련 웨어러블 기기인 핏빗이나 샤오미 밴드 , 스마트 워치 등에서 사람의 움직임 등을 파악하기 위해 사용됩니다. 
 이처럼, 기울기 센서(가속도/자이로 센서)는 다양한 곳에 활용되는데요,  대표적으로 많이 사용되는 GY-521(MPU6050) 모듈을 아두이노를 통하여 학습해 본다면,  이후 아두이노와 함께 다양한 응용 작품을 만드는데 좋은 기회가 될 것으로 생각됩니다 ^^.   
라즈이노 IoT에서는 앞으로 몇 회차에 걸쳐 기울기 센서 모듈을 이용해서 흥미로운 학습과제를 진행할 예정입니다. 
본 페이지에서는 GY-521 모듈의 스펙과 기본 사용법에 관련된 학습이 진행됩니다. 

《 GY-521 모듈(MPU-6050 6축-자이로 가속도 센서) 》

GY-521 기울기 센서 앞·뒷면 모습

IMU-6040 기울기 센서 모듈의 동작원리에 대한,  간략한 설명을 드리면, 
센서 이름에 있는 IMU의 뜻은 Inertial Measurement Unit의 약어로, 관성 측정 장치라는 뜻이 있으며,
IMU-6040 모듈에는 X, Y, Z의 3축 가속도 센서와, 3축 자이로 센서, 온도 센서로 구성되어 있습니다. 온도 센서는 가속도 자이로 값이 급격한 온도 변화에 영향을 받을 경우 적용하기 위해 있는 센서로 일반적인 환경하에서는 적용하지 않고 사용하게 됩니다.

기울기는, 자이로 스코프(Gyroscope)로 측정이 가능하며, 가속도 센서로도 측정 가능합니다. 두 가지가 함께 있는 이유는 서로의 단점이 존재하는데, 이를 보완하기 위함이라고 보시면 됩니다. "자이로 스코프"에는 MEMS Gyroscope 라는 칩, 시스템 혹은 센서라고 하는 것이 들어 있습니다.

MEMS 뜻은 "Micro Electro Mechanical System"의 약어로,  MEMS 센서는 칩이 회전 또는 기울어질 때 전압을 출력 시킵니다. 기울어지는 정도에 따라 비례해서 전압값이 다르게 출력됩니다.

이 전압은 칩 내부에서 16bit ADC 컨버터(아날로그 전압을 디지털 숫자 값으로 변환하는)에 의해 16비트(0 ~ 2의 16승 값 범위)값으로 변환 되고, 이 값을 가지고 아두이노 라이브러리와 프로그래밍 코드에서 처리하여 각도 값으로 변환해서 보여주게 됩니다.

 그리고 MPU-6050에는 Accelerometer(가속도 계)라는 측정 센서가 있습니다. 역시, X, Y, Z 3개의 축으로 구성 되어 있으며, 조금 설명하기 쉽게, 어떤 박스 안에 무게가 있는 둥근 공이 있을 때, -X ↔ 공 ↔ +X 예를 들어, X축을 기준으로 -X축 방향으로 박스를 빠르게 밀었을 때, 공은 제자리에 머물러 있게 되는데, 이는 관성에 의해 +X축 방향으로 이동한 것으로 볼 수 있습니다. 센서에서는 이런 움직임에 대해 각 축 별로 전압으로 측정해 내게 되고, 자이로 센서의 경우처럼, 이를 수치 값으로 변환하여 코드에서 기울기 값 등으로 처리 할 수 있게 됩니다.

 MPU-6050은 위 이미지에서 가운데 정사각형의 IC칩 명칭이며, 이 칩을 이용해서 만든 모듈 이름이 GY-521입니다. 따라서 같은 MPU-6050 칩을 사용한 다른 모델 제품도 있을 수 있으며, 경우에 따라 핀 배열이 다를 수 있습니다. 
하지만 GY-521 모듈이 대표적으로 많이 사용되고 있습니다. 

 MPU-6050은 6축의 자유도(DOF : Degree of Freedom)를 가지며,  3축(x, y, z) 가속도계와 3축(x,y,z) 자이로를 합하여 6 축이라고 하며,  또는 3축 가속도+자이로 2축+온도 1축을 합하여 6축이라고도 합니다. (온도 센서가 포함된 이유는 가속도와 자이로 값이 온도에도 영향을 받기 때문에 온도센서를 활용하면 온도 변화에도 대응하는 값을 얻을 수 있기 때문입니다)   여기에,  지자기(지구자기) 센서의 3축을 추가한 모델이 MPU-9060 ,  9축 센서입니다.  9축 센서를 이용하면 3차원의 위치(지구 상 공간)와 3차원의 방향을 모두 파악할 수 있게 됩니다. 

 - 가속도 센서는 시간에 대한 속도 변화의 비율을 말하는 데요,  중력가속도를 이용하여 가속도를 측정하게 됩니다. 
중력 가속도가 3개의 축 각각에 얼마만큼의 영향을 주었는지를 측정하여 센서의 기울어진 정도를 파악할 수 있게 됩니다.  다만, 가속도 센서의 경우 움직이는 동적인 물체에서는 가속도와 중력이 섞여서 검출되기 때문에 정확한 데이터를 얻기가 힘듭니다,  따라서 정적인 상태에서만 정확한 기울기를 측정할 수 있는 한계가 있습니다. 
 
 - 자이로 센서는 물체의 회전 속도인 '각속도'를 이용하는 센서이기 때문에 각속도 센서라고도 합니다. 역시 3축의 물리량을 측정하여 센서의 움직임을 감지하고 기울기를 측정할 수 있는데요, 동적인 상황에서 가속도 센서에 비해 비교적 안정적인 값이 출력되지만 각도를 계산하는 과정에서 적분 방식을 사용하기 때문에 시간이 지날수록 누적되는 오차가 발생합니다. 

※ 따라서, 가속도 센서와 자이로 센서의 장점을 적절하게 적용하여 코드를 구성한다면 보다 정밀한 결과를 얻을 수 있습니다.   그러므로 센서를 적용하려는 형태와 방법에 따라 코드가 심플해지기도 하며, 외부 라이브러리 사용과 함께 아주 복잡해지기도 합니다.

  바로 위 '6050칩 이미지'를 보면, 직선방향의 화살표가 향하는 방향이 x, y, z 축의 가속도 센서가 적용되는 방향입니다.
  ( 센서를 통해 얻을 수 있는 RAW 데이터 파일 값 중에서 화살표 방향이 +값으로 표시된다면,  화살표 반대방향으로 움직일 시, -(마이너스) 값으로 표시됩니다.   좀 더 정확히 얘기하자면,  중력의 방향을 기준으로 잡고,  중력의 방향은 - , 중력의 반대 방향이 +입니다.  )
 그리고 회전하는 모양의 화살표가 x, y, z 축의 자이로 센서가 적용되는 방향입니다. 
 (마찬가지로,  화살표 방향으로의 회전 일 때 +값이 얻어진다면,  반대 방향으로의 회전 시, -(마이너스) 값이 얻어집니다.  회전 방향에 대한 + 방향은 위 이미지를 참고하세요)
그리고,  이 회전 방향은 특히 드론과 같은 비행체나 배와 같은 곳에 필수적으로 적용이 되는데요,   이 센서가 있어야, 기울기/자세를 유지하거나 보정할 수 있기 때문입니다. 
X축 회전 각도를 Roll (롤)  ,  Y축 회전 각도를 Pitch(피치) ,  Z 축 회전 각도는 Yaw(야우)라고 불립니다. 

 

★ 기억하기 쉽도록 :   사람 머리를 기준으로 
   -  Roll 은  →  고개를 좌우로 갸우뚱갸우뚱 
   -  Pitch는  →  고개를 앞뒤로 끄덕끄덕
   -  Yaw는  →  고개를 도리 도리

그럼, MPU6050 칩의 상세 스펙과 MPU6050을 내장한 GY-521 모듈에 대해 본격적으로 살펴볼게요.

【 기울기 센서 MPU6050 스팩 】

 전원 사용은 일반적으로 5V를 입력하지만, 3V~5V 사이의 전원은 모두 동작하므로, 3.3V 전원을 사용하는 다른 모듈들과 함께 3.3V 전원 연결도 자주 이용됩니다

 보시는 바와 같이 MPU6050 I2C 인터페이스를 이용한 통신으로 측정값을 얻어낼 수 있습니다. 일반적으로 모듈로부터 데이터를 얻기 위해 SCL SDA 핀을 이용(모듈이 슬레이브로 동작)  합니다.  좀더 구체적으로 설명하자면, I2C는 필립스에서 개발한 직렬 컴퓨터 버스이며, 임베디드시스템 혹은 저속의 주변기기와의 통신을 위해 사용된 직렬 통신 방식입니다.  기본적으로 하나의 마스터와 하나 혹은 여러 대의 슬레이브 연결 구조이며 SDA핀으로 데이터를 주고받고,핀의 클럭신호(동기화)에 맞추어 통신하게 됩니다.  아두이노에서는 <Wire.h> 라이브러리를 활용하면 손쉽게 I2C 통신을 할 수 있습니다.  
 XDA XCL은 추가적인 외부의 지자기 센서나 또 다른 센서 연결을 확장하는 시리얼 통신 단자입니다.  External ,  XDA, XCL 연결 단자 입니다.
그리고, 하나의 회로에서 만약 동일한 GY521 모듈을 두 개 구성하여 사용할 경우, I2C 통신 주소를 다르게 하기 위해 AD0 핀에 풀업 저항을 달면 주소를 달리 할 수 있습니다.  모듈의 기본 Slave address 주소는 1101000 이며(0x68), +Vcc쪽으로 풀업 저항(1㏀~10㏀) 연결 시 1101001로(0x69) 변경됩니다.  

【 기울기 센서 실습  #1 】

: 기울기 센서 기본 실습으로 센서로부터 기본적인 RAW 데이터 값을 얻어내 보도록 하겠습니다. 
활용도와 정확도를 높이기 위해서는 라이브러리를 사용해야 하지만, 복잡하고 코드 내용 파악이 어려울 수 있기 때문에, 기초 실습 #1에서는 라이브러리 없이 진행됩니다. 
- MPU6050센서는 16bit ADC가 내장되어 있습니다.  센서의 각축으로부터 가속도와 자이로에 대한 아날로그 데이터를 16bit 분해능을 가진  ADC(Analog Digital Converter)를 거치면서 디지털 수치값으로 얻을 수 있다는 말인데요, 16bit는 2^16 이니 65536의 값인데, -(마이너스)부분까지 반으로 나누어 표시하면 기본적으로는 " -32768 ~ +32767 "  사이값의 출력 범위를 가진다는 말이 됩니다.   
실습 #1에서는 우선 원시 RAW 데이터를 각센서 축별로 출력해보고,
실습 #2는 가속도 센서를 통해 얻은 RAW 데이터로부터 X축과 Y축의 각도를 계산해 내는 실습으로 진행하고, 
실습 #3에서는 자이로 센서를 통해 얻은 RAW 데이터로부터 X축과 Y축의 각도를 얻는 과정으로 진행합니다. 
실습 #4 상보필터 적용 실습
 각 실습별 방법에 대한 장단점 및 기본적인 설명이 안내해 드리며,  상호 보완필터(상보필터)를 적용한 실습 #4로 이어지니 차근차근 하나씩 실습해 보시기 바랍니다.    가급적 실습 #4까지는 외부라이브러리를 배제한 코드를 사용하여 코드 단순화를 통해 동작원리를 이해하는데 도움이 되도록 하였습니다.

아래 회로 연결도를 구성해 주고 PC와 연결합니다.
▶ 회로 연결도
(아두이노 나노와 GY521(MPU6050) 연결도)

아두이노 나노와 GY521(MPU6050) 연결도

▶ 아두이노 코드 
(가속도 x, y, z 축 값과  자이로 x, y, z 축 값의 raw data를 시리얼 모니터로 출력해 보기)

/* 기울기 센서 GY-521(MPU6050) 기초 실습 #1 (RAW 데이터 얻기)                            */ 
/* 아래 코드관련 실습에 대한 설명과 회로도 및 자료는 https://rasino.tistory.com/ 에 있습니다 */

#include<Wire.h>
const int MPU_ADDR = 0x68;    // I2C통신을 위한 MPU6050의 주소
int16_t AcX, AcY, AcZ, Tmp, GyX, GyY, GyZ;   // 가속도(Acceleration) 와 
void getRawData();  // 센서값 얻는 서브함수의 프로토타입 선언 

void setup() {
  initSensor();
  Serial.begin(9600);
  delay(200);
}

void loop() {
  getRawData();          // 센서값 얻어오는 함수 호출
  Serial.print("AcX:");
  Serial.print(AcX);
  Serial.print("   AcY:");
  Serial.print(AcY);
  Serial.print("   AcZ:");
  Serial.print(AcZ);
  Serial.print("   GyX:");
  Serial.print(GyX);
  Serial.print("   GyY:");
  Serial.print(GyY);
  Serial.print("   GyZ:");
  Serial.print(GyZ);
  Serial.println();
  delay(300);  
}

void initSensor() {
  Wire.begin();
  Wire.beginTransmission(MPU_ADDR);   // I2C 통신용 어드레스(주소)
  Wire.write(0x6B);    // MPU6050과 통신을 시작하기 위해서는 0x6B번지에    
  Wire.write(0);       // MPU6050을 동작 대기 모드로 변경
  Wire.endTransmission(true);
}

void getRawData() {
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x3B);   // AcX 레지스터 위치(주소)를 지칭합니다
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_ADDR, 14, true);  // AcX 주소 이후의 14byte의 데이터를 요청

  AcX = Wire.read() << 8 | Wire.read(); //두 개의 나뉘어진 바이트를 하나로 이어 붙여서 각 변수에 저장
  AcY = Wire.read() << 8 | Wire.read();
  AcZ = Wire.read() << 8 | Wire.read();
  Tmp = Wire.read() << 8 | Wire.read();
  GyX = Wire.read() << 8 | Wire.read();
  GyY = Wire.read() << 8 | Wire.read();
  GyZ = Wire.read() << 8 | Wire.read();
}

 《 위 코드 다운로드 》

Angle_RawData.zip
0.00MB



▶ 실행 결과
: 코드를 실행해 보면, 가속도 값 3개와 자이로 값3개  총 6개의 값이 일렬로 나타납니다.  센서를 움직여보면
데이터 값이 변하는 것을 볼 수 있습니다.  방향에 따라 + ,  - 값으로 나타나는데요,  현재 보이는 값은 어떤 각도 값이나 보정된 값이 아닌  말 그대로 순수한 Raw data이기 때문에 방향과 위치에 따른 데이터 변화를 유추하기는 어렵습니다.  때문에, 기본적인 Raw 데이터를 추출하는 원리 정도만 파악하시면 되고, 다음 실험에서 삼각함수를 이용한 각도 값을 계산해 보거나 ,  특정 라이브러리를 이용해서 고정시킨 위치 데이터를 확인해 볼 수 있게 됩니다.  또는 프로세싱(Processing)과 같은 그래픽 구현 툴을 이용해서 3D 이미지로 센서의 움직임을 그래픽 화면으로 볼 수 있는 실험도 진행할 예정입니다.  

기울기센서(MPU6050)로부터 Raw 데이터 얻기

▶ 동작 영상
(본 글 제일 아래 전체 동영상을 참고해보세요 : 설명 음성 추가)

【 기울기 센서 실습  #2 】

: 실습 #1에서 Raw 데이터를 얻었다면,  이번엔 이 데이터를 가지고 우리가 흔히 알아보기 쉬운 각도(라디안: radian) 값으로 바꾸어 출력해 보는 실습입니다.
먼저 각도를 얻을 수 있는 방법은,  앞서 설명한 것처럼 크게 세 가지입니다. 
1. 가속도 센서를 이용한 방법
2. 자이로 센서를 이용한 방법
3. 이 둘을 합쳐놓은 '상호보완 필터' 코드를 통해 구하는 방법
이번 실습은 움직임이 없는 상태에서 보다 정확한 값을 구할 수 있는 1번 가속도 센서를 이용한 간단한 방법으로 진행합니다. 때문에 라이브러리 설치 없이 간단히 진행할 수 있고 코드도 비교적 단순하여 파악과 응용이 쉽습니다.
각도(라디안)를 라이브러리 설치 없이 진행되어 구하기 위해서는 중력과 X축, Y축, Z 축과의 기울기를 이용한 삼각함수를 적용해야 하는데요, 해당 수식은 아래와 같습니다. 

Roll/Pitch/Yaw 각도를 구하기 위한 삼각함수 수식

 물론 코드에서는 이 수식이 적용되어 있습니다. 

 회로 연결은 실습 1과 같고 아래에 있는 아두이노 코드를 업로드해 주세요.

▶ 아두이노 코드 
( 코드에서는 가속도 AcX에 대한 'Roll 각도'와 가속도 AcY에 대한 'Pitch 각도'만 구합니다.  앞서 설명드린 것처럼 가속도 센서만 가지고는 Yaw에 해당하는 정확한 AcZ 각도가 구할 수 없습니다.  Z축 Yaw가 중력 방향과 평행한 회전을 하기 때문에 삼각함수를 적용해도 올바른 데이터가 출력되지 않습니다.)

//    Roll과 Pitch 각도 구하기 실습  》                                               
//  가속도 센서만 가지고 롤(Roll)과 피치(Pitch)를 구하는 예제입니다.                          
//  본 코드는 드론과 같은 움직임이 심한 경우가 아닌 비교적 정적인 상태에서 안정된 값을 얻을 수 있으며,
//  복잡한 외부라이브러리를 사용하지 않아 코드가 심플해서 파악후 적용하기가 쉽습니다.
// 아래 코드관련 실습에 대한 설명과 회로도 및 자료는 https://rasino.tistory.com/ 에 있습니다   

#include<Wire.h>

const int MPU_ADDR = 0x68;    // I2C통신을 위한 MPU6050의 주소
int16_t AcX, AcY, AcZ, Tmp, GyX, GyY, GyZ;   // 가속도(Acceleration)와 자이로(Gyro)
double angleAcX;
double angleAcY;
// double angleAcZ;
const double RADIAN_TO_DEGREE = 180 / 3.14159;
void setup() {
  initSensor();
  Serial.begin(9600);
  delay(200);
}

void loop() {
  getAngleXY(); 
  Serial.print("Angle x : ");
  Serial.print(angleAcX);
  Serial.print("\t\t Angle y : ");
  Serial.println(angleAcY);
  delay(20);
}

double getAngleXY() {
  getData();  
  // 삼각함수를 이용한 롤(Roll)의 각도 구하기 
  angleAcX = atan(AcY / sqrt(pow(AcX, 2) + pow(AcZ, 2)));
  angleAcX *= RADIAN_TO_DEGREE;
  // 삼각함수를 이용한 피치(Pitch)의 각도 구하기
  angleAcY = atan(-AcX / sqrt(pow(AcY, 2) + pow(AcZ, 2)));
  angleAcY *= RADIAN_TO_DEGREE;
  // angleAcZ값(Yaw)은 아래의 삼각함수 공식은 있으나, 가속도 센서만 이용해서는 원하는 데이터를 얻을 수 없어 생략
// angleAcZ = atan(sqrt(pow(AcX, 2) + pow(AcY, 2)) / AcZ );
// angleAcZ *= RADIAN_TO_DEGREE;
}

void initSensor() {
  Wire.begin();
  Wire.beginTransmission(MPU_ADDR);   // I2C 통신용 어드레스(주소)
  Wire.write(0x6B);    // MPU6050과 통신을 시작하기 위해서는 0x6B번지에    
  Wire.write(0);
  Wire.endTransmission(true);
}

void getData() {
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x3B);   // AcX 레지스터 위치(주소)를 지칭합니다
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_ADDR, 14, true);  // AcX 주소 이후의 14byte의 데이터를 요청
  AcX = Wire.read() << 8 | Wire.read(); //두 개의 나뉘어진 바이트를 하나로 이어 붙여서 각 변수에 저장
  AcY = Wire.read() << 8 | Wire.read();
  AcZ = Wire.read() << 8 | Wire.read();
  Tmp = Wire.read() << 8 | Wire.read();
  GyX = Wire.read() << 8 | Wire.read();
  GyY = Wire.read() << 8 | Wire.read();
  GyZ = Wire.read() << 8 | Wire.read();
}

 《 위 코드 다운로드 》

Angle_Roll_Pitch.zip
0.00MB

▶ 실행 결과
:  main loop( )에 있는 delay(20)을 느리게 혹은 빠르게 조절하여 확인해 볼 수 있습니다.
 센서 보드를 중력의 방향과 수직으로 놓으면 X와 Y는 0도를 가리킵니다.  그 상태에서 Roll(X)을 앞 뒤로 돌려보고, 
Pitch(Y)를 앞뒤로 돌려 보세요.  

 - Roll은 센서 보드 위 화살표 표시를 참고 기준으로 하여,  중력과 반대로 머리를 들면 +각도로 나오며, 중력의 방향으로 머리를 숙이면 -각도를 표시합니다.
 - Pitch 또한 피치 화살표를 기준으로, 화살표 방향으로 숙이면 +각도로 표시되며, 반대방향으로 회전시키면 -각도로 표시됩니다. 
 - 아래 이미지는 시리얼 플로터를 실행시킨 화면인데요, 각도 값을 그래프 형태로 보면 좀 더 직관적으로 파악하기 좋습니다. 
   ( 시리얼 플로터 창 열기 : 아두이노 IDE 툴 메뉴 클릭 》 시리얼 플로터 클릭! )
파란선이 Roll (AcX)에 대한 각도 그래프이며, 빨간선이 Pitch(AcY)에 대한 각도 그래프입니다.
기울기 센서 모듈은 접촉이 불안정할 경우, 데이터가 원하는 대로 나오지 않거나, 오작동 할 수 있습니다.
접촉이 헐렁한 브레드보드를 바꾸어 보거나 연결선을 확인해 보세요.  필요한 경우 납땜으로 연결해 주면 더욱 안정된 접촉이 이루어집니다.
그 외에 동작은 정상 동작하나, 데이터 값이 튀는 노이즈가 심할 경우에는, 추출 값을 3~10회 정도의 평균값 처리하는 루틴을 넣어 주면 어느 정도 해결할 수 있습니다.

▶ 동작 영상

 

【 기울기 센서 실습  #3 】

: 실습 #2에서 MPU6050에 있는 가속도 센서를 이용해서 각도(라디안: radian) 값으로 바꾸어 출력해 보는 실습을 했다면, 이번엔 MPU6050에 있는 자이로 센서를 이용해서 각도를 계산해 출력해 보겠습니다.

1. 가속도 센서를 이용한 방법
2. 자이로 센서를 이용한 방법
3. 이 둘을 합쳐놓은 '상호보완 필터' 코드를 통해 구하는 방법
이번 실습은  2. 자이로 센서를 이용한 방법 입니다. 
 먼저 자이로 센서는 진자의 움직임과 같은 축을 중심으로 회전하는 각속도를 측정합니다.
각속도는 시간당 회전하는 각도를 의미하는데요, 예를 들면, 
1. 수평한 자세를 유지하고 있는 상태이라면, 각속도는 0도/sec를 나타낼 텐데요, 
2. 이 물체가 10초 동안 50도만큼 기울어졌을 경우 ,  이 10초동안은 0이 아닌 각속도 값을 가지게 됩니다. 10초 동안의 평균 각속도는 5도/sec 가 되는데요,  즉,  초당 5도를 움직이는 속력이라 말할 수 있습니다.
3. 기울어지는 동작을 한 후 다시 멈춰서 50도를 유지한다고 할 때, 이때는 다시 각속도가 0도/sec 가 됩니다. 

1번 2번 3번 과정을 거치면서 각속도는 0 -> 5 -> 0으로 바뀌었는데요, 그런데 각도는 0도에서 점차 증가해서 50도가 된 상태입니다.   그래서 각속도가 움직인 각도에 비례해서 증가하는 것이 아니기 때문에, 각도를 구하려면 전체 시간에 해당하는 만큼의 각속도를 모두 합(적분을) 해야합니다.  자이로 센서는 이와 같이 각속도를 데이터로 출력하기 때문에  이 각속도 데이터를 모두 합(적분)하면 기울어진 각도를 계산해 낼 수 있는 원리입니다.  그런데 자이로 센서의 경우 문제는 이러한 적분 때문에 발생하게 됩니다.  센서에서 측정되는 각속도는 노이즈나 미세한 기본 오차 값들이 적분으로 인해, 시간이 지날 수록 쌓여 결국 측정값(각도 오차)의 오차가 커지게 되는 문제가 있습니다.  Drift 현상이 발생합니다. 
(즉, 이 방법만으로는 시간이 지날 수록 각도 혹은 기울기의 오차가 커지게 되는 단점이 있죠. 하지만, 가속도 센서처럼 진동에 영향이 크게 없으며 중력과 일치하는 Z축의 Yaw 각도도 구할 수 있는 장점이 있습니다. 

[ 용어 정리 ]
- Drift 현상 : 조건이 일정함에도 시간이 경과함에 따라서 값이 이탈 또는 흘러가는 현상.
- 각속도란 :  각속도 오메가(ω)는 원운동에서 단위 시간 동안에 회전한 각도를 말하며,  즉, 회전하는 물체에 대한 회전의 빠르기를 의미합니다. 

- 각도 :  각속도에 시간을 곱한 것이 각도 이며,  이것들을 모두 합치면 움직인 전체 각도가 됩니다

속력/속도/가속도 와의 관계식


 회로 연결은 실습 1과 같고 아래에 있는 아두이노 코드를 업로드해 주세요.

▶ 아두이노 코드 
( 코드에서는 시리얼 모니터 통신속도를 115200bps 으로 바꾸었으니, 실행시 시리얼 모니터 창의 보드레이트를 115200 bps로 맞추어 주세요)

// 《 자이로 Gyro 센서로 Roll과 Pitch, Yaw의 각도 구하기 실습  》         
//  자이로 센서만 가지고 롤(Roll)과 피치(Pitch), 야우(Yaw)를 구하는 예제입니다.                          
/* 아래 코드관련 실습에 대한 설명과 회로도 및 자료는 https://rasino.tistory.com/ 에 있습니다    */

#include<Wire.h>

const int MPU_ADDR = 0x68;    // I2C통신을 위한 MPU6050의 주소
int16_t AcX, AcY, AcZ, Tmp, GyX, GyY, GyZ;   // 가속도(Acceleration)와 자이로(Gyro)
double angleAcX, angleAcY, angleAcZ;
double angleGyX, angleGyY, angleGyZ;

const double RADIAN_TO_DEGREE = 180 / 3.14159;  
const double DEG_PER_SEC = 32767 / 250;    // 1초에 회전하는 각도
// GyX, GyY, GyZ 값의 범위 : -32768 ~ +32767 (16비트 정수범위)


unsigned long now = 0;   // 현재 시간 저장용 변수
unsigned long past = 0;  // 이전 시간 저장용 변수
double dt = 0;           // 한 사이클 동안 걸린 시간 변수 

double averAcX, averAcY, averAcZ;
double averGyX, averGyY, averGyZ;

void setup() {
  initSensor();
  Serial.begin(115200);
  caliSensor();   //  초기 센서 캘리브레이션 함수 호출
  past = millis(); // past에 현재 시간 저장  
}

void loop() {
  getData(); 
  getDT();
  angleGyX += ((GyX - averGyX) / DEG_PER_SEC) * dt;
  angleGyY += ((GyY - averGyY) / DEG_PER_SEC) * dt;
  angleGyZ += ((GyZ - averGyZ) / DEG_PER_SEC) * dt;
  
  Serial.print("Angle Gyro X:");
  Serial.print(angleGyX);
  Serial.print("\t\t Angle Gyro y:");
  Serial.print(angleGyY);  
  Serial.print("\t\t Angle Gyro Z:");
  Serial.println(angleGyZ);  
  delay(20);
}

void initSensor() {
  Wire.begin();
  Wire.beginTransmission(MPU_ADDR);   // I2C 통신용 어드레스(주소)
  Wire.write(0x6B);    // MPU6050과 통신을 시작하기 위해서는 0x6B번지에    
  Wire.write(0);
  Wire.endTransmission(true);
}

void getData() {
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x3B);   // AcX 레지스터 위치(주소)를 지칭합니다
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_ADDR, 14, true);  // AcX 주소 이후의 14byte의 데이터를 요청
  AcX = Wire.read() << 8 | Wire.read(); //두 개의 나뉘어진 바이트를 하나로 이어 붙여서 각 변수에 저장
  AcY = Wire.read() << 8 | Wire.read();
  AcZ = Wire.read() << 8 | Wire.read();
  Tmp = Wire.read() << 8 | Wire.read();
  GyX = Wire.read() << 8 | Wire.read();
  GyY = Wire.read() << 8 | Wire.read();
  GyZ = Wire.read() << 8 | Wire.read();
}

// loop 한 사이클동안 걸리는 시간을 알기위한 함수
void getDT() {
  now = millis();   
  dt = (now - past) / 1000.0;  
  past = now;
}

// 센서의 초기값을 10회 정도 평균값으로 구하여 저장하는 함수
void caliSensor() {
  double sumAcX = 0 , sumAcY = 0, sumAcZ = 0;
  double sumGyX = 0 , sumGyY = 0, sumGyZ = 0;
  getData();
  for (int i=0;i<10;i++) {
    getData();
    sumAcX+=AcX;  sumAcY+=AcY;  sumAcZ+=AcZ;
    sumGyX+=GyX;  sumGyY+=GyY;  sumGyZ+=GyZ;
    delay(50);
  }
  averAcX=sumAcX/10;  averAcY=sumAcY/10;  averAcZ=sumAcY/10;
  averGyX=sumGyX/10;  averGyY=sumGyY/10;  averGyZ=sumGyZ/10;
}

《 위 코드 다운로드 》

Angle_Gyro.zip
0.00MB

▶ 실행 결과
:  센서 보드를 X축 Y축 Z축 각각 움직여 보세요.

▶ 실행 영상
(제일 아래 전체 설명 동영상 참고)

【 기울기 센서 실습  #4 】

: 실습 #2와 실습#3에서는 각각 가속도 센서와 자이로 센서를 이용한 각도를 구했는데요,
가속도센서는 진동에 약하기 때문에(튀는 데이터값의 영향이 큼) 짧은 시간의 변화에는 약하지만, 긴 시간에 대해서는 정확한 각도를 산출해 낼 수 있고,  자이로센서는 진동에 강하기 때문에 짧은 시간에 대해서는 정확한 각도를 얻을 수 있지만 시간이 지나면서 오차가 누적되어 긴 시간에서는 취약합니다. 
 그래서
각각의 장점도 있지만, 단점이 명확하여 어느 하나의 센서 만으로는 드론과 같은 자세제어나 보정은 어렵습니다.   따라서 센서 둘을 모두 이용하고, 이 둘의 장점을 이용하여 서로의 단점을 보완한 상호보완 필터 코드를 적용하여 사용한다면, 비교적 오류가 없는 각도를 구할 수 있어서  드론 등의 자세제어 코드에 사용할 수 있습니다. 

1. 가속도 센서를 이용한 방법
2. 자이로 센서를 이용한 방법
3. 이 둘을 합쳐놓은 '상호보완 필터' 코드를 통해 구하는 방법
이번 실습은 3. 상호보완 필터를 이용한 방법 입니다. 

 아래 이미지는 상호보완 필터의 개념도 입니다. 

상보필터(상호보완) 개념도

[ 상보필터의 원리 - Complementary Filter ]
- 가속도 센서(Accelerometer)는 센서 특성상 고주파 영역에서 노이즈가 많이 발생하게 되어 정확한 값을 얻기 어려운데요, 그래서 노이즈 영역을 제거하고자 고역은 감쇠시키고,  낮은 주파수 영역을 통과시키는 저역필터(Low Pass Filter)를 적용해주면 정확도가 올라갑니다. 
- 자이로 센서(Gyroscope)는 센서 특성상 저주파 영역에서 값이 변하는 Drift현상이 발생하여 정확한 값을 기대하기가 어렵습니다. 그래서 저역을 감쇠시키고 노이즈가 적은 고역을 통과시키기 위한 고역필터(High Pass Filter)를 적용해주면 역시 정확도가 올라갑니다.   
※ 이렇게 각각의 필터를 통과해서 노이즈가 걸러진 값들을 합하여 보다더 정확한 각도값을 얻게 됩니다. 
이외에 칼만필터(Kalman Filter), Quanternion 라는 것도 있습니다.

상보필터에서는 가속도 센서의 저주파 영역에서의 장점과 , 자이로센서의 고주파 영역에서의 장점만을 융합한 필터로서 , 방법과 코드가 간단하여 적용하기 쉬운 장점이 있습니다.   상보필터에서는 ALPHA라는 가중치 값을 통해 자이로센서와 가속도센서 각각으로부터 얻은 각도를 어떤 비중으로 적용시킬지 정하여 계산하게 되는데요. 
 아래가 바로 보정값(가중치) ALPHA를 적용한 보정된 각도 값의 식(angleFiX) 입니다.
  angleFiX = ALPHA * angleTmpX + (1.0 - ALPHA) * angleAcX;

 여기서 angleTmp 는 자이로센서 값을 기준으로 만든 상보필터 처리를 위한 임시각도이며
X축에 대해 정리하면  angleTmpX = angleFiX + angleGyX * dt  가 됩니다.
가중치 ALPHA 값은 α = T/(T+
Δt) 식으로 구하는데요,  α (ALPHA) = 1 / (1+0.04)  가되어,  α 값은 0.96 이 됩니다.
즉,  1(T) 사이클 도는 동안의 loop Time(Δt=0.04) 을 적용한 식입니다.     그런데 이 값은 고정값은 아니며,  loop Time이 길어지거나 등의 이유로 알파값을 시스템에 맞게 변경할 수 있습니다.
즉, angleFiX 식을 보면 아시겠지만,  자이로 값에 * 0.96 가중치를 곱하고(주고), 가속도 값에 * 0.04의 가중치를 줘서 합한 값이어서 자이로센서(자이로스코프)에 더 의존하는 형태라고 말 할 수 있습니다.   그런데, 이런 형태가 비교적 정밀한(안정적인) 출력값을 내는 이유는,   식을 다시 살펴보면
angleFiX = ALPHA * angleTmpX + (1.0 - ALPHA) * angleAcX;
각도 변화가 상당히 느린 구간(저주파 영역)에서는 자이로센서의 데이터 값이 작아지기 때문에(angleGyX * dt의 누적값 감소), (1.0-ALPHA) = 0.04 가중치 적용으로 작았던 가속도 데이터 값이 상대적으로 커지게 되어 ,  자이로스코프의 저주파 영역에서 발생하는 Drift(드리프트)에 대한 단점을 보완 할 수 있게 됩니다. 

▶ 아두이노 코드 
( 위에서 설명한 식을 코드에 적용한 아두이노 코드입니다.   실습 #1과  실습#2에 소개한 코드를 합쳐서, 상보필터 식을 적용한 코드입니다.   축 3가지를 동시에 시리얼모니터로 확인하기 불편하기 때문에, 일부 축에 주석처리 되어 있으니, 필요한 경우 주석을 해제하여 사용하세요. )
 -  시리얼모티너(플로터) 출력은 아래처럼 각 축별로 비교하기 쉽도록 배치하였습니다. 
    《가속도센서 X축》 출력과 《필터링된 X축》 출력
    《가속도센서 Y축》 출력과 《필터링된 Y축》 출력
    《자이로센서 Z축》 출력과 《필터링된 Z축》 출력

// 《 상보필터를 적용한 Roll과 Pitch, Yaw의 각도 구하기 실습  》         
/* 아래 코드관련 실습에 대한 설명과 회로도 및 자료는 https://rasino.tistory.com/ 에 있습니다    */

#include<Wire.h>

const int MPU_ADDR = 0x68;    // I2C통신을 위한 MPU6050의 주소
int16_t AcX, AcY, AcZ, Tmp, GyX, GyY, GyZ;   // 가속도(Acceleration)와 자이로(Gyro)
double angleAcX, angleAcY, angleAcZ;
double angleGyX, angleGyY, angleGyZ;
double angleFiX, angleFiY, angleFiZ;

const double RADIAN_TO_DEGREE = 180 / 3.14159;  
const double DEG_PER_SEC = 32767 / 250;    // 1초에 회전하는 각도
const double ALPHA = 1 / (1 + 0.04);
// GyX, GyY, GyZ 값의 범위 : -32768 ~ +32767 (16비트 정수범위)


unsigned long now = 0;   // 현재 시간 저장용 변수
unsigned long past = 0;  // 이전 시간 저장용 변수
double dt = 0;           // 한 사이클 동안 걸린 시간 변수 

double averAcX, averAcY, averAcZ;
double averGyX, averGyY, averGyZ;

void setup() {
  initSensor();
  Serial.begin(115200);
  caliSensor();   //  초기 센서 캘리브레이션 함수 호출
  past = millis(); // past에 현재 시간 저장  
}

void loop() {
  getData(); 
  getDT();

  angleAcX = atan(AcY / sqrt(pow(AcX, 2) + pow(AcZ, 2)));
  angleAcX *= RADIAN_TO_DEGREE;
  angleAcY = atan(-AcX / sqrt(pow(AcY, 2) + pow(AcZ, 2)));
  angleAcY *= RADIAN_TO_DEGREE;
  // 가속도 센서로는 Z축 회전각 계산 불가함.
  
  // 가속도 현재 값에서 초기평균값을 빼서 센서값에 대한 보정
  angleGyX += ((GyX - averGyX) / DEG_PER_SEC) * dt;  //각속도로 변환
  angleGyY += ((GyY - averGyY) / DEG_PER_SEC) * dt;
  angleGyZ += ((GyZ - averGyZ) / DEG_PER_SEC) * dt;

  // 상보필터 처리를 위한 임시각도 저장
  double angleTmpX = angleFiX + angleGyX * dt;
  double angleTmpY = angleFiY + angleGyY * dt;
  double angleTmpZ = angleFiZ + angleGyZ * dt;

  // (상보필터 값 처리) 임시 각도에 0.96가속도 센서로 얻어진 각도 0.04의 비중을 두어 현재 각도를 구함.
  angleFiX = ALPHA * angleTmpX + (1.0 - ALPHA) * angleAcX;
  angleFiY = ALPHA * angleTmpY + (1.0 - ALPHA) * angleAcY;
  angleFiZ = angleGyZ;    // Z축은 자이로 센서만을 이용하열 구함.
  Serial.print("AngleAcX:");
  Serial.print(angleAcX);
  Serial.print("\t FilteredX:");
  Serial.print(angleFiX);
  Serial.print("\t AngleAcY:");
  Serial.print(angleAcY);
  Serial.print("\t FilteredY:");
  Serial.println(angleFiY);
  Serial.print("\t AngleAcZ:");
  Serial.print(angleGyZ);
  Serial.print("\t FilteredZ:");
  Serial.println(angleFiZ);


//  Serial.print("Angle Gyro X:");
//  Serial.print(angleGyX);
//  Serial.print("\t\t Angle Gyro y:");
//  Serial.print(angleGyY);  
//  Serial.print("\t\t Angle Gyro Z:");
//  Serial.println(angleGyZ);  
//  delay(20);
}

void initSensor() {
  Wire.begin();
  Wire.beginTransmission(MPU_ADDR);   // I2C 통신용 어드레스(주소)
  Wire.write(0x6B);    // MPU6050과 통신을 시작하기 위해서는 0x6B번지에    
  Wire.write(0);
  Wire.endTransmission(true);
}

void getData() {
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x3B);   // AcX 레지스터 위치(주소)를 지칭합니다
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_ADDR, 14, true);  // AcX 주소 이후의 14byte의 데이터를 요청
  AcX = Wire.read() << 8 | Wire.read(); //두 개의 나뉘어진 바이트를 하나로 이어 붙여서 각 변수에 저장
  AcY = Wire.read() << 8 | Wire.read();
  AcZ = Wire.read() << 8 | Wire.read();
  Tmp = Wire.read() << 8 | Wire.read();
  GyX = Wire.read() << 8 | Wire.read();
  GyY = Wire.read() << 8 | Wire.read();
  GyZ = Wire.read() << 8 | Wire.read();
}

// loop 한 사이클동안 걸리는 시간을 알기위한 함수
void getDT() {
  now = millis();   
  dt = (now - past) / 1000.0;  
  past = now;
}

// 센서의 초기값을 10회 정도 평균값으로 구하여 저장하는 함수
void caliSensor() {
  double sumAcX = 0 , sumAcY = 0, sumAcZ = 0;
  double sumGyX = 0 , sumGyY = 0, sumGyZ = 0;
  getData();
  for (int i=0;i<10;i++) {
    getData();
    sumAcX+=AcX;  sumAcY+=AcY;  sumAcZ+=AcZ;
    sumGyX+=GyX;  sumGyY+=GyY;  sumGyZ+=GyZ;
    delay(50);
  }
  averAcX=sumAcX/10;  averAcY=sumAcY/10;  averAcZ=sumAcY/10;
  averGyX=sumGyX/10;  averGyY=sumGyY/10;  averGyZ=sumGyZ/10;
}

《 위 코드 다운로드 》

Angle_Acc_Gyro_CompFilter.zip
0.00MB


※ 아래 실행결과 화면을 보시면 알겠지만, 상보필터를 적용 후의 그래프는 노이즈나 한 번씩 크게 튀는 값 들이 상당히 제거되어 나타나는 것을 알 수 있습니다.   단, 노이즈 향상을 위해 ALPHA값 등, 보정값을 과도하게 조정하게 되면, 보정된 데이터의 출력 딜레이(시간차)가 발생하게 됩니다.  이는 드론(Drone)과 같은 제어에 있어서는 적시에 올바른 제어를 할 수 없게 만들 수도 있습니다.  

▶ 실행 결과
1.   《가속도센서 X축》 출력과《필터링된 X축》 출력 비교 화면
먼저, 시리얼모니터 화면을 살펴 보세요.(아래 이미지)  , 보드를 77도 정도에서 고정한 상태에서 가속도센서에서 얻은 데이터는 각도 값이 68~70도 사이를 짧은 순간에 제법 심하게 요동치고 있는 반면에, 필터링한 각도 값은, 77도에서 소수점 단위 정도만 변동이 있을 뿐 매우 안정된 출력을 보여주고 있는 것을 알 수 있습니다. 

 그럼, 이제 시리얼 모니터만으로는 잘 체감이 안 되실텐데요, 같은 출력을 아두이노 IDE 메뉴에 있는 '시리얼 플로터'를 통해 그래프로 보면 좀더 확연히 그 차이를 구분하실 수 있게 됩니다. (아래)

파란색 그래프가 가속도센서로 부터 얻은 X축 회전(각도)상태의 데이터인데요,  떨림과 같은 병동이 심한 반면에, 
필터링 코드를 거친 빨간색 X축의 데이터는 이런 노이즈들이 깔끔하게 제거 된 것을 알 수 있습니다.

2.   《가속도센서 Y축》 출력과《필터링된 Y축》 출력 비교 화면
그럼, Y축 그래프도 살펴 볼게요.

역시 마찬가지로, 필터링 되지 않은 Y축 출력과 필터링된 Y축 출력에 차이가 있음을 볼수 있습니다.

3.   《자이로센서 Z축》 출력과《필터링된 Z축》 출력 비교 화면
그리고, Z축 같은 경우는 앞서 설명드린대로, 가속도 센서로부터는 데이터를 얻을 수 없는 상태이고, 따라서 자이로 센서로 부터 얻은 Z축 데이터와,  자이로센서 데이터 가중치가 높은 필터링된 Z축 데이터를 출력해 본 것이어서 두 그래프간의 차이가 거의 없는 그래프 모습을 보여주고 있습니다.

3.  끝으로 전체 축을 동시에 비교해봤습니다. 《자이로센서 X-Y-Z-축》 출력과《필터링된 X-Y-Z축》 출력 화면

X축과 Y축을 0도 기준으로 움직이지 않았을 때 출력 모습

※ 여기서 한가지 생각해볼 수 있는 사항은, 
필터링전 그래프와 필터링후의 그래프간 출력의 시간차가 조금씩 나는 것을 볼 수 있습니다.   이는 더 매끈하게 노이즈를 제거 하려고 ALPHA값 수치를 조정하거나 하다보면, 더 커질 수 있는데요,  이는 공중에서 빠른 반응으로 자세보정을 해야하는 드론과 같은 경우에는 상보필터의 적용이 어려울 수 있습니다.  따라서, 이런 경우 등으로 인해, 대개 칼만필터 같은 것들이 적용이 되고 있습니다.  하지만 칼만필터의 경우는 주로 외부라이브러리도 필요하고 구조적으로 코드가 복잡합니다.   그래서 드론 이외의 모델에서는 코드적으로 매우 심플한 상보필터를 적용해보면, 적용하기도 쉽고, 충분히 만족스러운 결과를 얻을 수 있을 것이라 생각됩니다.


▶ 실행 영상( 이번 MPU6050 실습에 대한 전체 설명 영상을 제작했으니 보신다면 내용이해에 충분히 도움 되실 듯 합니다 )

youtu.be/BTpwAFfeg0I

 

반응형
반응형

【 아두이노프렌즈 초소형 아두이노 ATtiny85 기초부터 응용까지 완벽 풀코스(초미니 OLED 온·습도계 제작)

 


 여러분은 아래 이미지를 보시고 똑 같은 기능이 가능한 3가지 모델 중 어떤 것을 선택하시겠어요?
( 제품 비용, 제품 크기-공간 차지 등 고려 시 )

 당연히 너무 타이니(tiny)해서 매력적인 ATtiny85을 선택해야 겠죠?  ^^
그럼, 이번 시간을 통해 가격도 타이니,  크기도 타이니해서 공간 차지도 적어 너무 매력적인 ATtiny85에 대해 기초 부터 상세하게 설명드리고, 게다가 'OLED 온·습도계'라는 멋진 응용작품까지 만드는 법에 대해 상세하게 설명드릴테니 안내에 따라 실습해보세요. 

【 ATtiny85 개요 】


'ATtiny85'는 Atmel사의 AVR 시리즈중 하나이며,  8bit, 8pin 스몰 사이즈의 Microcontroller 입니다.(Atmel 사는 후에
Microchip사에 인수됨)  
 아두이노 보드의 메인 칩인 ATmega328 MCU와 같은 계열의 마이크로 프로세서 유닛입니다. 
따라서, 아두이노 처럼 프로그래밍된 코드를 올려 입출력 포트를 제어하는 프로젝트에 이용할 수 있으며, 비록 입출력 포트수가 적고 프로그래밍 영역 메모리(플래시 메모리)가 작지만,  우노 보드 보다 몇 배나 작은 크기로 인해 초소형 저전력 아두이노 프로젝트에 매우 적합한, 장점이 많은 MCU입니다. 
다만, 이렇게 아두이노IDE 툴을 통해 아두이노 코드를 업로드하여 작동하도록 하기 위해서는 부트로더라는 영역에 부트로더가 우선 설치되어져야 합니다.  마치 PC에서 윈도우와 같은 운영체제 설치와 응용프로그래밍이 돌아가기 위해 먼저 설치되어 있는 MBR과 같은 부트레코드(부트코드)가 필요하듯 말이죠.

여기서 시리즈 모델명에 대한 풀이를 잠시 하면 아래 이미지와 같습니다. 

따라서  ATtiny85는 8핀 타입의  IC이며, 코딩으로 프로그래밍 가능한 Flash 메모리 용량이 8Kb인 MCU가 됩니다.  필요한 경우, 아래 데이터 시트(Data Sheet)를 살펴 보세요.

ATTINY85.pdf
4.53MB

【 ATtiny85 IC 주요 스팩 】



 

ATtiny85에 부트로더를 직접 올리는 실습은 아래 실습 과정에 있습니다
PC 에서의 MBR영역
AVR 칩에 부트로더와 코드가 탑재되는 영역

 따라서,  이번 학습에서는 앞부분에 부트로더를 굽는(칩의 메모리 영역에 기록) 과정부터 알려드립니다.  이 과정에서 절차를 생략하거나 순서가 바뀌면 에러가 날 수 있기 때문에 최대한 상세하게 안내를 하고 있으니, 천천히 보면서 개념을 정리하고 넘어가시면 좋습니다.  

 다음으로, 이런 부트로더를 굽는 과정에서는 Atmel 사의 AVR 시리즈 칩에서 사용하던 AVR ISP라는 전용 프로그래머가 필요합니다.  이 것 또한 따로 구하려면 비용이 들고, 번거롭기도 한데요, 다행히 아두이노 우노 혹은 나노 보드를 가지고 이런 AVR ISP 프로그래머를 만들어 사용할 수 있습니다. (중반부에 회로도면과 방법 설명)   물론,  아두이노 우노(나노) 보드에 올려진 Atmega328칩에는 이런 부트로더가 이미 탑재된 상태로 출시되기 때문에,  부트로더 탑재 과정 없이 바로 아두이노 코드를 올릴 수 있게 됩니다.

AVR ISP 프로그래머

아래는 ATtiny85의 상세 핀아웃(PinOut) 입니다.
IC에는 1번핀 부터~ 8번 핀까지 물리적인 핀 번호가 있으며,  PB0~PB5 까지 6개의 디지털 입출력이 가능한 포트가 있습니다.  이중에 PB5, PB2, PB4, PB3번 포트는 아날로그 입력에 대한 처리가 가능한 포트 이며,  PB0와 PB1 포트는 PWM출력(디지털 방식의 아날로그 값 출력)이 가능한 포트 입니다.   따라서, 아두이노 코드와 회로 연결를 통해 핀 아웃에 적혀진 기능을 사용할 수 있습니다.

ATtiny85의 핀 아웃(Pin Out), '보라색 원'표시는 1번핀의 위치를 알려줌

 

 

 일반적으로 많이 사용되는 주요 기능핀만 보기 좋게 정리된 이미지가 있어 소개합니다. 
주요 기능핀으로, I2C 통신용 핀(물리적 5번 핀, 7번 핀)과, SPI통신용(물리적 5번, 6번, 7번핀)핀이 표시되어 있고, PWM(물리적 5번핀, 6번핀),  Reset핀(물리적 1번 핀),  +전원 8번 핀 , -전원(GND) 4번 핀 등이 표시 되어 있으니 참고하세요.  

ATtiny85의 주요 핀 기능 표시

[ ※ 본 게시물의 모든 이미지는 클릭하면 확대 됩니다  ]



【 학습 목차 】

 

【 실습 재료 】

1. ATtiny85 : 1개 이상  (되도록 2~3개 이상 여유 있게 준비 하세요)
2. 전해 콘덴서 : 10uF 1개 (용량은 더 작거나 조금 더 커도 크게 관계 없습니다)
3. LED :  5 개 이상
4. 저항 : 220Ω 5개 이상(100Ω~470Ω도 가능),  4.7kΩ 1개 (1kΩ~10kΩ도 가능)
5. I2C type OLED (128x64 픽셀) :  1개 이상
6. 온습도 센서 :  DHT11 또는 DHT22 1개     (또는 각 1개)
7. 아두이노 보드 : 우노 보드 1개 또는 나노 보드 1개 (또는 각 1개)
8. 브레드 보드 : 400홀 1개 또는 170홀 3개  (또는 모두)
9. 전원 :  3.6~5.5V 사이 전원으로 사용가능한 모든 종류 가능

【 실습 #2 】 아두이노 우노 보드를 이용한 AVR ISP 보드 만들기 

▶ 회로 연결도면
우노보드를 이용해서 ATtiny85용 AVR ISP 보드를 만드는 연결도면 입니다.
아래 연결도를 보고 조립해 주세요.

우노보드를 이용해서 ATtiny85용 AVR ISP 연결도면

 단, 아래 이미지를 참고해서 콘덴서의 +, - 극성을 구분해서 연결해야 합니다.
파란색 사각형에 표시된 흰색 줄무늬가 있는 쪽의 리드선(길이가 짧은)이 '-극성'핀입니다.
상대적으로 다리(리드선)이 긴 쪽이 +극성 핀입니다.

 

< 실습 #1-1> ArduinoISP 코드를 아두이노 우노 보드에 업로드하기
먼저, 아두이노 IDE 프로그램을 실행시키고 아래 이미지 처럼 예제 파일에 있는  ArduinoISP 예제파일을 열어서 아두이노 우노 보드에 빌드&업로드 시켜주세요.   
: 아두이노 IDE 메뉴 》 예제 》 11. ArduinoISP 》 ArduinoiSP

이미지 클릭하여 확대해서 보세요

- 이때, 업로드시 에러가 난다면,  보드에 연결해 놓았던 콘덴서는 잠시 제거합니다.  코드가 업로드 되면 다음 단계 실습을 다시 연결해 주세요

 

- 환경설정하기 :  ATtiny85에 부트로더를 올리기거나 코드를 업로드하기 위해서는 우선적으로 ATtiny85 보드가 선택항목에 포함 되어 있어야 합니다.  아두이노 IDE 기본 설치 상태에서는 tiny85보드 항목이 보이지 않는데요,  이때,
  1.1 attiny관련 보드 정보를 담고 있는 JSON 파일에 대한 링크를 아두이노 IDE 환경설정 탭에서 추가해주세요. 

만약, 아래 이미지 처럼 기존에 esp8266과 같은 다른 보드의 URL이 존재할 경우, 아래 이미지 처럼, 창 아이콘을 눌러 팝업창이 뜨면 거기 제일 아랫줄에 붙여넣기 하여 추가해주면, 여러가지 보드를 동시에 추가해 놓을 수 있게 됩니다.   (아래 ATtiny 보드 추가용 주소를 복사하야 아두이노 환경설정에 추가해 주세요)

https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json

https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json


- 아래 이미지, 아두이노 IDE 》 툴 》 보드 : 》 보드 매니저...    에서 검색창에 'attiny'로 검색 한 후 검색된 항목을 설치해 주세요. 

※ 만약 보드 매니저에서 "attiny로 검색해도 검색 결과가 뜨지 않을 경우에는 떠 있는 모든 아두이노 프로그램을 닫고 다시 실행 시켜서 검색해보세요. (경우에 따라 2~3번 이상 껏다 켰다 반복 필요)
이렇게 했는 데도 보드 검색이 되지 않는 다면, 여기 링크에서 직접 압축파일을 다운 받으세요. 
https://github.com/damellis/attiny

 

GitHub - damellis/attiny: ATtiny microcontroller support for the Arduino IDE

ATtiny microcontroller support for the Arduino IDE - damellis/attiny

github.com

깃허브에보면 암호(Code) 라고 되어 있는 녹색 버튼을 클릭해보면 "ZIP다운로드" 가 보일텐데 클릭해서 다운로드 받고, 
윈도 실행창(단축키 : 윈도 + R키) 에서 appdata를 입력해서 C:\Users\User\AppData\Local\Arduino15  와같은 경로로 찾아 들어가서 다운로드한 ZIP파일을 압축을 해제해서 넣어 주고 아두이노를 다시 실행시켜주면, 보드 검색이 될거예요.

attiny 보드 라이브러리가 추가 되었다면 아래내용으로 계속 진행해 주세요.

- 아래 이미지, 아두이노 IDE 메뉴 》 툴 》에서 , 
  보드 :  ATtiny25/45/85 ,   프로세서 : ATtiny85 ,   Clock : "Internal 8 MHz"  로 선택하고  
  포트는 자신의 아두이노 ISP 보드가 연결된 포트 번호를 선택하세요.

 이때, 프로그래머는 : 반드시 "Arduino as ISP"로 선택하세요.  ('ArduinoISP'는 아니에요! X )

- 아래 이미지,  다음 부트로더 굽기를 누르면  AVR ISP로 동작하는 아두이노 우노를 통해 ATtiny85칩의 플래시 메모리의 부트로더 영역에 부트로더가 탑재됩니다. 

- 아래 이미지, "부트로더 굽기 완료" 표시가 뜨면 부트로더가 ATtiny85에 탑재 성공한 것이에요.

- 이제 ATtiny는 아두이노 IDE를 통해 코드를 올리고 아두이노처럼 동작할 수 있습니다. 
- 아래 이미지,  그럼 5번 핀(PB0의 0번 포트)에 연결된 LED를 Blink 기본 예제를 올려서 잘 깜빡이는지? 동작을 테스트해 볼게요.

- 잘 깜빡인다면, 딜레이 타임을 조절해서,  예를 들어 delay(400) 으로 바꾸어 다시 업로드 테스트해 보세요.  바뀐 코드 적용도 잘 될거에요.

-  와우~!!!  
여러분은 방금 멋진 작업을 하셨습니다. 
지금의 ATtiny85 칩은 아두이노 처럼 코드 올려서 동작 시킬 수 있게 된 것이죠. 
작고 간단한 일에는 덩치큰 아두이노 우노 형님이 나서지 않더라도, ATtiny85 막내가 충분히 처리할 수 있게 된 것이에요.
그럼, 정말 그런 것인지?  우노와 연결된 케이블이나 전원선을 제거하고 ,  ATtiny85칩에 직접 전원을 넣어 보면,  우노보드 없이 ATtiny 칩만으로도 동작할 수 있는지? 확인이 되겠죠. (아래 이미지)

Data Sheet를 살펴보면, tiny85칩은 기본적으로 동작전원이 '2.7v~5.5v'로 되어 있으니, 부족하거나 오버되지 않도록 주의해 주세요. 

물론 OLED 같은 경우 3.3V 전원이 요구되니 공급전압은 3.3v 이상이어야 전체적으로 동작됩니다.  
따라서 전체 구성되는 모듈들의 최소 요구전압을 확인하여 공급전압을 결정해야 합니다.

---  【 추가 사항 】-------------------------------------------------------------------------------------------------------

ATtiny 보드를 통해 소리(멜로디) 나가도록 하기 위해서는 다른 보드 라이브러리를 설치해서 진행해야 합니다. 

보드 라이브러리 주소는 아래와 같습니다.

https://drazzy.com/package_drazzy.com_index.json

https://drazzy.com/package_drazzy.com_index.json

자세한 사항은 아래 이미지 설명을 참고해 주세요

--------------------------------------------------------------------------------------------------------------------------------

 

 

 - 응용회로로 LED를 여러개 연결하여 ATtiny85의 포트 여러개를 제어하는 연습을 해볼게요.
 - 아래 이미지, 회로 연결도와 코드를 참고하세요.  
 - 순서는 부트로더가 탑재된 tiny85칩에 LED1to5.ino 코드를 업로드  → 순차점멸회로에 코드 업로드된 tiny85칩 연결 → 적절한 외부 전원을 연결하여 동작을 확인함.

이미지를 클릭하면 확대 됩니다

< 아두이노 코드 : 1 to 5 LED 순차 점멸 코드 >

/* LED 5개 순차 점멸 하기  with Tiny85         */
/* Rasino.tistory.com   YouTube: 라즈이노 IoT */
int i=0;
void setup() {
  pinMode(0, OUTPUT);
  pinMode(1, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);    
}

void loop() {
  for (i=0; i<5; i++) { 
    digitalWrite(i, HIGH);   
    delay(200);               
  }
  for (i=4; i>=0; i--) { 
    digitalWrite(i, LOW);   
    delay(200);               
  }
}

(Code download)

LED1to5.zip
0.00MB

<실제 동작 모습>

- 멋지지 않습니까? 이렇게 작은 칩하나로 커다란 아두이노를 대신할 수 있으니 말이죠~!
  물론, 입·출력포트 수가 적고, 메모리 용량이 작아, 아두이노보드 처럼 사용하기에는 제약이 있지만,
  이처럼 작고 단순한 제어나 제품사이즈를 소형화 시켜야하는 프로젝트에는 정말 활용하기 좋습니다
- 여기서 LED에 연결된 저항의 역할은 과도한 전류의 흐름을 조절하여 LED를 보호하는 역할을 해요
- ※ 저항을 먼저 거친 후 LED가 연결되어도 되고, LED를 먼저 거치고서 저항이 연결되어도 됩니다

- 그럼, 이번에는 스위치를 넣어 입력에 따른 출력을 제어할 수 있는지? 간단히 확인해 볼게요
 이 개념이 중요한 이유는? 스위치 대신 다양한 센서로 제어가 가능하다는 뜻이며, LED 대신 OLED와 같은 디스플레이나 모터 같은 것을 제어할 수 있다는 뜻이기 때문입니다. 
- 연결위치는 LED순차 점멸회로에서 5번 LED가 연결된 선을 빼고 스위치를 달아주겠습니다.
  스위치를 누르는 순간 GND와 연결 되어 있어서 LOW ( 0 ) 값이 입력되며, 스위치를 누르지 않았을 때는 확실한 High신호가 입력되도록 하기 위해 4.7KΩ의 저항을 달았어요.  이런 용도의 저항을 풀업(Pull UP)저항이라 하며 보통 1㏀~10㏀ 사이 값을 주로 사용하게 됩니다. 

ATtiny85 LED 순차점등 스위치 제어 연결도

- 코드내용은 스위치를 누르면 LED의 순차 점멸 속도를 더 빠르게 하도록 하였는데요,
 위에서의 과정과 똑같이 UNO로 만든 AVR ISP를 통해 아래 코드를 업로드하세요.

/* 스위치로 LED 순차 점멸 속도 바꾸기 with Tiny85 */
/* Rasino.tistory.com   YouTube: 라즈이노 IoT  */
int i=0; 
int SW;
void setup() {
  pinMode(0, OUTPUT);
  pinMode(1, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, INPUT);    
}
void loop() {
  SW=digitalRead(4);
  if (SW==LOW) {         
    for (i=0; i<4; i++) { 
      digitalWrite(i, HIGH);   
      delay(20);               
    }
    for (i=3; i>=0; i--) { 
      digitalWrite(i, LOW);   
      delay(20);               
    }
  }
  if (SW==HIGH) {         
    for (i=0; i<4; i++) { 
      digitalWrite(i, HIGH);   
      delay(80);               
    }
    for (i=3; i>=0; i--) { 
      digitalWrite(i, LOW);   
      delay(80);               
    }
  }    
}

(Code download)

ATtinyControlLEDSW.zip
0.00MB

<실제 동작 모습>

- 스위치를 누르지 않은 상태에서는 20ms(0.02)초 간격으로 LED가 On/Off 되며,  만약 
  스위치를 누르게 되면 80ms(0.08초) 간격으로 LED가 On/Off 되게 됩니다

- 이번에는 Uno보드 보다 작은 Nano 보드를 이용해서 AVR ISP 전용보드를 만들어 볼게요.
  작업 방법은 Uno 보드에서와 동일합니다.  아래 회로 연결도를 보고 조립해 주세요.

- 만약, ArduinoISP 코드를 업로드 할 때, 아래처럼, avrdude : stk500_getsysc ( ) attempt 10 of 10 : not in sys...  와 같은 에러가 발생한다면,   AVR ISP 회로를 만들면서 Reset 포트에 연결한 콘덴서를 잠시 제거한 후에 업로드 해보세요.   업로드가 완료 된 후에 다시 콘덴서를 꽂아주면 됩니다.

 - 업로드가 완료되면, LED순차회로 코드를 업로드 시켜 동작을 확인해 보세요.

- 아래이미지, 리튬폴리머 배터리를 연결할 때 사용하는 커넥터는 핀이 매우작아 브레드보드에 꽂기가 어려운데요,  아래 이미지에서와 같은 부품을 구해서 납땜으로 핀을 확장해 주면, 브레드보드에도 꽂을 수 있게 됩니다.


여기서 중요한 건,  리튬 이온, 리튬 폴리머와 같은 전지를 사용할 때는, 반드시 합선(전기적으로 +양극과 -음극 단자 연결된 상태)에 주의해야 합니다.  이는 겉으로 보기에 직접적으로 연결되어 보이지 않더라도, 회로적으로 낮은 저항 값으로 인해 합선과 같은 결과가 나타날 수 있으니,  전기전자적 기본지식이 부족하다면, 임의적인 확장이나 선 연결을 자제해 주시기 바랍니다.  그래야 합선으로 인한 소폭발 및 화재를 예방 할 수 있습니다. 

 

- 그럼 이제 tiny85의 기본 사용법을 충분히 익히셨다면, 이제 활용도 높은 응용회로를 만들어 볼게요
- I2C 통신을 이용해 온·습도 센서의 데이터를 받아 OLED에 표시해주는 미니'온습도계'입니다

[ 선수 학습 자료 ]  OLED 온·습도계를 만들기 과정에 참고하면 도움될 사전학습자료 입니다. 

1. 【 아두이노 센서#17】 DHT11 온·습도 센서 다루기 #1

2. 【 아두이노 센서#18】 DHT11 온·습도 센서 다루기 #2

3. 【 아두이노 센서#19】 DHT22 온·습도 센서 다루기 with LCD#3

4. 【 아두이노모듈#29】 OLED 처음 사용 설명서 #1 (SPI, I2C 주요 5종 사용법 안내)

 

 5-1.  DHT11센서 또는 DHT22 센서를 를 활용한 OLED 초소형 온·습도계 회로 연결도를 참고하여 회로를 완성하세요.

DHT11센서와 OLED를 활용한 온습도계 연결도
DHT11센서와 OLED를 활용한 온습도계 연결도

  ※ OLED의 경우에는 아래 이미지처럼, GND와 VCC 단자의 순서가 다른경우가 있으니 잘 보면서 연결하세요.   또한 많은 종류의 OLED는 3.3V 전원과 5V 전원까지 모두 지원하지만, 특정 제조사 모델의 경우 5V로만 동작하는 경우가 있으니 OLED를 구입한 곳(또는 제조사)의 스펙을 확인해 보세요.



5-2.  아래 소스 코드를 ATtiny85에 업로드하세요.
 : 업로드 시에는 위에서 만든 Uno AVR ISP를 이용하거나,  Nano로 만든 AVR ISP 프로그래머를 이용해서 업로드하면 되며,  새로운 칩을 사용할 경우, 부트로더 탑재 단계부터 시작해 주세요,   혹은 기존 부트로더가 올려진 칩에서는 이 단계를 건너뛰고 아두이노 코드를 바로 전송시키면 됩니다. 

 [ 소스 코드 - DHT11 센서용 ]

ATtiny_OLED_DHT11_TinyOzOled.zip
0.00MB

 [ 소스 코드 - DHT22 센서용 ]

ATtiny_OLED_DHT22_TinyOzOled.zip
0.00MB


[ 필수 라이브러리 ] 
- 컴파일 과정에서의 대부분의 에러는 맞지 않은 라이브러리 사용으로 인한 에러이니 반드시 아래 내용을 읽어보세요.

 - 라이브러리는 이름이 같아도 파일의 용량이 다르면 안에 내용이 다르다는 것을 뜻합니다.
서로 다른 사람이 라이브러리를 수정, 추가 또는 만들었기 때문에 제가 코드 작성에 사용한 라이브러리를 그대로 사용하셔야 컴파일 에러가 나지 않습니다.  반드시 아래 첨부해드리는 라이브러리를 설치해서 실행해보세요. 
 - 라이브러리 설치할 때, 가장 깔끔하고 좋은 방법은 아래 이미지 처럼, 아두이노 IDE의 메뉴에서, 
   "스케치 》 라이브러리 포함하기 》 .ZIP 라이브러리 추가...  "  메뉴를 통한 설치입니다. 
   그래서 아래 첨부해드리는 라이브러리를 다운받아 압축을 풀지 않은 채로 .ZIP 라이브러리 추가... 메뉴를 통해 다운받은 라이브러리 압축파일을 선택해서 추가해 주세요.


 1-1.  온습도 센세와 관련된 라이브러리 입니다.  

DHT.zip
0.00MB

 1-2.  OLED 라이브러리 입니다. (플래시 메모리 용량이 적은 ATtiny85에, 사용할 수 있도록 축소시킨 라이브러리 이며, 기본 작은 사이즈의 영문 알파벳 및 숫자 및 아스키 기호를 표시하고, 큰 사이즈의 숫자를 나타낼 수 있게 디자인 되었습니다.   큰 알파벳 X ,  한글 X ,    기타 화면 클리어 ,  출력과 관련된 명령어를 사용할 수 있습니다)

TinyOzOled-master.zip
0.01MB

  1-3.   I2C 통신을 위한 라이브러리 입니다. (아래 압축파일 내부에 'TinyWireM.h' 파일 :  DHT 센서와 그리고 OLED와 같은 I2C 통신을 하는 장치와 Tiny칩과의 I2C 통신을 하는데 필요한 라이브러리 입니다)

ssd1306_minimal.zip
0.02MB

 


【 동작 확인 】
 DHT11 센서와 DHT22센서 회로에 코드를 올리고 전원을 연결하여 동작확인을 해보세요.

DHT11 온습도 센서를 이용한 ATtiny85 회로
DHT22 온습도 센서를 이용한 ATtiny85 회로

DHT22 센서를 이용하면, 데이터 값이 소숫점 1자리까지 DHT11센서보다 정밀하게 표시 됩니다. 

끝으로,  아래 이미지에 보이는 것 처럼, 용도와 목적에 맞게 다양한 전원을 활용할 수 있습니다. 
- 3.7V 리튬폴리머 배터리,  - 3.7v 리튬이온 배터리,  4.5V AA건전지(1.5V AA x 3개 직렬 소켓 활용) , 
  3.0V CR2032 무수은전지(리튬)  ,  여기서 DHT센서와 OLED모듈의 구동전압이 최하 3.3v 이상이 되어하 합니다.  하지만, 3V로 구동되는 회로 제작시 참고될 수 있도록 연결해 본 것입니다.   아래 다양한 전원사용은 영상을 참고하면 명확하게 확인 가능합니다.

 

[ 에러 체크리스트 ]

[코드 컴파일 과정과 하드웨어 조립과정에서 예상할 수 있는 에러에 대한 체크 리스트]

 

 

【  전체 과정 영상으로 학습하기!  】

 

 

[ 만약,  ATtiny84를 활용하신다면,  아래 링크를 참고해 보세요.  매우 정리가 잘 되어 있습니다 ]
https://blog.naver.com/jehongjeon/222509007422

 

ATtiny84 / 85 OLED 구동 (PORT_USI was not declared in this scope 해결)

안녕하세요 jehongjeon 입니다 어느새 방학이 끝나고 다시 학기가 시작했네요 이번 학기는 작품 만들기 &am...

blog.naver.com

 

반응형
반응형

【 아두이노프로젝업뎃#1 ESP8266 esp-01 스마트폰으로 LED 컨트롤 하기 업뎃 자료

 

먼저 아래 기존 게시글을 참고하세요. 

【 아두이노모듈#28】 ESP8266 esp-01 활용하기#4 : 스마트폰으로 LED 컨트롤 하기(with Arduino & cp2102 )

 

이번 글은 기존 프로젝트에서 LED를 완전히 개별로 제어가능하도록 코드를 일부 수정하여 게시하오니 참고하세요. 

 

 

[ 관련 영상 보기 ]

 

 

수정된 코드 

/*  ### 스마트폰 WiFi로 esp8266모듈회로의 LED 켜고·끄기 ### 
 *  1. LED를 연결한 esp8266 회로를 서버로 동작시킨다. 
 *  2. 앱인벤터를 이용하여 접속앱을 직접 제작 한다.
 *  3. 접속앱에서 esp8266 서버 주소를 입력하고 접속한다. 
 *    (접속 IP 주소는 코드 업로드가 완료되면 시리얼모니터(115200bps)를 통해 확인 가능함)
 *  4. 앱화면의 버튼을 눌러 LED를 On·Off 할 수 있다.(GPIO0(LED1), GPIO2(LED2))
 *  5. 아두이노 우노를 제거하고 미니 전원을 연결하여 소형화 된 무선 WiFi 모듈을 구성해본다.  
 *    http://server_ip/gpio0/0 이면 GPIO0(LED1) 를 LOW로 설정,
 *    http://server_ip/gpio0/1 이면 GPIO0(LED1) 를 HIGH로 설정,
 *    http://server_ip/gpio2/0 이면 GPIO2(LED2) 를 LOW로 설정,
 *    http://server_ip/gpio2/1 이면 GPIO2(LED2) 를 HIGH로 설정,
 *    
 *  주의 : 반드시 동일한 내부 네트웍(하나의 공유기로 연결된)에서 동작 시켜야 접속이 이루어 집니다. 
 *  
 *  제작과정의 좀더 상세한 내용과 설명 영상은 http://rasino.tistory.com/300 참조 하세요 
 */

#include <ESP8266WiFi.h>
#define GPIO0 0
#define GPIO2 2
int GP0val=0;
int GP2val=0;

const char* ssid = "XXXXXXX";         //  접속가능한 공유기(AP) WiFi의 ID를 입력하세요
const char* password = "xxxxxxx";    // 공유기(AP) WiFi의 접속 패스워드를 입력하세요
// 서버 인스턴스를 생성합니다 (80번 포트 지정)
WiFiServer server(80);

void setup() {
  Serial.begin(115200);
  delay(10);
  // GPIO 포트들을 초기화 합니다
  pinMode(GPIO0, OUTPUT);
  digitalWrite(GPIO0, 0);
  pinMode(GPIO2, OUTPUT);
  digitalWrite(GPIO2, 0);
  // Serial 통신으로 WiFi 네트웍에 연결합니다.
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  WiFi.begin(ssid, password);  // 네트웍에 설정된 id와 패스워드로 접속을 합니다.
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  
  // 서버 시작
  server.begin();
  Serial.println("Server started");

  // 서버의(esp8266) IP 주소를 출력합니다 
  Serial.println(WiFi.localIP());
}

void loop() {
  
  // 클라이언트가 접속하는지 체크 합니다
  WiFiClient client = server.available();
  if (!client) {
    return;
  }
  
  // 클라이언트가 데이터를 보낼 때까지 기다립니다.
  Serial.println("new client");
  while(!client.available()){
    delay(1);
  }
  
  // 요청 첫 출을 읽어 옵니다.
  String req = client.readStringUntil('\r');
  Serial.println(req);
  client.flush();
  
  // 요청 사항과 비교 후 GPIO들에 대해 셋팅 해줍니다.
  
  if (req.indexOf("/gpio0/0") != -1){
    GP0val = 0;
    digitalWrite(GPIO0, GP0val);
  }
  else if (req.indexOf("/gpio0/1") != -1) {
    GP0val = 1;
    digitalWrite(GPIO0, GP0val);
  }
  else if (req.indexOf("/gpio2/0") != -1) {
    GP2val = 0;
    digitalWrite(GPIO2, GP2val);  
  }
  else if (req.indexOf("/gpio2/1") != -1) {
    GP2val = 1;
    digitalWrite(GPIO2, GP2val);  
  }
  else {
    Serial.println("invalid request");
    client.stop();
    return;
  }

  client.flush();
  // 응답을 준비합니다.
  String s1 = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n \r\n\r\nGPIO 0 is now ";
  String s2 = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n \r\n\r\nGPIO 2 is now ";
  s1 += (GP0val)?"HIGH":"LOW";   //GP0val 값에 따라 HIGH 또는 LOW 응답합니다.
  s1 += "\n";
  s2 += (GP2val)?"HIGH":"LOW";   //GP2val 값에 따라 HIGH 또는 LOW 응답합니다.
  s2 += "\n";

  // 클라이언트로 응답을 보냅니다
  client.print(s1);
  delay(1);
  client.print(s2);
  delay(1);
  Serial.println("Client disonnected");  // 응답완료 후에는 클라이언트를 닫습니다.
}

 

[코드 다운로드]

WiFiWebLED3.zip
0.00MB

 

반응형
반응형

아두이노 프로젝트#12아두이노 나노(Nano) OLED 탁상시계 (with Calendar & 온도계)

 쉽게 구할 수 있는 나노와 OLED를 가지고 책상 위에 올려놓을 수 있는 멋진 미니 탁상시계를 만들어보세요!

또한 3D 프린팅을 이용해서 꼭 맞는 깔끔한 케이스를 만드는 과정도 담았으니 끝까지 보셨으면 합니다.

 

 

실습 재료 목록

 : 아래 표와 이미지를 참고하여 실습재료를 준배해 주세요

 

 

[ 주요 부품 스팩 ]

 나노(Nano Pin Map) 보드 핀 맵은 아래와 같습니다. 

OLED 사용을 위한 관련 지식 및 자료

(실습에 사용되는 OLED는 SSD1306 드라이버를 사용하는 I2C 타입입니다)

 

아래는 우노 보드와의 기본 연결이며, 나노보드와의 연결도 동일합니다.

우노 보드와의 기본 연결이며, 나노보드와의 연결도 동일합니다

 

우노보드와 나노보드에서 OLED와의 I2C 통신을 위한 SDA핀과 SCL핀의 번호는 동일하며,  기타 메가보드나 레오나르도보드 사용 시의 핀 번호는 다르기 때문에 아래 표를 참고하세요.  (SDA핀과 SCL핀 번호는 보드마다 지정되어 있으니 반드시 해당 핀으로 연결해야 I2C 통신이 됩니다.)

추가적으로 OLED관련해서 다른 타입의 OLED를 사용하려 하거나 관련 정보가 필요하다면 아래 게시글을 먼저 살펴보시기 바랍니다. 

※ 【 아두이노모듈#29】 OLED 처음 사용 설명서 #1 (SPI, I2C 주요 5종 사용법 안내)

 

DS3231  RTC 모듈 핀 맵

 'SCL, SDA, VCC, GND' 핀은 사용상의 편의를 위해 좌우측에 동일한(서로 연결된) 핀을 배치하였기 때문에 

연결하기 편한 쪽으로 연결하면 됩니다.

DS3231 모듈의 특징은,  DS1307 모듈보다 정밀한 RTC기능(리얼타임클럭)을 제공하며  보드에 온도센서를 포함하고 있어,  RTC 모듈의 주변 온도값 데이터를 얻을 수 있는 특징이 있습니다. 가격도 매우 저렴하기 때문에,  DS1307보다는 DS3231 RTC모듈을 적극 추천합니다. 

 

브레드 보드 내부 핀의 연결 구조

 

 

 아두이노 탁상시계 회로 연결도

 

 아두이노 코드

 

/**** 참고 : https://simple-circuit.com/arduino-ssd1306-oled-ds3231-rtc/ ***/ 
/* 편집 : 상세한 한글 주석과 연도 표시를 한국식 (yyyy/mm/dd)으로 수정함          */
/* 기타 추가 자료 참고는 여기를 방문하세요 : http://RasINO.tistory.com         */
/**************************************************************************/
#include <SPI.h>
#include <Wire.h>                // I2C 장치 사용을 위한 선언(현재 버전의 IDE사용시 생략가능)
#include <Adafruit_GFX.h>        // Adafruit graphics library 사용
#include <Adafruit_SSD1306.h>    // Adafruit SSD1306 OLED 드라이버 사용
 
#define OLED_RESET -1            // -1은 아두이노 보드 리셋과 연동 됨.
Adafruit_SSD1306 display(128, 64, &Wire, OLED_RESET);  // 128 x 64 OLED 사용시 

#define button1    11   // 버튼1을 나노 11번 핀으로 (설정버튼-무브) 설정함
#define button2     3   // 버튼2는 나는 3번 핀으로 (숫자 증가버튼) 설정함

void setup(void) {
  Serial.begin(9600);
  pinMode(button1, INPUT_PULLUP);  // 풀업 저항을 생략하기 위해 INPUT_PULLUP으로 선언함
  pinMode(button2, INPUT_PULLUP);  // 풀업 저항을 생략하기 위해 INPUT_PULLUP으로 선언함
  delay(1000);
   
  // OLED 초기화
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // OLED후면 설정(납땜)에 따라 주소를 0x3D로 바꿀 수 있음
  
  display.clearDisplay();  // 디스플레이 버퍼에 들어 있는 내용을 클리어 함
  display.display();       // 현재의 디스플레이 버퍼 내용을 출력해봄
 
  display.setTextColor(WHITE, BLACK);
  display.drawRect(117, 56, 3, 3, WHITE);   // 온도 표시를 위한 기호 ( ° ) 출력
  draw_text(0, 56, "TEMPERATURE =", 1);
  draw_text(122, 56, "C", 1);
}
 
char Time[]     = "  :  :  ";
char Calendar[] = "20  /  /  ";
char temperature[] = " 00.00";
char temperature_msb;
byte i, second, minute, hour, day, date, month, year, temperature_lsb;
 
void display_day(){
  switch(day){
    case 1:  draw_text(40, 0, " SUNDAY  ", 1); break;
    case 2:  draw_text(40, 0, " MONDAY  ", 1); break;
    case 3:  draw_text(40, 0, " TUESDAY ", 1); break;
    case 4:  draw_text(40, 0, "WEDNESDAY", 1); break;
    case 5:  draw_text(40, 0, "THURSDAY ", 1); break;
    case 6:  draw_text(40, 0, " FRIDAY  ", 1); break;
    default: draw_text(40, 0, "SATURDAY ", 1);
  }
}
 
void DS3231_display(){
  // Convert BCD to decimal  (10진수 형태의 시간과 날자를 출력하기 위한 변환)
  second = (second >> 4) * 10 + (second & 0x0F);
  minute = (minute >> 4) * 10 + (minute & 0x0F);
  hour   = (hour >> 4)   * 10 + (hour & 0x0F);
  date   = (date >> 4)   * 10 + (date & 0x0F);
  month  = (month >> 4)  * 10 + (month & 0x0F);
  year   = (year >> 4)   * 10 + (year & 0x0F);
  // End conversion

  // 각 요소별로 10의 자리와 1의 자리를 분리하여 저장
  Time[7]     = second % 10 + 48;     // 초의 1의 자리값 저장
  Time[6]     = second / 10 + 48;     // 초의 10의 자리값 저장
  Time[4]     = minute % 10 + 48;
  Time[3]     = minute / 10 + 48;
  Time[1]     = hour   % 10 + 48;
  Time[0]     = hour   / 10 + 48;
  Calendar[9] = date   % 10 + 48;
  Calendar[8] = date   / 10 + 48;
  Calendar[6] = month  % 10 + 48;
  Calendar[5] = month  / 10 + 48;
  Calendar[3] = year   % 10 + 48;
  Calendar[2] = year   / 10 + 48;
 
  // 온도가 0도씨 이하가 되면 온도 앞에 '-' 기호를 붙여줌
  if(temperature_msb < 0){
    temperature_msb = abs(temperature_msb);
    temperature[0] = '-';
  }
  else
    temperature[0] = ' ';
    
  
  temperature_lsb >>= 6;   // temperature_lsb = temperature_lsb >> 6 (온도하위비트 비트이동 후 다시 저장)  
  temperature[2] = temperature_msb % 10  + 48;  // 온도값 1의 자리 저장
  temperature[1] = temperature_msb / 10  + 48;  // 온도값 10의 자리 저장
  if(temperature_lsb == 0 || temperature_lsb == 2){
    temperature[5] = '0';
    if(temperature_lsb == 0) temperature[4] = '0';
    else                     temperature[4] = '5';
  }
  if(temperature_lsb == 1 || temperature_lsb == 3){
    temperature[5] = '5';
    if(temperature_lsb == 1) temperature[4] = '2';
    else                     temperature[4] = '7';
  }
 
  draw_text(4,  14, Calendar, 2);    // 한국식(yyyy/mm/dd) 형태로 날짜 출력
  draw_text(16, 35, Time, 2);        // 시간 출력 
  draw_text(80, 56, temperature, 1); // 온도 출력
}

// 날짜, 요일, 시간 등 수정을 위한 블링크 루틴
void blink_parameter(){
  byte j = 0;
  while(j < 10 && digitalRead(button1) && digitalRead(button2)){
    j++;
    delay(25);
  }
}

// edit함수 : 버튼 눌림에 따른 날짜, 시간 등 각각의 수정된 값들을 저장하는 루틴 
// 버튼1을 눌러 수정모드가 된 후 버튼2를 눌러 각각의 값을 변경함
byte edit(byte x_pos, byte y_pos, byte parameter){
  char text[3];
  sprintf(text,"%02u", parameter);
  while(!digitalRead(button1));                      // 버튼1이 눌러지면(GND 신호이면)
  while(true){
    while(!digitalRead(button2)){                    // 버튼2가 눌러지면(GND 신호이면)
      parameter++;
      if(i == 0 && parameter > 31)                   // 날짜가(date > 31)이면  date = 1 로
        parameter = 1;
      if(i == 1 && parameter > 12)                   // 달이(month > 12) 이면  month = 1 로
        parameter = 1;
      if(i == 2 && parameter > 99)                   // 연도가(year > 99) 이면 year = 0 로
        parameter = 0;
      if(i == 3 && parameter > 23)                   // 시간이(hours > 23) 이면 hours = 0 로
        parameter = 0;
      if(i == 4 && parameter > 59)                   // 분이(minutes > 59) 이면 minutes = 0 로
        parameter = 0;
      sprintf(text,"%02u", parameter);               // 파라메터 숫자 값을 문자열 값으로 변환함
      draw_text(x_pos, y_pos, text, 2);              //  
      delay(200);                                    // 200ms 기다려줌
    }
    draw_text(x_pos, y_pos, "  ", 2);
    blink_parameter();
    draw_text(x_pos, y_pos, text, 2);
    blink_parameter();
    if(!digitalRead(button1)){                       // If button B1 is pressed
      i++;                                           // Increament 'i' for the next parameter
      return parameter;                              // Return parameter value and exit
    }
  }
}

// 전달받는 파라메터 값에 따라 문자를 OLED 디스플레이에 출력해주는 루틴
// 표시할 x y 좌표위치와, 출력할 내용(저장된 주소값), 문자 크기 
void draw_text(byte x_pos, byte y_pos, char *text, byte text_size) {
  display.setCursor(x_pos, y_pos);
  display.setTextSize(text_size);
  display.print(text);
  display.display();
}
 
void loop() {
  if(!digitalRead(button1)){                         // 버튼1(수정)이 눌러 진다면
    i = 0;
    while(!digitalRead(button1));                    // 버튼1이 눌렀다 떼어지는 것을 체크
    while(true){
      while(!digitalRead(button2)){                  // 버튼2가 눌러질 때마다
        day++;                                       // 요일 증가
        if(day > 7) day = 1;                         // 7요일 째에는 다시 SUNDAY로 리셋  
        display_day();                               // 버튼 누를 때마다 요일을 OLED화면에 표시 
        delay(200);                                  // 200 ms 기다려줌
      }
      draw_text(40, 0, "         ", 1);              // 깜빡임을 위해 요일 자리의 내용을 공백으로 지움
      blink_parameter();                             
      display_day();                                 // 다시 요일을 화면에 표시
      blink_parameter();                             
      if(!digitalRead(button1))                      // 버튼1이 (다시) 눌러진다면
        break;                                       // 요일 변경 루틴을 빠져 나감 
    }
 
    date   = edit(100, 14, date);                    // date 날짜 수정
    month  = edit(64, 14, month);                    // month 달 수정
    year   = edit(28, 14, year);                     // year 연도 수정
    hour   = edit(16, 35, hour);                     // hour 시간 수정
    minute = edit(52, 35, minute);                   // minutes 분 수정
    // 시간의 십진값을 BCD 코드 값으로 변환 (Convert decimal to BCD)
    minute = ((minute / 10) << 4) + (minute % 10);   // (십의 자리값)+(일의 자리값)
    hour = ((hour / 10) << 4) + (hour % 10);
    date = ((date / 10) << 4) + (date % 10);
    month = ((month / 10) << 4) + (month % 10);
    year = ((year / 10) << 4) + (year % 10);
    // 변환 구간 끝
 
    // 위에서 수정한 요일, 날짜, 시간등의 데이터 값을 I2C통신을 통해 DS3231 RTC 모듈에 기록함 
    Wire.beginTransmission(0x68);               // I2C 통신에 필요한 DS3231 모듈의 고유한 주소 값(0x68) 호출
    Wire.write(0);                              // 기록할 레지스터 주소 지정(Send register address)
    Wire.write(0);                              // 0초 리셋 후 초 발진기 스타트(Reset seconds and start oscillator)
    Wire.write(minute);                         // minute 분   값 기록
    Wire.write(hour);                           // hour   시간 값 기록
    Wire.write(day);                            // day    요일 값 기록
    Wire.write(date);                           // date   날   값 기록
    Wire.write(month);                          // month  달   값 기록
    Wire.write(year);                           // year   연도 값 기록
    Wire.endTransmission();                     // 전송 종료
    delay(200);                                 // 200ms 기다려 줌
  }

  // 아래부터는 기본적으로 요일, 날짜, 시간등의 데이터 값을 I2C통신을 통해 DS3231 RTC 모듈로부터 읽은 다음 OLED에 표시하는 코드
  Wire.beginTransmission(0x68);                 // DS3231의 호출 주소를 통해 I2C 통신을 시작함
  Wire.write(0);                                // 읽어올 레지스터 주소 지정(Send register address)
  Wire.endTransmission(false);                  // I2C 재시작(restart)
  Wire.requestFrom(0x68, 7);                    // 'DS3231'로부터 날짜와 시간 값들이 저장되어 있는 7 byte(8bit씩 7개)의 값을 읽어 들인다
  second = Wire.read();                         // 0번 레지스터로부터 초 값을 읽어 'second'에 저장
  minute = Wire.read();                         // 1번 레지스터로부터 분 값을 읽어 'minuts'에 저장
  hour   = Wire.read();                         // 2번 레지스터로부터 시간 값을 읽어 'hour'에 저장
  day    = Wire.read();                         // 3번 레지스터로부터 요일 값을 읽어 'day'에 저장
  date   = Wire.read();                         // 4번 레지스터로부터 날 값을 읽어 'date'에 저장
  month  = Wire.read();                         // 5번 레지스터로부터 달 값을 읽어 'month'에 저장
  year   = Wire.read();                         // 6번 레지스터로부터 연도 값을 읽어 'year'에 저장
  Wire.beginTransmission(0x68);                 // DS3231의 호출 주소를 통해 I2C 통신을 시작함
  Wire.write(0x11);                             // 읽어올 레지스터 주소 지정(0x11)
  Wire.endTransmission(false);                  // I2C 재시작(restart)
  Wire.requestFrom(0x68, 2);                    // 'DS3231'로부터 온도값이 저장되어 있는 2 byte(8bit씩 2개)의 값을 읽어 들인다
  temperature_msb = Wire.read();                // 상위(읽는 순서대로) 온도 비트를 읽어 'temperature_msb' 저장한다 
  temperature_lsb = Wire.read();                // 하위(읽는 순서대로) 온도 비트를 읽어 'temperature_lsb' 저장한다
 
  display_day();                                // 요일 출력 루틴 호출하여 출력
  DS3231_display();                             // 시간과 날자 출력 루틴 호출하여 출력
 
  delay(50);                                    // 50ms 딜레이 줌
}

아두이노 코드 파일 다운로드

Nano_OLED_DS3231_II_kr_1.zip
0.00MB

 

 만약 코드 업로드시 에러가 난다면, arduino nano 보드의 프로세서 옵션을  Old Bootloader로 선택해서 다시 업로드 해보세요.   아두이노 IDE 버전이 1.8.8 버전 이상을 사용하거나,  CH340, CH341과 같은 호환 통신칩셋을 사용한 나노 보드의 경우 업로드시 IDE메뉴,  툴 》 프로세서 "ATmega328P" 옵션에서,   "ATmega328P (Old Bootloader)"로 선택해 주어야 에러가 나지 않습니다. 

화면을 클릭하면 확대 가능합니다.

 

코드 업로드 및 동작 확인

: 회로 전체를 조립한 후 회로를 조립하고 코드를 업로드한 후 동작을 확인해 보세요

 미니 브레드보드 블럭을 끼워 연결하는 방향에 따라,  여러 가지 형태의 시계를 만들 수 있어 좋습니다.

  

3D 모델링 툴을 활용한 탁상시계 케이스 디자인

: 회로 조립과 동작은 시켰는데, 뭔가 아쉽죠?  그래서 3D 프린터로 깔끔하게 케이스를 만들어 봤습니다.  물론 주변에 아크릴 케이스 같은 걸 활용해도 좋습니다. 

 3D 모델링을 위해 사용한 디자인 툴은 라이노3D (Rhino 3D)입니다. 

3D 모델링 툴은 Rhino, fusion360, 123 Design 등 여러가지가 있지만, 비용이나, 각각의 장단점 및 특색이 있기 때문에 누구의 추천이 아니라, 본인이 지향하는 방향과 맞는 툴을 선택하시는 것이 좋습니다. 

 

모델링의 순서는 브레드보드에 꽂은 형태의 완성품을 가지고 가로x세로x높이를 측정한 다음, 케이스의 두께를 결정하고 OLED 디스플레이의 위치를 설계하는 순서로 설계했고요,  케이스 우측에는 나노의 USB mini 케이블 단자를 여유 있게 꽂을 수 있는 크기의 사각 구멍을 뚫어 주었습니다. 

그리고, 케이스의 커버는 접착제 없이 끼우고 뺄수 있는 디자인을 위해,  치수 계산을 좀 정밀하게 하여, 어느 정도 단단히 끼우거나 빠질 수 있도록 설계했습니다. 

 그리고 한 가지, 3D 프린팅을 위한 디자인에서는 프린팅되는 형태를 감안한 설계가 필요한데요,  가령 예를 들어, 위쪽 커버를 만들 때,  로고를 전면에 붙이면서, 양각으로 튀어나오게 하다 보니, 반대편에도 홈에 끼우기 위한 라인이 양각으로  즉,  상하 모두 튀어나오는 디자인으로 설계되다 보면, 3D 프린팅 과정에서 결과물이 뭉개지거나 기대하는 모양을 얻기가 어렵습니다.  따라서 로고를 음각으로 하여 뒤집어 출력하도록 하면 평평한 바닥부터 위쪽을 쌓아 올리듯 했을 때 문제없이 프린팅 됩니다.   #캡스톤디자인

 

《 3D 프린팅의 순서(생성 파일 기준) 》

: 3D 프린팅을 위해서는 프린팅에 필요한 파일을 생성해야 합니다.  모델링 설계 단계부터 생성되는 파일이 각각 있기 때문에  생성파일의 유형을 가지고 "3D 제품 모델(링) 프린팅"의 전체 흐름을 파악할 수 있습니다.  

 

아래가 그 순서입니다. (모델링 툴에 따라 파일 확장자는 다를 수 있습니다)

1. 3D 모델링 툴을 이용하여 모델링 파일 생성하기.  라이노의 경우 "xxx.3dm" 으로 작업 파일 저장 후 

   다음 단계에 사용될 파일(대표적으로, "xxx.stl" )을 Export(출력) 함.

2.  큐라(Cura)라는 대표적인 슬라이싱 프로그램을 통해 3D 모델링 파일을 한 층씩 슬라이싱 한 데이터 형태로 만들어 G-Code파일을 Export(출력)함.  :  FDM 방식의 3D 프린터는 X-Y-Z 축의 좌표 형태로 움직이면서 익스투루더의 노즐로 가열된 필라멘트를 출력시켜 한 층씩 쌓아가면서 출력물을 만들게 됩니다.  이를 위해 큐라 프로그램에서 3D 프린터에서 필요한 X-Y-Z축 좌표 코드 즉, G-Code라 하는데,  이 G-Code형태의 파일을 Export(출력)해서 , 이 파일을 가지고 3D프린터기에 입력하면 해당되는 출력물을 얻게 됩니다.   

 정리하면, 

[  3D 모델링 툴(라이노)에서 "xxx.stl" 파일 생성 》  큐라(Cura)에서 G-Code 파일("xxx.gcode") 생성 》 3D프린터로 출력 ]

아래는 대표적인 슬라이싱 프로그램인 큐라에서의 셋팅 모습입니다. 

 

아래는 큐라에서 생성한 G-Code파일을 열어본 모습입니다.  X-Y-Z 축의 좌표 등과 같은 데이터가 들어 있는 것을 알 수 있습니다. 

 

아래는 큐라에서 생성한 G-Code파일을 입력하여 모델링 파일을 출력하고 있는 모습입니다.

(프린터 모델은 CR-10 S4 기종을 사용하고 있습니다)

아래는 최종 출력물 모습입니다.

최종 조립전에, 케이스의 높이로 인해 OLED가 너무 깊숙이 들어가 있어, OLED를 최대한 잘 보이도록 위로 돌출시키기 위해,  OLED의 핀헤더를 좀 더 긴 것으로 연결하여 교체해보았습니다. (납땜 작업을 위한 인두기와 솔더 필요)

 

 

그럼,  조립회로를 넣어 최종 조립해보겠습니다.

케이스 하나 만들어 넣었을 뿐인데,  무언가 완성감 있는 만족도가 있어 좋습니다. 

 

 3D 모델링 툴을 활용한 탁상시계 케이스 디자인에 사용한 파일 다운로드 받기

  1.  3D 모델링 작업 파일 (라이노 3D Ver5 )

 

Nano_OLED_case5.3dm
0.49MB

 2.   큐라(Cura)와 같은 슬라이싱 툴에서 편집 가능한 파일 

NaOLED2.stl
1.18MB

 3.  FDM 방식의 3D 프린터에서 바로 출력 가능한 G-Code 파일 

 

NaOLED3.gcode
1.34MB

 

※ 위의 파일을 다운받아 그대로 출력해보셔도 좋고, 아니면, 본인의 보드 디자인에 따라,  이래저래 바꾸어 보며, 연습해보시면 학습에 많은 도움이 될 것으로 기대합니다.  때문에,  파일의 편집 수정 요청은 말아주셨으면 합니다. ^^;

 

 아래 영상도 함께 참고하면 전체 흐름을 파악하는데 도움되실 듯합니다.

< 전체 학습 및 제작과정 영상 보기 >

 

 

 

 

 

 

 

 

반응형
반응형

MFRC522 RFID with Nano 33 iot #1아두이노 나노(33 IoT) 보드에 RFID 카드 모듈 사용해 보기!
( feat.  RFID 컴파일 오류 있는 경우도 보세요! )

 

  Nano 33 every(또는 33 iot 등)에서 RFID를 사용해보려 하는데요,  MFRC522 RFID 모듈사용시 컴파일 오류가 일어나는 경우에 대해 먼저 짚고 넘어가 보도록 하겠습니다. 

대표적으로 컴파일 과정에서 오류가 일어나는 경우에는 예전에 설치한 RC522드라이버가 더이상 현재의 아두이노 IDE툴 버전에서는 제대로 작동되지 않아서인 경우가 주요 원인이라고 보시면 됩니다. 

참, 그리고 아두이노 nano every(33 iot)라고 해서 기존의 nano와 핀 배열 및 기본적인 사용법은 크게 다르지 않기 때문에 보드 종류의 문제는 아닙니다.  

 

먼저 지난번 아두이노 우노에서 RC522 모듈을 적용한 이후 새로운 RC522 드라이버가 업데이트 되었는데요, 가장 최근에 것을 다시 다운로드 받아, 아두이노 IDE에서 드라이버를 설치해주시면 됩니다. 

아래가 사이트 링크입니다. 

www.arduinolibraries.info/libraries/mfrc522

 

MFRC522

Arduino RFID Library for MFRC522 (SPI)

www.arduinolibraries.info

아래에 있는 드라이버를 다운로드 받아
 아두이노 IDE 메뉴에서  " 스케치 》 라이브러리 포함하기 》 .ZIP 라이브러리 추가...  " 로 간단히 추가할 수 있습니다.

MFRC522-1.4.7.zip
1.16MB

그리고 아래 처럼, 예제 파일 ReadNUID를 불러온 후 컴파일 해보세요.

(모든 이미지는 클릭하면 확대 됩니다.)

 그런 다음 아래와 같이 nano 보드와 연결된 포트를 확인 또는 제대로 선택하세요.  (자신이 연결한 보드로 선택)

 

 그리고서 연결된 보드로 업로드해 주세요. 

이미지 처럼 업로드 완료가 뜨면 됩니다.

나노 33 IoT 보드 핀맵은 아래와 같습니다.
(보드상의 Pin Out은 구형 Nano 보드 = Every 보드 = Nano 33 IoT 보드 등과 동일합니다)

나노 33 IoT 핀 아웃

- 아래는 아두이노 사이트에서 제공하는 나노 33 IoT 보드의 핀 아웃 모습

나노 33 iot 핀 아웃

 

- 아래는 아두이노 사이트에서 제공하는 나노 에브리(every)의 핀 아웃(Pin Out) 모습입니다.

나노 에브리(every) 핀 아웃

※ 보이는 것처럼 나노 33 IoT 버전과 에브리(every)의 보드상의 핀 아웃은 일치함을 알 수 있습니다. 이는 구형 Nano 보드와도 일치하기 때문에 구형 나노보드에서 사용했던 연결을 그대로 every 보드 등에 대해서도 똑 같이 연결하면 대부분의 경우 작동 됩니다.   다만, 위에서 설명드린 것처럼, 아두이노IDE 오래전 버전에서 작업이 되었던 특정 모듈의 경우,  코드 컴파일 부분에서 에러가 날 수 있으니,  해당 모듈의 제조사 페이지 또는 깃허브 등에서 찾아 업데이트 후 다시 시도해보면 대부분 해결 됩니다. 

 

 

아두이노 나노 33 IoT와 RFID-RC522모듈의 연결

아두이노 나노 33 IoT와 RFID-RC522모듈의 연결

 

동작 실행

 코드가 나노에 업로드 되었다면 UID카드를 가져다 대어 보면,  아래처럼 카드에 따라 각각의 고유한 ID가 인식되는 것을 확인 할 수 있습니다. 

 

 

작업 영상 보기
 

 

반응형
반응형

『 매번 물주기 귀찮은 화분!  말라죽는 우리집 화분을 구해주세요!   
아두이노 활용 프로젝트 콘텐츠 소개! 』

 

《 기존 프로젝트 '아두이노 Uno에 LCD와 FND를 붙여 제작한 기본 버전 :  rasino.tistory.com/217 》 참고

 

IoT를 접목하여 더욱 작고 스마트하게 업그레이드 된 스마트 화분 』을 만들어 보세요~!
수분 공급을 자동으로 해주고 ThingSpeak 앱과 웹에서 접속하여 화분의 상태를 확인하고 데이터를 엑셀 등의 파일로 관리할 수 있는 IoT 스마트 화분입니다!

 

1. 학습 영상에서 다루는 내용 :

2. 영상에 사용되는 D1 mini 의  제원 소개 :

 

3.  수분 자동 공급 IoT 스마트 구성 개념도 (상세한 연결 도면은 영상을 통해 다운받으실 수 있습니다.)

 

4. ThingSpeak 클라우드 서버 활용 모습:

 


5. 영상 마지막에 기본 모듈의 단점을 보완한 업그레이드 버전까지 포함되어 있습니다.

단점을 보완한 업그레이드 버전 제공!

 

 

6. 콘텐츠 영상 보는 방법 :

매번 말라죽는 화분이 나오는 우리 집! 이제 화분 관리로부터 해방시켜 주세요~!

아두이노 프로젝트 : ESP8266칩셋의 D1 mini 를 활용하여 물을 자동으로 공급할 수 있는 스마트 화분입니다.

프로젝트 수준 : 아두이노 기초를 조금이라도 해보신 분 또는 간단한 아두이노 프로젝트를 해보신 분은 영상을 따라 충분히 하실 수 있습니다.

콘텐츠 영상 보기 : https://www.udemy.com/courses/search/?src=ukw&q=%EC%8A%A4%EB%A7%88%ED%8A%B8+%ED%99%94%EB%B6%84

 

온라인 강좌 - 자신의 일정에 맞춰 뭐든지 배워 보세요 | Udemy

Udemy는 130,000개 이상의 강좌와 35백만 명 이상의 수강생이 있는 온라인 학습 및 교수 마켓플레이스입니다. 프로그래밍, 마케팅, 데이터 과학 및 그 밖의 분야에 대해 배워 보세요.

www.udemy.com

시청 방법 : 위 링크를 따라 Udemy.com 에 접속하여 회원가입 하고, 검색창에 "스마트 화분" 검색 후 위 영상을 구매 후 이용하시면 됩니다.

(구입 특징 : 영상의 유통기한 없이 계속 시청가능하며, PC뿐 아니라 스마트폰으로도 학습이 가능합니다. 현재, 할인 행사 중에 있으며, 만약 할인 행사가 종료 되었을 경우 댓글로 남겨주시면 본 영상의 할인 쿠폰을 발행해 드립니다 )

책 한권 사셨다 생각하시고 활용하기 좋은 교육 콘텐츠 구매해서 멋진 프로젝트에 도전해 보세요~ ^^

 

 

반응형
반응형

에러 디버깅  아두이노 스케치 IDE 사용중 'WProgram.h ' 라이브러리 에러 발생!

 

『 아두이노 실행시 라이브러리를 설치해도 아래와 같은 라이브러리 에러가 발생했을 때 대처방법입니다 』

에러 발생 이미지

 

- 아래는 에러가 발생된 맨처음 상황의 화면입니다.
1. 적외선 리모트 센서를 구동시키기 위한 코드를 컴파일 해보았는데요,
아래와 같은 IRremote.h 센서 에러가 발생하였네요.


 2. 그래서 해당 IRremote.h 헤더파일이 포함된 라이브러리를 찾아 다운받고 다시 실행시켰는데, 아래와 같은 에러가 다시 발생했습니다.  그런데, 이상한 점은 화면 위쪽 아두이노 코드에 보이는 "IRremote.h" 헤더파일을 설치했음에도 프로그램 코드에서 사용되지 않은 헤더파일을 요구하며 에러를 띄우는 모습입니다.

 그 이유는 'IRremote.h"파일(라이브러리)속에 'WProgram.h' 파일을 요구하는 코드가 있기 때문인데요 결론적으로 'WProgram.h'파일이 없기 때문에 에러를 띄우는 것입니다.
'WProgram.h'헤더 파일은 Arduino IDE 툴의 초기버전에서 기본적으로 사용되던 디폴트 파일인데요.
Arduino IDE 버전이 업그레드 되면서 현재는 'WProgram.h' 대신 'Arduino.h'헤더파일을 사용해요.
따라서 그런 오래된 버전에서 제작된 라이브러리의 경우 'WProgram.h'를 사용했기 때문에 , 
지금의 Arduino IDE 버전에서 그런 라이브러리를 사용하게 되면 에러가 뜨게 됩니다.
『 해결방법은 코드에서 사용하려는 라이브러리를('IRremoteInt.h') 열어서 ,
  'WProgram.h'사용 된 코드부분을 찾아 'Arduino.h'로 변경해 주면 해결됩니다. 』 

3. 그럼 직접 해결하는 방법을 보여드릴게요.
먼저, 탐색창을 열고 경로를 참고하여 에러가 난 헤더파일 위치를 찾아가서 헤더파일을 열어보겠습니다.

이미지를 클릭하면 확대 됩니다~!

 

4.  아래처럼 'WProgram.h'헤더파일이 있을 만한 xxxx.h 파일을 모두 열어서 찾아보세요. 

이미지를 클릭하면 확대 됩니다~!


5.  아래 처럼, 'WProgram.h'를 'Arduino.h'로 바꾸어 주고 저장후 창을 닫으면 됩니다.

이미지를 클릭하면 확대 됩니다~!



6. 자 그럼, 에러를 띄웠던 아두이노 코드를 실행시켜 보면, 아래처럼 에러가 해결 되고 코드실행이 잘 되게 됩니다. 

이미지를 클릭하면 확대 됩니다~!



[ 아래 직접 해결하는 영상을 함께 참고해 보세요. ]

에러 해결 영상 : RasIno YouTube 

 

 

 

반응형
반응형

【 아두이노초급#4-2 아두이노 초급 강좌! #05 "아날로그 입출력하기 2편"( Arduino for Absolute beginner! )

아날로그 입출력 2편

 

- 가변저항을 돌리면 LED의 밝기가 조절되는 실습입니다.

- 아두이노에서 가변저항을 통해 아날로그 데이터를 입력받아서,  PWM(Pulse Width Modulation) 제어를 통해 LED로 밝기 조절이 되는 출력(아날로그 형태의 출력)을 해보는 실습입니다. 

- 아두이노는 기본적으로 디지털 장치여서 아날로그 출력이 되지 않습니다.  하지만, PWM 출력을 통해 아날로그와 같은 출력 효과를 낼 수 있습니다.  

- 가변저항의 전압값은 아두이노 Analog port (A0~A5)로 입력 받으면,  아두이노 내부에 10bit ADC (아날로그를 디지털로 변환하는 회로) 컨버터에 의해 즉, 2의 10승 (0~1023) 의 데이터를 입력 받게 됩니다.  그러면, 이 데이터를 가지고 8bit 의 출력을 지원하는 디지털 포트 (D2~D13)에 출력을 내보낼 수 있습니다.  이때, PWM(펄스 폭 변조) 신호 형태의 출력을 행하면 0V~5V 사이의 전압 형태로 출력을 조절 할 수 있어 아날로그식의 출력으로 활용 할 수 있게 됩니다. 
다만,  이런 PWM 출력 기능을 지원하는 디지털핀은 몇 개 정해져 있는데요,  아두이노 디지털포트 숫자 옆에 '~' 물결 무늬가 붙어 있는 단자가 바로 PWM출력 기능을 지원하는 단자입니다.  ( ~3, ~5, ~6, ~9, ~10 , ~11)  

- 이때,  입력값은 10비트인 2의 10승 (0~1023) 값이고, 출력값은 8비트인 2의 8승(0~255) 값이여서,   입력값과 출력값을 매칭시켜 주면 좋은 데요, 이를 지원하는 함수가 바로 매핑함수인 map ( ) 함수 입니다. 

 '값' 영역에는 수시로 변하는 입력 받는 변수를 넣고,   fromLow~fromHigh 는 0~1023 대입,  toLow~toHigh 는 0~255 를 대입하면 됩니다.   즉,  map(Value, 0, 1023, 0, 255);  이런 형태로 함수를 사용하면,  0~1023의 변화 값이 0~255의 변화값으로 대응(매칭이)되어 출력이 됩니다. 


【 이전 영상 보기 

 아두이노쌩초보 영상 #4  ☜ 클릭!
 아두이노쌩초보 영상 #3  ☜ 클릭!

 아두이노쌩초보 영상 #2  ☜ 클릭!
 아두이노쌩초보 영상 #1  ☜ 클릭!

 

【 실습절차 

1.  아래와 같은 회로를 조립하세요 ( 연결도 )

아날로그 입출력 연결도면

 

2. 부품준비
 -  아두이노 (우노)  x 1 개
 - 가변저항 또는 반고정 저항 1 개 (용량은 크게 상관 없음)

 3. 주의 사항
 - 가변저항의 가운데 핀을 반드시 아두이노의 A0 포트에 연결해 주어야 합니다. 

 

【 아두이노 코드 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int VAR = 0
int LED = 11;
int LEDVar = 0;
void setup() {
  Serial.begin(9600); // 시리얼통신 사용선언
  pinMode(LED,OUTPUT);
}
void loop() {  
  VAR = analogRead(A0); 
  LEDVar = map(VAR,0,1023,0,255);
  Serial.println(LEDVar);
  analogWrite(LED, LEDVar);   
  delay(100);
}
 
cs


▶ 코드 다운로드

AnalogInOut_LED.zip
0.00MB


[ PWM 개념도 ]
디지털 보드인 아두이노에서는 아날로그 신호(전압)를 출력할 수 없는데요,
아래와 같이 PWM 방식을 이용하여 아날로그 출력을 보내어 LED 밝기 조절과 같은 할 수 있게 됩니다.

【 동작확인 및 강의 영상 

 아두이노를 처음 접하는 분들을 대상으로 자세하게 설명을 드리는 강의 영상입니다. 

 

 

반응형
반응형

【 아두이노초급#4-1 아두이노 초급 강좌! #04 "아날로그 입출력하기 1편"(Arduino for Absolute beginner!)

아두이노 아날로그 입출력 1편

 

 - 아두이노에서 아날로그 데이터를 입력받는 과정과 처리에 대해 설명합니다. 
 - 아두이노 Analog port (A0~A5)로 가변저항을 이용해서 데이터를 입력 받으면,  아두이노 내부에 10bit ADC (아날로그를 디지털로 변환하는 회로) 컨버터에 의해 즉, 2의 10승 (0~1023) 의 데이터를 입력 받게 됩니다.  
   이를 아두이노 IDE의 시리얼 모니터를 통해 확인할 수 있는 실습입니다.  
  이번 실습은 이어지는 다음 실습과 연결되어 있으니 바로 이어서 실습해 보세요. 
[ 이어지는 다음실습 :  rasino.tistory.com/317
 ] 

【 이전 영상 보기 

 아두이노쌩초보 영상 #3  ☜ 클릭!
 아두이노쌩초보 영상 #2  ☜ 클릭!
 아두이노쌩초보 영상 #1  ☜ 클릭!

 

【 실습절차 

1.  아래와 같은 회로를 조립하세요 ( 연결도 )

2. 부품준비
 -  아두이노 (우노)  x 1 개
 - 가변저항 또는 반고정 저항 1 개 (용량은 크게 상관 없음)

 3. 주의 사항
 - 가변저항의 가운데 핀을 반드시 아두이노의 A0 포트에 연결해 주어야 합니다. 

 

【 아두이노 코드 

int VAR = 0; 
void setup() {
  Serial.begin(9600); // 시리얼통신 사용선언
}
void loop() {  
  VAR = analogRead(A0); 
  Serial.println(VAR);
  delay(100);
}

▶ 코드 다운로드 

AnalogInOut_basic.zip
0.00MB

【 동작확인 및 강의 영상 

 

 

반응형
반응형

【 아두이노Nano#2 NANO 33 IoT 처음 사용 설명서 2편 WiFi 활용하기

 오늘은 지난 시간에 이어 Nano 33 IoT 보드에서 가장 중요한 기능인 WiFi 기능을 이용해 보도록 하겠습니다.

[ 주요 실습 ]   
 1. Nano 33 IoT 보드를 WiFi 공유기에 접속시키고 AP(Access Point)로 작동하도록 한다.
 2. Nano 33 보드에 LED 3개를 연결한다. (점퍼선을 이용하지 않고 굵은 단선을 이용한 방법)
 3. 스마트폰 혹은 스마트패드의 웹 브라우저에서 Nano 33 IoT 보드에 명령어를 보내 LED를 원격으로 제어한다. 
 4. 앱인벤터로 앱을 제작하여 앱으로 시각적으로 편리하게 제어할 수 있다.

NANO33 IoT 보드 뒷면 모습
NANO33 IoT 보드 윗면 모습

 먼저, Nano 제품군의 상세 비교 스펙을 참고해 보세요.
(클릭, 확대해서 보세요~)

- 선수학습 자료 : Nano 33 IoT 보드의 기초 자료를 먼저 참고하세요 

1. 2020/04/14 - [아두이노/5. 아두이노-프렌즈] - 【 아두이노Nano#1】 NANO 33 IoT 처음 사용 설명서

2. 2020/04/14 - [아두이노/5. 아두이노-프렌즈] - 【 아두이노Nano#2】 NANO 33 IoT 처음 사용 설명서 #2 (LSM6DS3 센서 테스트)

3. 2020/04/13 - [아두이노/3. 아두이노 모듈] - 【 아두이노모듈#28】 ESP8266 esp-01 활용하기#4 : 스마트폰으로 LED 컨트롤 하기(with Arduino & cp2102 ) (App Inventer로 앱 만들기 참고)



[ 보드 특징 ]
 아두이노 나노와 사이즈 (18mm X 45 mm)가 같으면서, IoT 및 블루투스, 각종 센서 기능이 강화된 보드입니다.
그동안 나노 보드의 불편했던 USB 커넥터가,  안드로이드 휴대폰과 같은 Micro-5Pin으로 바뀌었네요~ ^^
기존 나노보드 크기에 6축 또는 9축 가속도/자이로 센서가 탑재되었고, Sense 보드는 근접센서, RGB센서, 주변광센서, 제스처 센서가 탑재되어 팔방미인으로 통할 수 있는 보드입니다.   다만, 아직 가격이 상당해서,  가성비는 좀 그렇고 호환 보드가 출시된다면 더없이 좋을 것 같네요. 

 주요 특징으로는 , 기존 NANO 보드와 NANO Every 보드까지는 5V 톨러런트(Tolerant : 회로기판 내의 3.3V 부품도 5V레귤레이터를 통해 내부적으로 문제없이 처리 또는 견딜 수 있는)가 지원되지만,  NANO 33 보드는 이름에서도 알 수 있듯, USB 전원을 제외하고 신호 레벨 전압을 3.3V로 주어야 손상되지 않습니다. 

 NANO 33 보드들은 모두 BLE 기능을 지원하는데요, 일반적으로 블루투스는 동작시 전력 소모가 큰 단점이 있는데, 저전력으로 동작하도록 설계된 블루투스를 BLE라고 합니다.  NANO 33 IoT는 BLE 4.2를 지원하고,  NANO 33 BLE와NANO 33 BLE SENSE는 BLE 5.0을 지원합니다.  NANO 33 IoT의 경우 USB Host를 지원하며, 네오나르도와 같은 HID 장치로 사용이 가능한 것으로 나와 있네요. 

[ 보드 인식과 아두이노 스케치 IDE 사용하기 ]
 먼저 보드를 처음 연결하게 되면, 보드 드라이버가 자동으로 될 수 있지만,  만약 자동으로 설치되지 않을 경우는, PC-Nano33 IoT 보드 간 시리얼 통신에 사용되는 FTDI 칩셋의 드라이버를 설치해 주어야 합니다.  아래는 Nano 보드가 인식이 되고 시리얼 포트까지 할당받아진 상태입니다.

 

- FTDI 드라이버 다운로드 :
아래 홈페이지로 접속하여 운영체제 등 자신의 환경에 맞는 드라이버를 다운로드하으세요
https://www.ftdichip.com/Drivers/VCP.htm

- 다음으로 아두이노 IDE 스케치 툴에 Nano 33 IoT 제품군을 추가해 주어야 합니다.  스케치 IDE에서는 기본적으로 해당 보드가 설치되어 있지 않기 때문에, 메뉴에서,   툴 》  보드 》보드매니저를 열어 NANO 관련 추가 제품군을 등록해 주어야 합니다.   보드 매니저 검색창에서 'nano 33'으로 검색한 다음, 아래 Arduino SAMD Boards(32-bits ARM Cortex-M0+)를 설치해주세요. (설치 과정에 시간이 다소 걸릴 수 있으니, 중간에 창을 닫지 말고 끝까지 기다려 주세요)

- 또는 보드 최초 연결 시 보드 업그레이드 창이 아래처럼 뜨네요.  뜨면서 보드 매니저 창을 바로 띄워주기도 합니다.

- 또한 nano 33 IoT 보드는 wifinina라는 칩셋을 사용하는데요,  이와 관련한 라이브러리를 아두이노 라이브러리 매니저 창에서 설치해주면 됩니다.  ( 툴 》 라이브러리 관리 》 라이브러리 매니저 ,  'wifinina'로 검색)

- 보드 설치가 완료되면, 아래처럼 "Arduino NANO 33 IoT" 보드를 선택하고,  포트에는 "COMxx (Arduino NANO 33 IoT)" 인식된 포트를 선택해 주세요.

 

[ 회로 도면 ]

- 기본적으로 Nano 33 IoT 핀 배열은 기존 Nano 보드와 일치하니 이번 실습에서 사용되는 연결은 일반 나노 보드 핀 맵을 참고 해서 연결해도 무방합니다.

 [ 나노 33 IoT핀맵 ]

Nano 33 IoT PinOut

Nano 33 IoT 보드와  Nano 오리지널의 핀아웃은 똑 같기 때문에 아래 일반 나노의 핀 아웃을 참고하셔도 되요 ^^

아두이노 나노의 PinOut

( 실제 회로 연결 모습 )

- 선 연결 작업 시 아래처럼 점퍼선을 이용하지 않고 굵은 단선을 이용하여 깔끔하게 작업하는 것을 권해드려요.
점퍼선을 이용한 경우, 회로가 조금만 복잡하여도 어디가 어디로 연결된 건지? 만든 사람 본인도 파악하는데 시간이 걸리며, 만약, 잘못 연결된 곳이 있을 경우 찾기가 매우 힘들게 됩니다.   그래서 아래 오른쪽 이미지에서 처럼 필요한 길이만큼만 잘라서 직선적으로 바닥에 붙여 연결하면 회로 파악이 쉽고 연결도 깔끔해져,  납땜 작업 없이도 바로 작품용으로 사용할 수 있는 퀄리티가 나오게 됩니다.  (이때,  부품들도 모두 리드선을 적절하게 잘라서 보드에 바짝 붙여 주세요)

 물론 그냥 점퍼선으로 꽂는 것이 간편하고 시간이 적게 걸리는 점이 있지만,  길이에 맞추어 꽂는 작업이 조금만 익숙해지면 시간 차이는 별로 나지 않으며, 작품을 몇 개만 만들어도 다양한 길이의 완성된 선들이 모이기 때문에 절대 귀찮거나, 힘들지 않습니다.  작업의 만족도 또한 높게 나옵니다.(계속해보면 작업하는 맛?을 느낄 수 있으세요). 


- 이런 작업을 위해서는 아래와 같은,  굵은 단선이 필요하고, 와이어 스트리퍼 공구가 있으면 편리하게 작업이 가능합니다.(니퍼만으로도 작업 가능하지만, 와이어 스트리퍼를 사용하게 되면, 시간이 단축되며, 내부 와이어가 흠집이 나서 부러지는 것을 방지할 수 있습니다)

 

반응형

[ 회로 조립 ]

- Nano 보드와 같은, 핀이 많은 본체를 브레드보드에 직접 꽂을 때는 꽂기가 다소 뻑뻑할 수 있는데요, 좌우를 고르게 눌러가며 다소 힘을 주어 끼워 주세요.
또한, 꽂은 위치를 바꾸기 위해 다시 뽑아야 할 때는 한쪽만을 많이 들어 올릴 경우 핀이 휠 수 있으니 조심해야 합니다. 그래서 일자 드라이버 혹은 핀셋의 뒷부분을 이용해서 나노와 브레드보드 사이에 밀어 넣은 다음 양쪽을 번갈아 조금씩 들어 올려 주면 핀이 휘지 않고 탈거할 수 있습니다.


- LED 테스트와 + - 단자 구분하기
 LED는 +(플러스) 단자와 -(마이너스) 단자의 극성이 존재하는데요,  연결을 반대로 하게 되면 LED에 불이 들어오지 않습니다.  따라서 이 부분을 처음에 확실히 체크해서 연결해주어야,  나중에 동작이 안 될 때 아두이노 코드 쪽을 살펴보느라 시간 낭비되는 것을 방지할 수 있어요.  아두이노 코드 쪽은 문제없었는데 찾다 찾다 결국 LED를 반대 방향으로 꽂은 걸 발견하게 되면 정말 허탈하니까요. ㅎㅎ
 LED와 같은 전자부품들을 체크할 때 멀티 테스터를 사용하면 편리한데요,  LED를 동작시켜 볼 수 있어서 고장 유무 파악과 +선(단자)과 -선(단자)을 쉽게 파악할 수 있습니다.

- 저항 측정 단자로 전류를 흘려 돌아오는 값을 가지고 저항 값을 계산하게 되는데요, 이 전류를 가지고 LED를 켜볼 수 있어요,  테스터의 측정 레인지는 다이오드 혹은 소리 표시가 있는 도통 단자로 놓거나,  저항 측정 단자 중 2KΩ 이하 단자로 놓고 측정해 보세요. 2KΩ 이상에서는 내부 건전지에서 흘러나오는 전류값이 너무 작아서 LED를 켤 수 있는 용량이 되지 않기 때문입니다. 
  그리고
LED가 켜질 때 연결된 선의 색을 가지고  LED의 + , - 리드선 구분을 할 수 있습니다.   만약 LED가 켜질 때 연결한 붉은색 측정 단자의 LED 리드선 쪽이 +선이며,  반대쪽이 LED -리드선이 됩니다. 

 만약, 테스터가 없어도 + , - 구분이 가능한데요,  기본적으로 LED를 제조할 때 +리드선을 -리드선보다 길게 만들고 있습니다.   그리고, 만약, 작업을 위해 선을 수평으로 잘라 버릴 경우에는,  불빛이 나오는 투명한 부분 안쪽을 보면 머리가 작은 쪽이 거의 99% +리드선이라고 여기시면 됩니다.  (하지만 극히, 일부 제조사에서는 반대로 LED를 생산하는 곳이 있습니다)

- LED와 같은 부품들을 보드에 부착할 때는 브레드보드에 깊숙이 삽입될 만큼의 선만 남겨 놓고 잘라서 보드에 밀착시켜 꽂아 주세요. 

 

- 연결할 단선도 직각 형태로 필요한 길이만큼만 정확히 잘라서 선이 위로 올라오거나 모자라지 않도록 깔끔하게 작업해 주는 것이 좋습니다.  이런 형태로, 여러 작품을 작업해 놓으면 다음번 다른 작품의 작업 시 필요한 길이의 선과 부품을 별다른 작업 없이 그대로 사용할 수 있어서 너무 편리합니다.

[ ※ 주의 ]
 nano 33 IoT 보드를 다룰 때는 아래 WiFi 안테나 부분을 주의해서 다루어 주세요. 
무리하게 만지거나 누르면 안테나 부분이 부러 질 수 있고, 글루액 방울 같은 걸로 지지해 놓았으니 떼어내려고 하지 마세요.  비싼 nano 33 IoT 보드가  저렴한 일반 nano 보드로 다운 그레이드 되는 건, 순식간입니다!   ^^;;

 

[ 소스 코드 ]
- 보드가 완성이 되면, 아두이노 보드를 PC에 연결하고 아래의 소스 코드를 전송하세요.

#include <SPI.h> 
#include <WiFiNINA.h> 
int LED1 = 2; 
int LED2 = 3; 
int LED3 = 4; 
const char* ssid = "여기에 WiFi이름을 입력하세요";       // 공백없이 정확히 넣어야 해요.
const char* password = "여기에 WiFi pass워드를입력하세요";   // 공백없이 정확히 넣어야 해요.
int status = WL_IDLE_STATUS; 
WiFiServer server(80); 
void setup() { 
  Serial.begin(9600); 
  delay(10); 
  pinMode(LED1, OUTPUT);   // 출력포트로 설정
  pinMode(LED2, OUTPUT); 
  pinMode(LED3, OUTPUT); 
  digitalWrite(LED1, 0);   // LED Off로 초기화
  digitalWrite(LED2, 0); 
  digitalWrite(LED3, 0); 
  // WiFi 네트웍에 접속 
  while (status != WL_CONNECTED) { 
    Serial.print("Attempting to connect to SSID: "); 
    Serial.println(ssid); 
    status = WiFi.begin(ssid, password); 
    // WiFi에 접속할 때까지 10초간 대기
    delay(10000); 
    } 
    Serial.println(""); 
    Serial.println("WiFi connected"); 
    // 서버 시작
    server.begin(); 
    Serial.println("Server started"); 
    // 할당받은 IP 주소를 시리얼 모니터로 출력
    char ips[24]; 
    IPAddress ip = WiFi.localIP(); 
    sprintf(ips, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);  // IP형식으로 출력
    Serial.println(ips); 
    } 
void loop() { 
  // 클라이언트(폰, 패드등 동일 WiFi로 접속하는 기기)가 접속하였는지 체크
  WiFiClient client = server.available(); 
  if (!client) { 
    return; 
  } 
  // 클라이언트로부터 데이터 수신을 기다림
  Serial.println("new client"); 
  while(!client.available()){ 
    delay(1); 
  } 
  // 요청(데이터)의 첫 줄을 읽어 req에 저장
  String req = client.readStringUntil('\r'); 
  Serial.println(req); 
  client.flush(); 
  int val1 = 0; 
  int val2 = 0; 
  int val3 = 0; 
  int Ledreq = 0; 
  // 비교문으로 요청 들어온 값과 일치하는 부분이 있을 경우 {  } 안의 내용을 실행.
  // req.indexof("문자열")은, req에 있는 데이터에서 "문자열"이 일치하는 문자가 없을 경우는 '-1'을 반환.
  // 그외 일치하면 해당 문자열의 인덱스 시작위치(숫자)를 반환.   
  if (req.indexOf("/gpio1/0") != -1) { 
    val1 = 0;  Ledreq = 1; 
  } else if (req.indexOf("/gpio1/1") != -1) { 
    val1 = 1; 
    Ledreq = 1; 
  } else if (req.indexOf("/gpio2/0") != -1) { 
    val2 = 0; 
    Ledreq = 2; 
  } else if (req.indexOf("/gpio2/1") != -1) { 
    val2 = 1; 
    Ledreq = 2; 
  } else if (req.indexOf("/gpio3/0") != -1) { 
    val3 = 0; 
    Ledreq = 3; 
  } else if (req.indexOf("/gpio3/1") != -1) { 
    val3 = 1; 
    Ledreq = 3; 
  } else { 
    Serial.println(" ... "); 
    client.stop(); 
    return; 
  } 
  // if문에 의해 설정된 값을 출력(LED On/Off)
  digitalWrite(LED1, val1); 
  digitalWrite(LED2, val2); 
  digitalWrite(LED3, val3); 
  client.flush(); 
  // 요청에 대해 응답하기. 
  String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\n"; 
  if(Ledreq==1) { 
    s += "LED1 is "; 
    s += (val1)? "ON": "OFF"; // vall의 값이 참이면('0'아닌 값은 모두 참) 'ON'저장, 거짓이면'OFF'저장
  } else if(Ledreq==2) { 
    s += "LED2 is "; 
    s += (val2)? "ON": "OFF"; 
  } else if(Ledreq==3) { 
    s += "LED3 is "; 
    s += (val3)? "ON": "OFF"; 
    s += " , Welcome to RasINO IoT YouTube ^^";
  } 
  s += "</html>\n"; 
  // 응답할 내용을 클라이언트(폰, 패드 등 WiFi로 접속하는 기기)로 전송
  client.print(s);   //  예시 "LED1 is ON"  
  delay(2); 
  client.stop(); 
  Serial.println("Client disonnected");     
}

 (아두이노 코드 링크)

LED_WebControl.zip
0.00MB


[ 동작 확인 ]
 
- 우선 시리얼 모니터를 열고 10~20여 초를 기다리면, nano 33 IoT가 WiFi공유기로부터 IP를 할당받는 데요, 시리얼 모니터 창에 나타나도록 되어 있으니 참고하세요.  (할당받는 주소는 사람마다 다를 수 있습니다)
- 할당받은 주소를 스마트폰이나 패드에서 웹브라우저를 띄운 다음 주소표시줄에 아래와 같은 형식으로 입력해주세요.

' http://192.168.11.6/gpio1/1 '   → 1번 Red LED 켜기 
' http://192.168.11.6/gpio1/0 '   → 1번 Red LED 끄기 
' http://192.168.11.6/gpio2/1 '   → 2번 Blue LED 켜기 
' http://192.168.11.6/gpio2/0 '   → 2번 Blue LED 끄기 
' http://192.168.11.6/gpio3/1 '   → 3번 Green LED 켜기 
' http://192.168.11.6/gpio3/0 '   → 3번 Green LED 끄기 


- 현재 nano 33 iot 보드와 스마트기기는 동일한 WiFi 공유기로 접속되어 있어야 제어가 가능합니다. 
 Nano 33 iot 보드가 공유기로부터 할당받은 주소는 사설 IP이기 때문에 외부망에서는 보이지 않습니다.  따라서 외부에서 nano 33 iot 보드를 제어하고 싶다면,  공유기 설정으로 들어가서 nano 33 iot 보드가 할당받은 주소를 포트 포워딩이나 DMZ 설정 등과 같은 조치를 해주면 가능할 수 있습니다.  
- 또한 요즘 한창 유행하고 있는 Bylink(블링크) , MQTT와 같은 클라우드 서비스를 연동해서 하면 가능할 수 있으니,  필요하다면, 관련 부분은 검색해 보세요.


- 그럼, 마지막으로 웹 주소창의 입력으로는 조금 불편한데요,  이를 앱인벤터를 이용해서 앱을 만들어 제어해보면 편할 것 같네요. 
 - 순수하게 앱인벤터 사용법은 라즈이노 IoT의 앱인벤터 학습 카테고리와, 지난 esp8266-01 LED Web Control 영상을 먼저 참고하면 쉽게 하실 수 있습니다.  

[ 앱화면 구성  - UI 부분]


[ 앱화면 구성  - 코딩 블럭 부분]  (이미지를 클릭하면 확대 됩니다)


 [ 최종 완성된 앱 파일 다운 받기 - download apk file ]

Nano33IoT_LED.apk
3.53MB


 최종적으로 만든 앱을 설치해서 아래처럼 동작이 되는지 확인해보세요~  ^^

 

  끝으로 이 모든 과정을 따라 하기 쉽도록 영상으로 제작했으니,  영상도 함께 참고해 보세요.

 

반응형