아두이노2016. 6. 23. 17:55

독일 보쉬(Bosch)사의 BMP180 센서는 기압 및 온도를 측정 하는 기능을 가집니다. 고도에 따라 기압은 달라지므로 기압을 바탕으로 고도를 측정할 수 있기도 합니다. 고도가 높아지면 기압이 낮아지고 고도가 낮아지면 기압이 높아지는 원리를 이용하는 것입니다. 이를 기압고도(Pressure Altitude)라고 합니다. 일반적으로 표준 대기압 기준으로 해발 1500m 의 기압은 850hPa, 3000m는 700hPa 그리고 5400m는 500hPa 정도 된다고 합니다. 이를 계산식을 만들어 기압을 대입하면 고도값을 얻을 수 있는 것입니다. 이야기가 잠깐 샜는데 BMP180 센서는 BMP085 센서를 대체하는 보다 정밀한 기압센서 입니다. 이를 아두이노와 연결하면 배터리로 작동하는 기압계, 온도계, 고도계를 만들 수 있습니다. 아니면 개인 기상장치 같은 것도 만들 수 있겠네요.


BMP180 기압센서를 이용한 센서 보드 입니다. 풀업 저항, 레귤레이터, 콘덴서 등이 모두 붙어 있어서 바로 아두이노에 연결해서 사용하면 됩니다. 확대를 하니 굉장히 커 보이지만 사실은 매우 작은 보드 입니다. 센서 자체도 쌀알 정도의 크기이고 모듈전체는 새끼 손가락의 손톱만 합니다.


백원짜리랑 비교해 보았습니다. 훨씬 작은 크기죠. 제가 구한 센서는 저렇게 핀을 따로 납땜해서 연결해 주어야 합니다. 물론 자신만의 조그만 기압계를 만들고 싶은 분들은 소형화를 위해 핀 대신에 바로 전선을 납땜하는게 좋겠죠?


뒷면 입니다. VIN, GND, SCL, SDA 단자가 있습니다. 센서의 스펙은 아래와 같습니다.


■ BMP180 Digital Barometric Pressure Sensor Specification


- 데이터시트 :

BMP180.pdf

데이터시트에서 발췌한 스펙 입니다. 측정 가능한 기압의 범위는 300 ~ 1100hPa 즉, 해발기준 9000m ~ -500m 에 해당되는 고도의 기압까지 측정이 가능 합니다. 에베레스트 산이 8848m 이니 그 이상은 올라갈 일이 없겠죠? 물론 비행기가 있지만 비행기 내부는 승객들을 위해 내압을 조절하니 비행기 안에서의 측정은 의미가 없을 것 입니다. 작동 전압은 1.8V ~ 3.6V 이니 아두이노와 연결 시 3.3V에 연결해야 합니다.



테스트를 위해서 핀을 납땜을 해 줍니다. 센서가 매우 작으므로 쇼트되지 않도록 신경써서 작업해야 합니다.


■ 연결

전원은 3.3V 에 연결해야 하며 SCL, SDA 핀을 각각 Analog In 단자인 A5, A4 에 연결해 주었습니다.


 BMP180

 Arduino Uno

 VIN

 3.3V

 GND

 GND

 SCL

 A5

 SDA

 A4



실제 연결 모습 입니다.


 

■ 소스

먼저 Adafruit 의 라이브러리를 가져 옵니다. Adafruit 의 Copy 버전의 모듈이기 때문에 라이브러리도 서로 호환이 됩니다. 라이브러리는 Adafruit 센서 라이브러리와 BMP180 & BMP085 겸용 라이브러리를 다운로드 받아서 압축을 풀어서 아두이노 IDE 설치폴더의 Libraries 폴더에 복사해서 설치하면 됩니다.


- Adafruit Sensor Library : https://github.com/adafruit/Adafruit_Sensor

Adafruit_Sensor-master.zip


- Adafruit BMP085 & BMP180 : https://github.com/adafruit/Adafruit_BMP085_Unified

Adafruit_BMP085_Unified-master.zip


