여기에서는 LED를 켜고 끄는 실험을 해 보도록 한다. LED는 파이썬 코드가 GPIO를 동작시키는 것을 시각적으로 확인할 수 있는 가장 간단한 도구이다. 다음 그림과 같이 LED를 저항과 직결한 뒤 12번 핀에 연결한다. 저항은 200Ω (혹은 그 이상) 이고 이것은 LED에 과전류가 흐르는 것을 막아주는 역할을 한다. LED는 극성이 있는 소자이다. 다리가 긴 쪽이 anode(+극), 짧은 쪽이 cathod(-극)이므로 연결할 때 방향을 주의해야 한다. 잘못 연결하면 LED가 켜지지 않는다. 짧은 다리는 저항과 직결하여 6번 핀(GND)에 연결하고 긴 쪽은 12번 핀과 연결하면 된다.


그림 9.2.1 LED 결선도 (긴 다리를 12번 핀에 연결)


 GPIO핀으로 LED를 제어하기 위해서 이 핀을 먼저 GPIO.setup()를 이용하여 출력으로 설정해야 한다. 그 이후에 GPIO.output()함수로 GPIO.HIGH 신호를 내보내면 LED가 켜지고 GPIO.LOW 신호를 내보내면 LED가 꺼진다.


blink.py

import RPi.GPIO as GPIO
import time

led = 12
GPIO.setmode(GPIO.BOARD)
GPIO.setup(led, GPIO.OUT)

for k in range(10):
   GPIO.output(led, GPIO.HIGH)
   time.sleep(0.5)
   GPIO.output(led, GPIO.LOW)
   time.sleep(0.5)

GPIO.cleanup()


이 프로그램은 LED를 10번 점멸시키고 난 뒤 종료된다. 이것을 실행하려면 다음과 같이 하면 된다.


sudo python3 blink.py


전에 언급한 바와 같이 반드시 앞에 sudo 명령을 붙여야 한다는 것이 유의하자.


 한 가지 언급할 것은 저항 값을 선택하는 방법이다. 데이터 쉬트에 의하면 LED에는 10mA 정도 흐르도록 하면 되고 이때 LED의 전압 강하가 1.7V 정도이다. 따라서 오옴의 법칙에 의해서 R = (3.3-1.7)/0.01 = 160Ω  을 얻을 수 있다. 이 결과로부터 160Ω 이상의 저항을 선택하되 너무 저항 값이 크면 불빛을 눈으로 확인하기 어려우므로 160~500Ω 범위의 저항을 선택하면 된다.

원문링크

Posted by 살레시오
,

 GPIO를 제어하기 위한 방법은 여러가지가 있지만 여기에서는 파이썬으로 하는 방법에 대해서 소개하고자 한다. GPIO를 제어하기 위한 파이썬 패키지 중에서 RPi.GPIO 모듈과 WiringPi 라는 모듈이 가장 많이 쓰인다. 특히 RPi.GPIO는 라즈비언에 기본으로 설치되어 있으므로 별도로 설치하는 과정이 필요치 않다. 여기에서는 이것을 이용하기로 한다.


 RPi.GPIO 모듈을 사용하기 위해서는 먼저 다음과 같이 import 명령으로 불러와야 한다.


import RPi.GPIO as GPIO


그 이후에 다음과 같은 메서드들을 사용할 수 있다.


표 9.2.1 RPi.GPIO 모듈의 기본적인 메서드들

메서드 명

기능

GPIO.setmode(GPIO.BOARD)

GPIO.setmode(GPIO.BCM)

핀 번호를 라즈베리파이 보드(BOARD) 번호로 참조

BCM(Broadcom chip-specific pin numbers)모드

GPIO.setup(pin, GPIO.IN)

GPIO.setup(pin, GPIO.OUT)

핀을 입력으로 설정

핀을 출력으로 설정

GPIO.output(pin, GPIO.HIGH)

GPIO.output(pin, GPIO.LOW)

디지털 출력을 HIGH로 설정

디지털 출력을 LOW로 설정

GPIO.input(pin)

디지털 값을 읽음.

GPIO.cleanup()

GPIO 모듈의 점유 리소스를 해제

GPIO.VERSION

