ST 퀘스트 이벤트
Quest 7
퀘스트7/7 & Epilogue - 실내외 공기질 정보 제공 작성자 : 자작공작소

주제 : 실내외 공기질 정보 제공

 

 STM32MP1의 뛰어난 HW 성능을 발휘하면서 실생활에 활용 가능한 주제를 고민하던 중 공기질 제공 시스템을 만들기로 결정합니다. 그동안 배운것을 활용하면서 새로운 부분을 추가로 알아가며 프로젝트를 진행 하였습니다.

 

구성 소개

 M4에서 센서로 부터 읽어들인 공기질 정보를 IPCC(Inter-processor communication controller)를 통해서 A7으로 전달하여 실내 공기질 화면에 표시합니다. OpenAPI를 사용해 한국환경공단에서 얻은 동네 대기환경 데이터를 실외 공기질 화면에 표시합니다.

 

그림1. 전체 구성 화면

 

STM32MP157C-DK2 보드와  센서를 연결한 화면입니다.

 

 3가지 외부 센서에서 각기 다른 인테페이스로 실내 공기질 데이터를 받고 있습니다. BOSCH BME680은  I2C를 사용하여 온도, 습도, 기압, 가스 정보를 얻고 SHARP GP2Y10 Dust센서로는 아날로그 출력(ADC)으로 미세먼지 농도 데이터를 받으며 PIR 근접센서는 Digital Input으로 사람의 접근을 확인 합니다. (화면 보호기 용도)

 

(a) BME680 온도, 습도, 기압, 가스 센서 모듈

 

(b) GP2Y10 Dust 센서 모듈

 

(c) Mini PIR 근접(모션) 센서 모듈

그림 2. 과제에 사용한 센서 모듈 소개

 

 한국환경공단에서 제공하는 실외(동네) 공기질 정보는 그동안 잘 사용했던 WiFi 이더넷과 OpenAPI를 이용해 얻어옵니다. 이를 위해 공공데이터 포털에 가입하고 데이터 활용 신청을 하였습니다. 당초 계획은 기상청에서 제공하는 온도, 습도 기상정보와 한국 환경공단에서 제공하는 대기질 정보를 얻어 오는 것이였는데 온, 습도 정보의 경우 서버 연결이 되지 않아(프로토콜 오류) 최종적으로 사용하진 못하고 한국 환경공단에서 제공하는 대기질 정보만 사용하였습니다.

 

그림 3. 실내 공기질 표시 (센서로 수집)

 

 각종 센서를 구매하고 지원하는 인터페이스에 따라 하나하나 연결을 시도합니다. 먼저 BME680 센서의 경우 I2C를 사용합니다. 이 센서는 다행히 홈페이지에서 디바이스 드라이버를 제공하고 있습니다. 디바이스 드라이버를 사용하는 방법은 두 가지 있는데 하나는 A7용 커널에 추가하여 빌드 후 사용하는 방법이고 다른 하나는 CubeIDE에 추가하여 M4로 값을 읽을때 사용하는 것입니다.

 

 Quest 의도에 따라 CubeIDE에 추가하여 사용하기로 합니다. 우선 연결할 포트를 선택하는데 hi2c5를 사용합니다. 다른 채널들은 이미 보드에서 다른 용도로 사용되고 있어서 신규 채널을 선택하였습니다. CubeMX를 사용하여 I2C5를 설정하고 센서에 결선하고 테스트를 진행해 봅니다. BME680 센서 드라이버를 설치하고 I2C Read/Write, Delay_ms를 M4에 맞게 설정하면 됩니다. Data sheet를 보고 필요하면 일부 I2C 설정을 변경하면 됩니다.

 

스코프 없이 CubeIDE로 디버깅을 하려니 너무 느려서 디버깅이 쉽지 않습니다. 그래서 익숙한 printf로 센서에서 읽은 값을 터미널에서 확인 하기 위해서 huart3를 stdout(표준 스트림)포트 설정합니다. 이 후 USB to RS232 시리얼 컨버터에 연결하여 Host PC의 minicom으로  센싱 값을 쉽게 확인할 수 있었습니다. 나중에 Qt에서 IPCC 로  데이터를 받은 후에 보낸값이 잘 들어왔는지 확인 할때도 요긴하게 잘 사용했습니다.

 

 BME680의 경우 온/습도와 기압, 가스 저항값이 나옵니다. 가스 저항값은 IAQ(Indoor air quality, 실내 공기질) index값으로 변환해야 의미가 있습니다. 아래는 Index 값에 따른 공기질의 평가 테이블 입니다.

 