라이브러리 설치 후 예제를 실행해 봅니다. 예제 -> Adafruit BMP085 Unified -> sensorapi 를 열어 봅니다. BMP085 지만 같은 라이브러리를 사용해서 실행이 됩니다. 그런데 이 상태로 컴파일을 하게되면 경고가 발생합니다. 설치한 라이브러리 폴더로 다시 들어가서 '.github' 라는 폴더를 삭제해 버리면 됩니다. 뭐... 그런데 삭제하지 않더라도 컴파일되고 업로드 까지 되긴 됩니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP085_U.h>
 
/* This driver uses the Adafruit unified sensor library (Adafruit_Sensor),
   which provides a common 'type' for sensor data and some helper functions.
   
   To use this driver you will also need to download the Adafruit_Sensor
   library and include it in your libraries folder.
   You should also assign a unique ID to this sensor for use with
   the Adafruit Sensor API so that you can identify this particular
   sensor in any data logs, etc.  To assign a unique ID, simply
   provide an appropriate value in the constructor below (12345
   is used by default in this example).
   
   Connections
   ===========
   Connect SCL to analog 5
   Connect SDA to analog 4
   Connect VDD to 3.3V DC
   Connect GROUND to common ground
    
   History
   =======
   2013/JUN/17  - Updated altitude calculations (KTOWN)
   2013/FEB/13  - First version (KTOWN)
*/
   
Adafruit_BMP085_Unified bmp = Adafruit_BMP085_Unified(10085);
 
/**************************************************************************/
/*
    Displays some basic information on this sensor from the unified
    sensor API sensor_t type (see Adafruit_Sensor for more information)
*/
/**************************************************************************/
void displaySensorDetails(void)
{
  sensor_t sensor;
  bmp.getSensor(&sensor);
  Serial.println("------------------------------------");
  Serial.print  ("Sensor:       "); Serial.println(sensor.name);
  Serial.print  ("Driver Ver:   "); Serial.println(sensor.version);
  Serial.print  ("Unique ID:    "); Serial.println(sensor.sensor_id);
  Serial.print  ("Max Value:    "); Serial.print(sensor.max_value); Serial.println(" hPa");
  Serial.print  ("Min Value:    "); Serial.print(sensor.min_value); Serial.println(" hPa");
  Serial.print  ("Resolution:   "); Serial.print(sensor.resolution); Serial.println(" hPa");  
  Serial.println("------------------------------------");
  Serial.println("");
  delay(500);
}
 