RPi.GPIO 모듈의 버전값을 갖는 변수


 GPIO.setmode()함수는 핀 번호를 지정할 때 어떤 참조 방식을 사용하는지를 설정하는 함수로서 다른 메서드를 사용하기 전에 반드시 사전에 호출해야 하는 함수이다. 인자로는 기정의된 상수를 받는데 GPIO.BOARD 는 핀 번호로 라즈베리파이 보드 상의 번호(1~40)를 이용하겠다고 설정하는 것이다. GPIO.BCM은 브로드컴칩의 번호를 참조하겠다는 것으로서 그림 9.1의 GPIOXX 에서 XX에 해당하는 번호를 사용하겠다는 것이다. 예를 들어 GPIO.BOARD 모드에서 12번 핀은 GPIO.BCM 모드에서 18번 핀과 동일하다. 다른 메서드들을 사용하기 앞서서 반드시 GPIO.mode()함수를 호출하여 핀 번호 참조 모드를 지정해 주어야 하며 이 모드의 설정없이 다른 메서드들을 호출하려고 하면 예외가 발생한다.


   GPIO.setup() 함수는 아두이노의 pinMode()함수와 유사한 기능을 수행한다. GPIO.input()이나 GPIO.output()함수를 호출하기 전에 사용하고자 하는 핀이 입력인지 출력인지를 먼저 설정해 주어야 한다. 만약 GPIO.setup() 함수 호출시 풀업(pull-up)이나 풀다운(pull-down) 저항을 연결하려면 다음과 같이 pull_up_down 키워드 파라메터를 GPIO.setup()함수에 넘겨야 한다.


GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP )

GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_DOWN )


pull_up_down 파라메터를 주지 않으면 아무런 저항도 연결되지 않는다.


 GPIO 모듈의 사용이 모두 끝나면 GPIO.cleanup()함수를 호출하는 것이 좋다. 이 함수를 호출하면 사용 중인 핀을 포함해서 모든 리소스가 시스템에 반환된다.


 한 가지 주의할 점은 RPi.GPIO는 하드웨어에 접근하여 작업을 수행하기 때문에 root권한이 필요하다. 따라서 파이썬쉘을 실행할 때 반드시 sudo 명령을 사용해야 GPIO 메서드들을 정상적으로 사용할 수 있다.


sudo python3

sudo ipython3


또한 RPi.GPIO 패키지를 사용하는 스크립트파일(,py 파일)을 실행하는 경우에도 마찬가지로 sudo 명령을 사용해야 정상적으로 실행이 된다. 예를 들어 blink.py 파일에서 RPi.GPIO 패키지를 사용한다면


sudo python3 blink.py


와 같이 sudo 명령을 반드시 앞에 붙여야 한다.

원문링크

Posted by 살레시오
,

 라즈베리파이 2에는 40개의 헤더 핀(header pin)이 있는데 이것을 외부의 장치들을 연결하여  제어할 수 있다. 다음 그림에 그 구조를 도시하였다.



BCM

핀 번호

BOARD

BCM



3.3V

1

2

5V


SDA1

GPIO2

3

4

5V


SCL1

GPIO3

5

6

GND



GPIO4

7

8

GPIO14

TxD


GND

9

10

GPIO15

RxD


GPIO17

11

12

GPIO18



GPIO27

13

14

GND



GPIO22

15

16

GPIO23



3.3V

17

18

GPIO24


MOSI

GPIO10

19

20

GND


MISO

GPIO9

21

22

GPIO25


SCLK

GPIO11

23

24

GPIO8

CE0


GND

25

26

GPIO7

CE1

SDA0

GPIO0

27

28

GPIO1

SCL0


GPIO5

29

30

GND



GPIO6

31

32

GPIO12



GPIO13

33

34

GND



GPIO19

35

36

GPIO16



GPIO26

37

38

GPIO20



GND

39

40

GPIO21



그림 9.1.1 라즈베리파이 B+, A+, 2B의 GPIO 헤더핀들