그림 4.  IAQ Index 값에 대한  Grade 테이블

 

다행히 집안의 IAQ Index값이 14~15로 좋은 편입니다.

 

 다음은 미세먼제 센서인 GP2Y10을 연결합니다. 원리는 내부에 LED를 순간적으로 발광 시킨 후 특정 시간 후에 파티클수에 비례하는 아날로그 출력값을 내보내는 것으로 이 값을 ADC해야 합니다. 그래서 LED드라이브 포트와 ADC포트가 필요합니다.

 

그림 5. GP2Y10 ADC 조건

 

 us(microsecond) 단위로 펄스를 컨트롤 하기 위해서는 us Delay함수가 필요합니다. CubeIDE는 기본적으로  지원하는 HAL_Delay()는 ms(millisecond) delay이여서 us delay를 만들기 위해 M4 내부 Timer중 htim2를 사용했으며 us delay를 구현하고 시간 검증을 위해 스코프가 없는 관계로 10초 정도 긴 시간 딜레이를 만들어 잘 동작 하는지 확인 하였습니다. us delay를 구현하고 ADC 하기 위해 hadc2를 입력 채널로 설정하고 PE1 포트(디지털 출력)를 LED Drive 포트로 사용합니다.

 

 테스트시 Vref를 연결하지 않았더니 출력값이 이상했습니다. 센서를 달기전에 10k옴의 가변저항을 입력 소스로 사용했는데 전혀 변화가 없었습니다. 이 후 한참 고생 후 하필 5V를 기준 전압 Vref로 사용하였더니 역시나 의도하지 않은 값이 나왔습니다. 알고 보니 Vref와 VDD가 연관이 있었습니다.  이 부분에서 많은 시간을 허비하였습니다. (Data Sheet에서 확인, 난관) 다시 Vref로 3.3V 연결하고 가변 저항으로 입력을 확인하니 설정한 분해능에 따라 입력 전압 변화를 확인 할 수 있었습니다. 이후에 미세먼지 센서를 연결하고 LED드라이브를 위 그림처럼 설정하였더니 센서값을 읽을 수 있었습니다. ADC 방식은 폴링과 DMA가 잘 동작하며 최종적으로 폴링방식을 사용하였습니다.

 

 센서부 전원을 공통으로 사용하니 기준전압도 리플이 있고 해서 아주 안정적인 ADC 출력값이 나오지 않았습니다. 그래서 센서값에 필터링을 가해서 안정적인 값을 얻을 수 있었습니다. ADC로 얻은 센서 출력 전압을 미세먼지량으로 변한해야 하는데  Data Sheet에 있는 수식과 실험값에 의해서 결정하였습니다. 

 

 PIR 근접 센서는 적외선을 이용하여 사물 감지 후 디지털 출력을 내보냅니다. PE10포트를 디지털 입력으로 설정하여 센서값을 읽습니다. 반응속도는 약 1~2초 정도 Delay가 있으나 감지는 잘 하는 편입니다.

 

 아래는 이번 도전에 사용한 CubeIDE의 입출력 변수들 입니다.

/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc2;

I2C_HandleTypeDef hi2c5;

IPCC_HandleTypeDef hipcc;

TIM_HandleTypeDef htim2;

UART_HandleTypeDef huart3;

/* USER CODE BEGIN PV */
VIRT_UART_HandleTypeDef huart0;
VIRT_UART_HandleTypeDef huart1;

CubeMX는 아직도 어렵네요.

 

 최종적으로 M4에서는 아래와 같이 출력합니다. T는 온도, H는 습도, P는 기압, IAQ는 가스 저항값을 공기질 인덱스로  변환한 값, PIR은 인체감지 정보를 표시합니다.

