레이블이 ardpy인 게시물을 표시합니다. 모든 게시물 표시
레이블이 ardpy인 게시물을 표시합니다. 모든 게시물 표시

2017년 1월 21일 토요일

python3-smbus 와 아두이노간 통신 동작

 i2c에서 통신은 프로토콜 특성상 항상 마스터에서 먼저 슬레이브로 데이터를 보낸다. 마스터에서 데이터를 전송할 때도 그렇고 슬레이브에서 읽어올 때도 마스터에서 먼저 요구하면 슬레이브에서 그 요구를 받아서 데이터를 전송한다.

 아두이노의 Wire라이브러리를 이용하면 Wire.onReceive() 함수와 Wire.onRequest() 함수를 이용하여 핸들러 함수를 등록해야 한다.

Wire.onReceive( _onReceive ); #데이터를 받는다.
Wire.onRequest( _onRequest ); #데이터를 보낸다.

smbus의 관련함수들은 다음과 같다.

read_i2c_block_data(addr, cmd [, length] )
write_i2c_block_data(addr, cmd, lst)

smbus의 write_2ic_block_data() 함수는 다음과 같이 데이터를 전송하기 위해서 _onReceive()함수를 호출하게 된다. 전송되는 데이터의 첫 바이트가 cmd라는 것을 유의해야 한다. _onReceive( len)함수의 인수도 cmd까지 고려한 길이가 인수로 넘어간다.

cmd
lst[0]
lst[1]
...
lst[-1]

 그런데 smbus의 read_2ic_block_data()함수는 cmd 한 바이트를 먼저 전송한 후 데이터를 읽는다. 즉, 실제 동작은 _onReceive()함수가 먼저 호출되고 그 다음 _onRequest()함수를 호출한다. 따라서 예를 들면 아두이노의 핸들러 함수는 다음과 같이 작성해야 한다.

byte _cmd_i2c;
byte _rcvBuf[32];

void _onReceive(int count) {
   _cmd_i2c = Wire.read(); // 첫 바이트는 *항상* command

   //만약 smbus.read_i2c_block_data()호출이라면 여기서 종료되고
   //바로 _onRequest() 함수가 호출된다.
   if (count > 1) {
       _rcvBuf[0] = _cmd_i2c;
       _idx = 1;
       while(Wire.available())
           _rcvBuf[_idx++] = Wire.read();
   }
}

void _HRP_::_onRequest() {
   switch(_cmd_i2c) {
       // _cmd_i2c 에 따라 해당 데이터를 전
   }
}

위와 같이 작성하면 master에서 전송된 데이터는 command까지 포함해서 모두 _rcvBuf 배열에 저장되고 데이터를 전송하는 경우에는 _cmd_i2c 변수의 내용에 따라 각기 다른 데이터를 전송할 수 있다.


파이썬의 smbus 패키지를 이용하여 i2c 통신하기

 며칠간 라즈베리파이와 아두이노간 i2c 통신을 위해서 python3-smbus 라이브러리를 사용하였는데 여기에 몇 가지를 기록한다. 설치하는 법은 다음과 같다.

sudo apt-get update (먼저 반드시 수행해야 한다.)
sudo apt-get install python3-smbus

라즈베리파이 B+와 ver. 2 에는 i2c 포트가 두 개가 있는데 각각 i2c-0, i2c-1 이다. 만약 1번을 사용한다면 다음과 같이 초기화 할 수 있다.

import smbus
dev = smbus.SMBus(1)

smbus 레퍼런스에 보면 cmd (command) 파라메터가 있는데 이것은 단순히 보내는 데이터의 맨 앞에 먼저 보내지는 데이터이다. 보통 슬레이브는 이것을 보고 어떤 명령인지(또는 어떤 데이터가 따르는지)를 판별한다.

 그리고 함수들 중에 i2c 가 붙은 것들이 있는데 이것이 더 효율적이라고 한다.

read_i2c_block_data(addr, cmd [, length] )
write_i2c_block_data(addr, cmd, lst)

write_2ic_block_data()함수는 다음과 같이 데이터를 전송한다.

cmd
lst[0]
lst[1]
...
lst[-1]

read_2ic_block_data()함수는 cmd 한 바이트를 먼저 전송한 후 데이터를 읽어온다.

smbus에는 write_block_data()라는 함수도 있는데 write_i2c_block_data()와의 차이점은 전송되는 데이터가 하나 다르다는 것이다. 두 번째 바이트에 데이터의 길이를 전송한다.


cmd
size
lst[0]
lst[1]
...
lst[-1]