라즈베리파이 초기 모델에는 26핀만 있었다. 라즈베리파이 B+ 을 포함한 이후의 모델은 (A+, 2 model B, zero) 이것이 확장되어 40핀 GPIO핀을 갖는데 26번 핀까지는 동일한 배치이고 27번부터 40번까지가 더 추가되었다.


  그림 9.1을 보면 40개 중 대부분이 GPIO라고 이름이 붙어 있는데 이는 디지털 신호(digital signal)를 입출력 할 수 있는 포트핀 (port pin)으로 사용할 수 있다는 의미이다. 디지털 신호란 두 가지 상태만을 갖는 신호를 의미하며 하나의 비트로 표시되며 0 혹은 1 값만을 가질 수 있다. 물리적으로는 전압으로 구별되며 라즈베리파이에서  0은 0V(GND), 1은 3.3V 전압을 의미한다. (라즈베리파이의 내부 로직은 3.3V로 동작한다. 반면 아두이노는 보통 5V로 동작하는데 따라서 이 둘을 직접 연결할 경우 라즈베리파이가 손상될 가능성이 있다.) 포트핀은 츨력 혹은 입력 기능을 수행할 수 있는데 출력으로 사용되면 0V 혹은 3.3V 전압값을 갖도록 할 수 있으며 입력으로 사용된다면 포트핀의 전압이 0V인지 3.3V인지를 감지할 수 있다. 이 기능을 이용하면 예를 들어 LED를 점멸한거나 혹은 연결된 버튼의 눌렸는지 여부를 알아낼 수 있다.


 이외에도 5V/3.3V/0V(GND)는 외부에 전원을 공급할 때 사용되는 전원핀이고,  시리얼 통신/SPI 통신/I2C통신을 할 수 있으며 PWM 기능을 갖는 핀도 있다. 하지만 아날로그 입력을 받을 수 있는 핀은 없으며 이를 위해서는 별도의 외부 장치를 이용해야 한다.


 라즈베리파이에는 헤더핀만 나와있어서 빵판을 이용하여 실험하고자 할 때는 조금 불편하다. 이를 개선하기 위해서 다양한 연결 부품이 시중에 시판되고 있다.


그림 9.1.2 GPIO 핀을 빵판에 편리하게 연결해주는 제품의 예


이러한 확장 보드를 이용하면 앞으로의 실험을 좀 더 편하게 실행할 수 있다.

원문링크

Posted by 살레시오
,

 지시자(directive)인 volatile 은 변수 선언문의 변수형 앞에 두어서 컴파일러가 그 변수를 접근하는 방식을 지정한다.


 일반적으로 변수 데이터는 런타임에 RAM영역에 저장되지만 어떤 변수는 레지스터(register)에 임시로 저장되어 사용하기도 하는데 이 경우 속도면에서는 월씬 유리하지만 RAM에 저장된 실제 데이터와 레지스터에 저장된 (임시)데이터가 서로 다른 경우가 발생할 수도 있다.


 어떤 변수를 volatile로 지정하면 그 변수 데이터는 레지스터의 임시 저장소가 아니라 RAM에서 직접 읽어오도록 컴파일된다. 아두이노 프로그램의 경우 보통은 volatile로 정의할 필요는 없으나 인터럽트 서비스 루틴 (ISR) 내부에서 그 값이 변경되는 변수는 반드시 volatile로 선언해야 실시간으로 변경되는 데이터 값을 ISR 외부에서 정확하게 읽어올 수 있게 된다. 예를 들면 다음과 같다.


// toggles LED when interrupt pin changes state

int pin = 13;
volatile int state = LOW;

void setup()
{
 pinMode(pin, OUTPUT);
 attachInterrupt(0, blink, CHANGE);
}

void loop()
{
 digitalWrite(pin, state);
}

void blink()
{
 state = !state;
}


위의 예에서 blink()함수가 ISR이며 이 안에서 변경되는 변수 state는 volatile로 지정하였음을 확인할 수 있다.