T: 30.29 degC, H: 44.87 %rH, P: 991.41 hPa, IAQ: 14, D: 41 ug/m3, PIR: 1        
T: 30.29 degC, H: 44.87 %rH, P: 991.41 hPa, IAQ: 14, D: 42 ug/m3, PIR: 1        
T: 30.29 degC, H: 44.83 %rH, P: 991.41 hPa, IAQ: 14, D: 41 ug/m3, PIR: 1        
T: 30.29 degC, H: 44.85 %rH, P: 991.41 hPa, IAQ: 14, D: 39 ug/m3, PIR: 1        
T: 30.29 degC, H: 44.85 %rH, P: 991.41 hPa, IAQ: 14, D: 39 ug/m3, PIR: 0        
T: 30.29 degC, H: 44.85 %rH, P: 991.41 hPa, IAQ: 14, D: 39 ug/m3, PIR: 0        
T: 30.29 degC, H: 44.88 %rH, P: 991.41 hPa, IAQ: 14, D: 39 ug/m3, PIR: 0        
T: 30.29 degC, H: 44.95 %rH, P: 991.41 hPa, IAQ: 14, D: 40 ug/m3, PIR: 0        
T: 30.29 degC, H: 45.01 %rH, P: 991.43 hPa, IAQ: 14, D: 39 ug/m3, PIR: 0 

 

센서에서 읽어들인 값을 위와 같이 Serial 포트로 출력하여 확인(호스트 PC, Ubuntu)하고 다음으로 A7으로 보낼 방법을  Survey합니다.

 

 처음에는 IPCC를 이용해야 한다고 들었는데 조금 막막했습니다. 그러다 remote processor messaging (rpmsg) framework를 알게 되고 ttyRPMSG를 알게 되었습니다. 그래서 테스트 프로그램을 만들면서 드디어 Qt Creator를 사용하게 됩니다. Qt에는 QtSerialPort라는 Serial통신용 라이버리가 있습니다. QtSerialPort를 이용하여 M4와 A7간의 약속된 Packet Format을 만들고 데이터를 보냈더니 Qt App에서 데이터를 받지 못합니다. (난관) 이건 지금도 원인은 모르겠으나 Qt App에서 데이터를 보내 줘야 이 후 부터 정상적인 수신이 가능했습니다.  Data Packet은 문자열로 만들어 보내고 Qt App에서는 각 항목별로 파싱하여 사용합니다. 외부 환경데이터는 XML로 수신한 데이터를 파싱하여 사용했습니다.

 

그림 6. Qt Creator에서 STM32MP157C-DK2 Kit사용 화면 (meta-toolchain-qt5 설치)

 

 마지막 쿼스트를 무사히 끝마칠 수 있었던 것은 Qt5 Toochain을 미리 설치해 놓아서 가능했다고 생각됩니다. 디버깅할때 너무 편리하게 잘 사용하였습니다. 

 

 데이터 수신이 잘 되면서 UI도 구상합니다. 여유가 있으면 더 화려하게 구성할 예정이었으나 그동안 난관이 많아서 시간이 없습니다. 2주는 너무 짧다고 생각이됩니다.

 

 

그림 7. 실외 공기질 표시 (한국환경공단 제공 OpenAPI 사용)

 

 실외 공기질 데이터는 OpenAPI를 이용해 얻어옵니다. 미리 신청하여 받은 공공 데이터 이용 개인 KEY를 사용합니다. 사용한 공공 데이터는 한국 환경 공단에서 제공하는 측정소의 대기오염 정보입니다. 처음으로 기상청 데이터를 사용하려고 시도 하였으나 서버 접속시 아래와 같은 에러 메세지로  정상적으로 되지 않아 이를 확인하면서 많은 시간을 허비합니다. (난관)

const QString ServiceURL = "http://apis.data.go.kr/1360000/VilageFcstInfoService/"; // Error: "Protocol \"\" is unknown"

※ 이렇게 작성하고 보니 맨뒤에 '/' 때문인것 같습니다.

 

 처음에는 서버 접속 코드에 문제가 있는지 알았는데 아래처럼 환경공단 서버 접속은 같은 코드로 잘 되었습니다.