/**************************************************************************/
/*
    Arduino setup function (automatically called at startup)
*/
/**************************************************************************/
void setup(void
{
  Serial.begin(9600);
  Serial.println("Pressure Sensor Test"); Serial.println("");
  
  /* Initialise the sensor */
  if(!bmp.begin())
  {
    /* There was a problem detecting the BMP085 ... check your connections */
    Serial.print("Ooops, no BMP085 detected ... Check your wiring or I2C ADDR!");
    while(1);
  }
  
  /* Display some basic information on this sensor */
  displaySensorDetails();
}
 
/**************************************************************************/
/*
    Arduino loop function, called once 'setup' is complete (your own code
    should go here)
*/
/**************************************************************************/
void loop(void
{
  /* Get a new sensor event */ 
  sensors_event_t event;
  bmp.getEvent(&event);
 
  /* Display the results (barometric pressure is measure in hPa) */
  if (event.pressure)
  {
    /* Display atmospheric pressue in hPa */
    Serial.print("Pressure:    ");
    Serial.print(event.pressure);
    Serial.println(" hPa");
    
    /* Calculating altitude with reasonable accuracy requires pressure    *
     * sea level pressure for your position at the moment the data is     *
     * converted, as well as the ambient temperature in degress           *
     * celcius.  If you don't have these values, a 'generic' value of     *
     * 1013.25 hPa can be used (defined as SENSORS_PRESSURE_SEALEVELHPA   *
     * in sensors.h), but this isn't ideal and will give variable         *
     * results from one day to the next.                                  *
     *                                                                    *
     * You can usually find the current SLP value by looking at weather   *
     * websites or from environmental information centers near any major  *
     * airport.                                                           *
     *                                                                    *
     * For example, for Paris, France you can check the current mean      *
     * pressure and sea level at: http://bit.ly/16Au8ol                   */
     
    /* First we get the current temperature from the BMP085 */
    float temperature;
    bmp.getTemperature(&temperature);
    Serial.print("Temperature: ");
    Serial.print(temperature);
    Serial.println(" C");
 
    /* Then convert the atmospheric pressure, and SLP to altitude         */
    /* Update this next line with the current SLP for better results      */
    float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA;
    Serial.print("Altitude:    "); 
    Serial.print(bmp.pressureToAltitude(seaLevelPressure,
                                        event.pressure)); 
    Serial.println(" m");
    Serial.println("");
  }
  else
  {
    Serial.println("Sensor error");
  }
  delay(1000);
}
cs


예제 소스 입니다. 업로드 해서 실행해 봅니다.


현 위치의 기압, 온도 그리고 기압을 바탕으로 계산한 고도값이 나옵니다. 대략 114m 정도가 나옵니다. 신빙성이 있는지 구글 API 에서 현재 위치의 고도가 어떻게 되는지 찾아 보았습니다.


구글 API 에서는 현재 위치의 고도가 56m 정도로 표시가 됩니다. 대략 2배가 넘는 오차가 발생 합니다. 왜 그럴까요? 오늘 날씨가 흐려서 오차를 감안하더라도 너무 높게 나온 고도 같습니다.


※ 위도와 경도로 고도값 알아내기 (구글 API 이용, 응답값 Json Type)

http://maps.googleapis.com/maps/api/elevation/json?locations=[위도],[경도]&sensor=false


소스를 다시 들여다 봅니다. 소스에 쓰여 있기를 더욱 정확한 고도값을 얻기 위해서는 현재 지역의 Sea Level Pressure 즉, 해면기압을 알아내서 소스에 적용하면 더욱 정확한 고도측정이 가능한 것 입니다. 입력하지 않을 경우 라이브러리에 입력된 변수값(평균값)을 적용하게 되는데 그 값이 1013.25hPa 입니다.


그럼 현 위치의 해면기압을 알아내야 합니다. 해면기압은 기상청 사이트에 들어가면 알 수 있습니다. 


http://www.kma.go.kr/weather/observation/currentweather.jsp


위의 사이트에 들어가면 현재 위치의 해면기압을 알 수 있습니다. 현재 위치에서 가장 가까운 수원의 해면기압을 소스에 적용해 보았습니다.


소스의 float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA; 부분이 해면기압을 변수에 넣어주는 부분 입니다. SENSORS_PRESSURE_SEALEVELHPA (<- 이 값은 1013.25 겠죠?) 대신 위의 기상청 표에 나온 수원의 현재 해면기압 값인 1004.8 을 넣어 주었습니다. float seaLevelPressure = 1004.8;



100m도 넘던 고도 값이 확 줄었습니다. 여전히 56m 와는 약간의 오차가 있지만 GPS 고도 측정값도 어느정도 오차가 있을 것이므로 대체로 만족스러운 값 같습니다.



이상으로 BMP180 기압측정 센서모듈을 아두이노에 붙여서 기압, 온도 그리고 고도를 측정해 보았습니다. 다른 센서들 보다 뭔가 공부할 거리도 많은 것 같고 재미있는 것 같습니다.

반응형
Posted by 대네브 (deneb)

댓글을 달아 주세요

  1. 저기 VENT HOLE 을 막으면 안되는거죠? 제품에 적용하여 주위를 몰딩을 할건데 저 VENT HOLE은 필히 노출시켜야 되는거죠?

    2019.05.14 17:03 [ ADDR : EDIT/ DEL : REPLY ]
    • 아마도 그렇지 않을까요? 괜히 구멍이 있지는 않겠죠? 자세한 사항은 센서의 데이터시트를 참고하세요.

      2019.05.14 17:08 신고 [ ADDR : EDIT/ DEL ]
  2. 장재환

    여기에서 if(event.pressure)부분이 이해가 가질 않습니다 정확히 무슨뜻이며 어떻게 이런 형태의 코딩이 나왔나요?

    2020.03.13 18:23 [ ADDR : EDIT/ DEL : REPLY ]
    • 에이다프룻 라이브러리에서 제공하는거에요. c언어 아시면 라이브러리 소스 보면 알 수 있어요

      2020.03.14 15:09 신고 [ ADDR : EDIT/ DEL ]
  3. 이진우

    혹시 이 센서로 사람의 체온을 측정할 수 있나요???

    2020.05.24 13:17 [ ADDR : EDIT/ DEL : REPLY ]