만약 i2c 통신을 사용하는 것이라면 read_i2c_block_data(), write_i2c_block_data() 함수를 사용하는 것이 좋다.


ardpy 개발 동기

 필자는 아두이노(Arduino)와 라즈베리파이(Raspberry pi)에 관심이 많다. 교육 현장에서 2000년대 초반부터 AVR로 마이크로컨트롤러(micro-controller)로 수업을 진행했었는데 간단해 보이는 8비트 마이크로컨트롤러도 그 개발 환경을 구축하고 매뉴얼을 참고하며 코딩을 수행한다는 것이 (학생들 입장에서는) 결코 수월하지 않다. 이러던 차에 아두이노가 개발되어 많은 사람들에게 사용되면서 이러한 고민을 해소시켜 주었다. 아두이노의 장점을 들라면 다음과 같은 것들이 있을 것이다.

  • PC와 USB로 연결만 하면 구축되는 간편한 개발 환경
  • 사용하기 쉬운 전용  IDE와 라이브러리
  • 폭넓은 사용자들이 쌓아 놓은 풍부한 개발 정보
  • 저가로 쉽게 구매 가능
  • 다양한 목적에 부합되는 보드들을 동일한 개발 환경을 사용

이에 반해서 단점을 꼽으라면 아무래도  C++에 대한 지식이 있어야 된다는 점인데 제대로 코딩하기 위한 학습 노력이 요구된다.

[그림 1] 다양한 아두이노 제품들

 이러한 장점들 때문에 현재는 소위 메이커(maker)들의 절대적인 지지를 얻고 있으며 필자의 마이크로컨트롤러 수업도 아두이노를 이용하여 진행하고 있는데 교육 효과가 이전보다 훨씬 더 낫다고 느끼고 있다.

 아두이노가 저변을 넓혀가는 와중에 사물인터넷(IoT)이 화두로 떠오르기 시작했는데 아두이노로 사물인터넷 제품을 구현하고자 하는 시도가 많이 일어났다. 보통은 wifi 쉴드를 아두이노에 얹어서 네트워크에 연결하여 아두이노에 연결된 기기들을 제어하는 방식인데 아두이노가 기본적으로 AVR 기반이다 보니 낮은 성능과 복잡한 코드로 인해서 이런 작업을 수행하기엔에는 수월하지가 않다. 사물인터넷을 겨냥한 아두이노 융(YUN)이라는 제품도 있으나 비싼 가격과 제한된 성능으로 인해서 별로 매력적이지 않다. 필자는 아두이노 자체만으로 네트워크 연결을 구현하거나 사물인터넷 제품을 만드는 것은 부적합하다고 생각하는 편이다.

 한편, 라즈베리파이는 영국에서 개발된 저가의 컴퓨터이며 가격이 35달러 이하의 제품군으로 구성되어 있다. 신용카드만한 크기에다 하드디스크를 대신할 메모리카드에 운영체제를 올려서 완벽한 리눅스 컴퓨터로 사용할 수 있는 획기적인 제품으로서 저가이면서도 상대적으로 높은 성능으로 인해서 크게 각광을 받고 있는 제품이다.

[그림 2] 라즈베리파이 컴퓨터

원래는 저개발국이나 후진국 아이들의 교육용으로 개발되었으나 일반인들의 관심도 많이 받아서 다양한 분야에서 널리 사용되고 있다. 기본적으로 리눅스 컴퓨터이기 때문에 C/C++은 물론이고 파이썬(python), 자바스크립트(node.js), 자바(java) 등 각종 언어들을 자유롭게 사용할 수 있으며 웹서버를 구축하거나 하는데 전혀 제약이 없다. 하지만 헤더핀의 기능이 제한적이기 때문에 여기에 각종 센서나 작동기 등을 연결하여 제어하는 데에는 제약이 따른다. 센서나 모터와 같은 기기를 제어하는 기능으로만 따져 본다면 아두이노보다도 더 비효율적이다.
 
 이러한 배경으로 인해서 필자는 라즈베리파이에 아두이노를 연결하여 파이썬으로 제어할 수 있는 환경을 구축하는데 관심이 많았다. 시중에 이러한 제품들이 몇몇 있기는 하지만 필자의 요구를 충족시키지는 못하였다. 그래서 직접 라이브러리를 개발하기 시작하였고 ardpy라는 이름을 붙여서 배포하고 있다. 이것을 오픈소스로 공개한 이유는 다양한 사용자들과 같이 고민하면서 발전시키면서 좀 더 많은 사람들에게 도움이 되는 라이브러리가 되기를 기대하기 때문이다.


홈