const QString ServiceURL = "http://openapi.airkorea.or.kr/openapi/services/rest/ArpltnInforInqireSvc/getMsrstnAcctoRltmMesureDnsty";

 

 OpenAPI를 통해 Request 메세지를 만들어 보내면 대기질 데이터를 XML로 보내줍니다. 측정소는 거주지역에서 가까운 "기흥"으로 합니다. XML수신 후 원하는 값을 파싱해서 UI에 표시합니다. 실내 공기질 표시용으로 만든 UI를 사용합니다.

 

 표시하는 환경값은 아황산가스 농도, 일산화탄소 농도, 오존 농도, 이산화질소 농도, 미세먼지(PM10)농도, 미세먼지(PM2.5)농도 등 6가지 입니다. 미세미세 앱과 농도값을 비교하니 같은 서버 데이터를 이용하기에 동일한 값을 표시합니다. 시간이 허락하면 농도에 따라 색을 달리 하려고 WHO 기준으로 인터페이스는 만들었으나 Style적용시 모듈이 없다는 오류로 적용하지 못합니다.(난관)

 

최종 UI는 QML로 Swipe와 ColumnLayout을 이용하여 만들었습니다.  각 실내외 공기질 데이터는 시그널을 이용하여 값의 변화가 생기면 업데이트됩니다.

  실내 공기질 데이터는 1초 주기로 M4에서 보내 주면 Qt에서 수신이벤트가 발생하고 값을 파싱 후 시그널을 발생시킵니다.  QML에서는 각 항목이 프로퍼티로 연결되어 있어 자동으로 Update됩니다. 실외 공기질 데이터는 10분 주기(하루 144회) 타이머를 이용하여 서버에 접속하여 데이터를 받아오고 실내 공기질 데이터와 같은 방식으로 화면에 업데이트합니다. 서버 접속의 경우 1일 최대 접속가능 횟수와 업데이트 주기를 고려하여 선정하였습니다.

 

꿈은 창대하였으나 기본 기능 구현에 상당한 시간을 소비하여 UI에 투자할 시간이 절대적으로 부족했습니다.

 

동영상 1. 시연 영상

 

※ 실행 프로그램은 첨부된 압축파일 내에  M4, A7용으로 각각 압축되어 있습니다.

 

Epilogue

 

1. 주제 구상은 언제나 즐겁습니다.

2. 주제를 정하고 측정할 아이템을 선정하고 센서류를 구매합니다.

3. 오실로 스코프 부재로 미니 테스터기로 어렵게 디버깅합니다.

4.  화려한 UI를 꿈꿨으나 온갖 허들, 난관으로 인해 많은 시간을 허비합니다.

5. 인체감지 센서는 사용자 접근시에만 화면을 켜는 용도로 구상하였으나 백라이트 컨트롤 솔루션을 해결하지 못해 적용하지 못했습니다.

 - shell에서 command로 brightness를 조절할 수 있습니다. (0이면 커지고, 기본값은 240입니다.)

 - command를 게시판에 적이니 입력 오류가 발생합니다.

 - Qt에서 shell command를 실행하려면 QProcess를 사용하면 되는데 이녀석이 큰 따옴표를 무력화해서 결국 이 방법은 포기합니다.

6. Qt Style을 적용하려고 하였으나 모듈이 없다는 에러로 인해 무산됩니다. (뭐가 문제인지 모르겠네요.)

7. Qt Backend (Model, Control)은 UI에 비해 수월합니다. XML도 익숙하구요.

8. 기상청 데이터용 서버 접속이 되지 않아 디버하며 시간을 소비합니다.

9. 그동안 함께 배우고 정보 공유해 주신 도전자 분들께 감사 드립니다.

10. STM32MP1의 많은 것을 배울 수 있도록 기회를 주신 ST마이크로일렉트로닉스와 E4DS 관계자 분들께 깊은 감사를 드립니다.

11. 오랜만에 새로운 도전으로 며칠밤도 새워봅니다.

12. 끝으로 생일임에도 불구하고 신랑의 도전을 위해서 묵묵히 지켜봐준 아내와 아이에게 큰 감사함을 전합니다.