(출처 : https://www.arduino.cc/en/Reference/Volatile )



Posted by 살레시오
,

1.3 Raspian(Debian)에서 ipython 설치 방법  c{ipy04}

라즈비안(rasbian)에서는 python3는 기본으로 설치되어 있다. 여기에 ipython3을 설치하는 방법은 매우 간단하다.


~$ sudo apt-get install ipython3

설치가 끝난 다음에 다음과 같이 실행할 수 있다.


~$ ipython3

이렇게 명령을 내리면 ipython쉘이 실행된다.


Posted by 살레시오
,

 풀업이 된 푸시버튼이 2번 핀에 연결되었다고 가정하자. 이 버튼은 외부에 풀업이 된 상태이기 때문에 안 눌려진 상태에서는 1값이 읽혀지고 눌려지면 0값이 읽힌다. 부저는 11번핀에 연결되었다고 가정한다.


 이 때 버튼이 눌려지는 시점에서 멜로디가 울리도록 하는 프로그램은 다음과 같다. tone()함수는 ISR 내부에서는 정상적으로 동작하기 않기 때문에 인터럽트 기능은 사용할 수 없다는 점에 유의하자.


#include "pitches.h"
#define BUZ 11
#define K 2

void setup() {
 pinMode(K, INPUT);
}

int iBtnPrev = 1; //버튼의 이전 상태값을 저장하는 변수

void loop() {
 int iBtn = digitalRead(K);
 if (iBtn == 0 && iBtnPrev == 1)
   melody();
 iBtnPrev = iBtn;
}

void melody() {
 tone(BUZ, NOTE_C4);
 delay(100);
 tone(BUZ, NOTE_D4);
 delay(100);
 tone(BUZ, NOTE_E4);
 delay(100);
 noTone(BUZ);
}


이 프로그램을 다운로드하면 버튼이 눌리는 순간 ‘도레미’ 멜로디가 울린다.



Posted by 살레시오
,

아두이노 아날로그핀 연습 문제


1. 가변저항에 노브(knob)가 연결되어 이거을 돌리면 출력이 0~1023 사이의 값이 나온다고 가정하자. 이것으로 부저의 주파수(31~4978Hz)를 조절하는 프로그램을 작성하라.


2. 아날로그 광량센서를 이용하여 주변이 어두워지면 LED가 켜지고 밝아지면 꺼지는 프로그램을 작성하라.


3. X축, Y축, 버튼이 달린 조이스틱이 아날로그핀과 디지털핀에 연결되었다고 가정하자. X축 값과, Y축 값, 버튼 상태를 시리얼 터미널에 출력하는 프로그램을 작성하라.


4. 조이스틱의 버튼이 눌렸다면 X축의 위치에 따라 부저의 주파수가 변하는 프로그램을 작성하라. 버튼이 눌려지지 않았다면 부저에서는 소리가 나지 않아야 한다.


5. 아두이노의 tone()함수는 ISR 내부에서 사용할 수 없다. 이 사실에 유의하여 조이스틱의 버튼이 눌리는 순간에 '도레미' 음이 발생하도록 프로그램을 작성하라. 다음 함수를 이용해야 한다.


#define BUZ 11

void melody() {

tone(BUZ, NOTE_C4);

delay(100);

tone(BUZ, NOTE_D4);

delay(100);

tone(BUZ, NOTE_E4);

delay(100);

noTone();

}



Posted by 살레시오
,

 요즘에는 저가의 초소형 리눅스 보드들이 많이 출시되고 있는데 nanopi 도 그 중 하나이다.

스펙은 라즈베리파이1에 비해서도 낮은 성능이지만 그 절반 크기에 와이파이와 블루투스 모듈이 내장되어 있다. 가격은 최소가 기준으로 $25 이다.


 업그레이드 버젼도 있는데 nanopi2 이다. 유사한 폼펙터에 1.4GHz, 램1G 으로 라즈베리파이2보다도 높은 성능을 가진다. 가격은 $32 이다.

이 보드들의 장점은 작은 사이즈(라즈베리파이의 절반 크기), 와이파이와 블루투스 모듈을 내장했음에도 가격은 다소 더 저렴하다는 것이다.



Posted by 살레시오
,

 아두이노에는 tone()함수가 제공되는데 부저나 스피커로 음을 발생시킬 수 있는 함수이다. 기본 문법은 다음과 같다.


tone(pin, freq [, duration]);


  • pin : 부저나 스피커가 연결된 디지털 핀번호

  • freq : 주파수 (범위 : 31 ~ 65535)

  • duration : (옵션) 음의 발생 시간


여기서 duration은 주파수 지속시간으로서 이 시간이 지난 후에 noTone()함수가 자동으로 호출되는 것과 같은 효과를 낸다.  duration이  생략되면 noTone()함수가 호출될 때까지 음이 계속 발생된다. 예를 들어서 11번 핀에 부저가 연결되었다면 다음과 같이 한다.


tone(11, 262); // ‘도’음 발생
delay(500);
noTone(11);


이 코드는 ‘도’음을 0.5초간 발생시키는데 다음과 같이 할 수 있다.


tone(11, 262, 500);


이렇게 하면 음 발생 직후 다른 작업을 수행할 수 있으며 500ms후에는 내부 인터럽트가 발생하여 음발생이 자동으로 정지된다. 하지만 단음만 생성할 경우에는 상관없지만 연속음을 생성할 경우에는 주의해야 한다.


tone(11, 262, 500); // ‘도’음
tone(11, 294, 500); // ‘레’음
tone(11, 330, 500); // ‘미’음


이렇게 하면 맨 마지막의 ‘미’음만 발생하게 된다. (왜?) 따라서 올바른 동작을 위해서는 다음과 같이 해야 한다.


tone(11, 262); // ‘도’음 발생
delay(500);
tone(11, 294); // ‘레’음 발생
delay(500);
tone(11, 330); // ‘미’음 발생
delay(500);
noTone(11);
tone(11, 262); // ‘도’
delay(500);
tone(11, 294); // ‘레’
delay(500);
tone(11, 330, 500); // ‘미’


tone()함수는 내부적으로 타이머를 사용하므로 다음과 같은 점들을 주의해야 한다.

  • 이 함수를 사용할 경우 3번 11번 핀의 PWM이 정상적으로 동작되지 않는다.

  • 한 번에 하나의 주파수만 발생시킬 수 있으며 여러 핀에 동시에 다른 음을 발생시킬 수 없다.


 특정 음에 해당되는 주파수를 일일이 숫자로 기입하는 것은 가독성 면에서 좋지 않으며 이를 개선하기 위해서 아두이노에서는 음의 주파수만을 모아놓은 “pitches.h”라는 헤더파일을 제공한다. 내용은 다음과 같다.


/*************************************************
* Public Constants
*************************************************/
#define NOTE_B0  31
#define NOTE_C1  33
#define NOTE_CS1 35
#define NOTE_D1  37
#define NOTE_DS1 39
#define NOTE_E1  41
#define NOTE_F1  44
#define NOTE_FS1 46
#define NOTE_G1  49
#define NOTE_GS1 52
#define NOTE_A1  55
#define NOTE_AS1 58
#define NOTE_B1  62
#define NOTE_C2  65
#define NOTE_CS2 69
#define NOTE_D2  73
#define NOTE_DS2 78
#define NOTE_E2  82
#define NOTE_F2  87
#define NOTE_FS2 93
#define NOTE_G2  98
#define NOTE_GS2 104
#define NOTE_A2  110
#define NOTE_AS2 117
#define NOTE_B2  123
#define NOTE_C3  131
#define NOTE_CS3 139
#define NOTE_D3  147
#define NOTE_DS3 156
#define NOTE_E3  165
#define NOTE_F3  175
#define NOTE_FS3 185
#define NOTE_G3  196
#define NOTE_GS3 208
#define NOTE_A3  220
#define NOTE_AS3 233
#define NOTE_B3  247
#define NOTE_C4  262
#define NOTE_CS4 277
#define NOTE_D4  294
#define NOTE_DS4 311
#define NOTE_E4  330
#define NOTE_F4  349
#define NOTE_FS4 370
#define NOTE_G4  392
#define NOTE_GS4 415
#define NOTE_A4  440
#define NOTE_AS4 466
#define NOTE_B4  494
#define NOTE_C5  523
#define NOTE_CS5 554
#define NOTE_D5  587
#define NOTE_DS5 622
#define NOTE_E5  659
#define NOTE_F5  698
#define NOTE_FS5 740
#define NOTE_G5  784
#define NOTE_GS5 831
#define NOTE_A5  880
#define NOTE_AS5 932
#define NOTE_B5  988
#define NOTE_C6  1047
#define NOTE_CS6 1109
#define NOTE_D6  1175
#define NOTE_DS6 1245
#define NOTE_E6  1319
#define NOTE_F6  1397
#define NOTE_FS6 1480
#define NOTE_G6  1568
#define NOTE_GS6 1661
#define NOTE_A6  1760
#define NOTE_AS6 1865
#define NOTE_B6  1976
#define NOTE_C7  2093
#define NOTE_CS7 2217
#define NOTE_D7  2349
#define NOTE_DS7 2489
#define NOTE_E7  2637
#define NOTE_F7  2794
#define NOTE_FS7 2960
#define NOTE_G7  3136
#define NOTE_GS7 3322
#define NOTE_A7  3520
#define NOTE_AS7 3729
#define NOTE_B7  3951
#define NOTE_C8  4186
#define NOTE_CS8 4435
#define NOTE_D8  4699
#define NOTE_DS8 4978


이 헤더파일은 전역 상수 정의로만 이루어져 있으므로 실행 파일의 용량을 증가시키진 않는다. 따라서 이 파일을 폴도에 복사한 후 인클루드시켜서 필요한 주파수를 사용하면 된다.


#include “pitches.h”
tone(11, NOTE_C3, 1000); // 3도 ‘도’음을 1초간 발생
...


이렇게 주파수(숫자) 대신 상수 이름을 사용하면 가독성이 높아지게 된다.




Posted by 살레시오
,

 시중에서 쉽게 구할 수 있는 저가형 초음파 센서 모듈(HC-HR04)는 그림과 같이 4핀 인터페이스를 갖는다. Vcc/GND는 전원핀이고 Trig는 초음파를 발생시키는 펄스 신호를 내보내는 핀이며 Echo는 반사파가 감지되었음을 알려주는 신호선이다. 따라서 이 모듈을 사용하려면 아두이노의 디지털 핀 두 개가 필요하다.


초음파 센서 모듈인 HC=SR04를 이용하기 위해서 아두이노의 NewPing 라이브러리를 이용해 보자. 압축된 zip 파일을 다운로드 받은 후에 다음과 같이 아두이노 IDE에서 등록할 수 있다.


스케치 > Include Library > Add .ZIP Library


설치하였다면 다음과 같이 메뉴에 항목이 새로 만들어진다. 이것을 선택하면 프로그램에 #include “NewPing.h” 가 추가되고 라이브러리 함수를 사용할 수 있다.



NewPing 라이브러리의 생성자는 다음과 같다.


NewPing sonar(trigger_pin, echo_pin [, max_cm_distance]);


해당되는 핀 번호 두 개와 최대 측정 거리(기본값 500 cm)를 주게 되어 있으며 최대 측정 거리는 생략할 수 있다.

이 라이브러리는 다양한 함수를 제공하고 있으나 여기에서 사용할 함수는 sonar.ping() 이다. 이 함수는 초음파가 발사되고 그 반사파가 감지될 때까지 걸린 시간을 microsecond 단위의 정수로 반환한다. 따라서 이 값을 라이브러리에 기정의된 상수 US_ROUNDTRIP_CM 으로 나누면 장애물까지의 거리를 cm단위로 얻을 수 있다.


sonar.ping(); // 반사파가 감지될 때 까지의 시간을 us 단위의 정수로 반환
// 감지 가능 거리 내에 장애물 없을 때 0을 반환
US_ROUNDTRIP_CM // us를 cm단위로 바꾸어주는 상


완전한 예제는 다음과 같다. trig 는 2번 핀에 echo 는 3번 핀에 연결되었다고 가정한다.


#include <NewPing.h>
#define TRIGGER_PIN  2
#define ECHO_PIN     3
NewPing sonar(TRIGGER_PIN, ECHO_PIN);
void setup() {
 Serial.begin(9600);
}

void loop() {
 float fDist = (float)sonar.ping()/US_ROUNDTRIP_CM;
 Serial.print("Ping: ");
 Serial.print(fDist);
 Serial.println(" cm");
 delay(100);
}


위에서 fDist 변수값을 구하는데 sonar.ping()함수의 반환값을 float로 변환했음에 유의하자. 이렇게 해야 정확한 실수값이 구해지게 된다.




Posted by 살레시오
,