Ail_ 2022. 1. 7. 18:57

참고한 책 : 진짜 코딩하며 배우는 라즈베리파이 4

 

IoT

구성요소

Sensors/Device

Network

Platform

BIg Data

Application/Service

 

 

라즈베리파이 os 설치

커스텀 img 파일 다운

img 파일 다운

imager_1.6.2.exe 다운

 

커스텀 파일(이미지) 사용하여 sd카드에 설치(imager_1.6.2.exe 실행)

custome - 다운받은 img 파일 선택

Storage - sd카드 선택 - wirte

img : 리눅스 기반 커스텀 파일

 

라즈베리파이에 랜선으로 연결해 아이피를 타고 들어가 접속하는 방식

 

sd카드 - boot 드라이브

command line.txt => 끝에 ip=192.168.138.100 추가

ssh 파일 추가(확장자명 x)

 

라즈베리파이의 sd카드, 랜선, 전원 모두 연결

 

노트북을 공유기처럼 사용(내부 네트워크를 구성할 수 있음)

(원래는 공유기에 노트북과 라즈베리파이를 각각 연결하는 게 맞으나 공사가 덜 끝난 관계로...)

 

네트워크 연결 보기

WI-FI 속성 - 공유 항목 둘다 체크, 홈 네트워킹 연결 : 이더넷

이더넷 - 인터넷 프로토콜 버전4(TCP/IPv4) : 다음 IP 주소 사용 설정(IP주소 192.168.138.1)

주의! 이더넷 연결 꼭 확인할 것(전원 콘센트가 불안정하여 전원이 꺼질 수 있음)

 

PuTTY

HostName에 192.168.138.100 입력 후 Open 클릭

 

Login as: pi

~password : raspberry(입력한 문구 안보임 주의)

pi(계정이름)@raspberrypi(호스트 이름) :~ $(현재 디렉토리)

라즈베리파이에 접속 완료

 

리눅스 기본 명령어

ls : 파일과 디렉토리 목록을 보여줌(= 윈도우의 파일탐색기) / 다양한 옵션이 있음(-a, -l -r 등, -al처럼 같이 써도 됨)

pwd : 현재 작업중인 디렉토리 확인 가능(print working directory)

tree : 디렉토리 구조를 트리 모양으로 출력

cd : 디렉토리 이동

cd 위치 적을 때 앞글자만 치고 tap 누르면 있는 폴더의 경우 자동완성 됨(home일 경우 h, tap)

touch 파일명 : 파일 생성

rmdir 디렉토리명 : 빈 디렉토리 삭제(파일 있으면 삭제 안됨)

rm 파일명 : 파일 삭제

rm -r 디렉토리명 : 해당 디렉토리와 파일 삭제

rm -r : 디렉토리와 함께 파일까지 삭제 가능(현재 어디 위치인지 매우 주의해서 사용해야함)

cat 파일명 : 파일 내용 확인

vi 파일명 : 리눅스 기본 에디터 => i 누르면 편집 가능

nano 파일명 : nano 에디터

 

 

VSCode 사용

Remote-SSH install

 

Remote Player - Add new

 

pi@192.168.138.100 입력 후 enter

 

맨 위 그냥 enter

 

ip 주소 확인

 

 

Linux - Continue 선택

 

오른쪽 버튼 Connect to Host in new window or 우클 후 Connect to Host in current window

 

비밀번호(동일)입력하면 연결 완료

 

Open Folder - password 입력

 

폴더 내용 확인 가능

 

라즈베리파이의 파이썬 패키지 사용

예외 처리

try:
    while True:
      print("Hello. I'm Raspberry Pi")
      
except KeyboardInterrupt: # ctrl+c 강제종료하면 그냥 멈추겠다
      pass

time.sleep

import time

try:
    while True:
        print("Hello. I'm Raspberry Pi")
        time.sleep(0.5)
except KeyboardInterrupt:
    pass

실행 결과

데이터 타입/연산/리스트

num = 2
print(num) # 2
print(type(num)) # <class 'int'>

a = 1
b = 2
sum = a+b
print(sum) # 3

print(17/3) # 5.666666666666667
print(type(17/3)) # <class 'float'>
print(17//3) # 5 : 몫 출력
print(17%3) # 2 : 나머지 출력

# 리스트
L = ["python", 1,2,3,4, "last"]

print(L[0]) # python
print(L[1]) # 1
print(L[2]) # 2

print(L[1:3]) # [1, 2] : 1부터 3까지
print(L[5][1]) # a : 5번째의 1번 인덱스

L.append(4) # 맨뒤에 한 개 추가
L.append(5)

print(len(L)) # 8 : 길이 확인(length)
print(L) # ['python', 1, 2, 3, 4, 'last', 4, 5]

L.extend([12, 35])

print(len(L)) # 10
print(L) # ['python', 1, 2, 3, 4, 'last', 4, 5, 12, 35]

파이썬 수행 속도 측정

import time
start = time.time() # 현재 시간을 얻어와 start 변수에 저장

cnt = 0
while True: # 반복
    cnt = cnt+1 # cnt 변수를 하나 증가
    if cnt>10000000: # cnt 변수 값이 10000000보다 크면
        break # 10줄로 이동

end = time.time() # 현재 시간을 얻어와 end 변수에 저장
print(cnt) # 10000001 : cnt 변수 값 출력
print(end - start) # 9.522742748260498 : 천만번 수행하는데 걸리는 시간

논리 연산자 / 비교연산자

# 논리 연산자
print(True and True)
print(True and False)
print(False or True)
print(False or False)

print(not False)
print(not True)

'''
True
False
True
False

True
False
'''

# 비교 연산자
print(4 == 4)
print(4 != 4)
print(4 > 4)
print(4 >= 4)

'''
True
False
False
True
'''

 조건문 / for문 / while

# 조건문
x = 3
if x == 3:
    print("true1") # true1
if x == 3:
    print("true2") # true2 상관 없음

x = 3
if x == 3:
    print("true1")
elif x == 3:
    print("true2") # 대전제가 if, elif는 위의 if가 틀려야 실행됨 따라서 실행X
else:
    print("x!=3") # 대전제가 if, if와 elif가 둘다 틀려야 실행됨
    
# for문
sum = 0

for i in range(11):
    sum = sum + i # i는 0부터 11까지(010)

print("i:", i) # i: 10
print("sum:", sum) # sum: 55

sum2 = 0
for j in range(1, 11, 2): # j 1~11까지 2씩 증가하면서 5회 반복
    sum2 = sum2 + j

print("j:", j) # j: 9
print("sum:", sum) # sum: 55

# while
sum = 0
i = 1

while i < 11: # i가 11보다 작을 때까지만 아래 코드를 실행
    sum = sum+i
    print("i:", i)
    i = i+1

print("sum:", sum)

while의 특징 : 특정 조건 실행 가능

# while
sum = 0
i = 1

while i < 11: # i가 11보다 작을 때까지만 아래 코드를 실행
    sum = sum+i
    print("i:", i)
    if( i == 5 ) : break # 특정 조건을 걸어 break 실행 가능
    i = i+1

print("sum:", sum)

함수

def sum(math, eng):
    return (math + eng)

print("sum:", sum(30, 40)) # sum: 70

* 파이썬 기본 제공 함수도 있고(ex. time()) 개발자가 직접 만들어 사용할 수도 있음

 

라즈베리파이3 핀맵

물리적 핀번호와 GPIO 핀번호가 다르다. 참고

물리적 핀번호

GPIO 핀번호 : 소프트웨어에서 입력 또는 출력핀으로 지정될 수 있다

 

 

led 연결

import RPi.GPIO as GPIO # RPi.GPIO 모듈을 GPIO 라는 이름으로 불러옴

led_pin = 17 # 17 : BCM GPIO 핀 번호

GPIO.setmode(GPIO.BCM)
# GPIO.setmode 함수를 호출하여 BCM GPIO 핀 번호 사용하도록 설정

GPIO.setup(led_pin, GPIO.OUT)
# GPIO.setup 함수를 호출해 led_pin을 GPIO 출력으로 설정 => True 또는 False를 써 연결된 LED 조작 가능

GPIO.output(led_pin, True)
# GPIO.output 함수를 호출해 led_pin을 True로 설정 => led_pin에 연결된 LED 켜짐

try:
  while True: # 빈 while문을 수행하며 LED가 켜진 상태 유지
    pass
except KeyboardInterrupt: # ctrl+c를 누르면 키보드 인터럽트 처리
  pass

GPIO.cleanup() # GPIO 핀의 상태 초기화

결과

빛이 있으라~

import RPi.GPIO as GPIO
import time

led_pin = 17

GPIO.setmode(GPIO.BCM)

GPIO.setup(led_pin, GPIO.OUT)

try:
  while True:
    GPIO.output(led_pin, True) # led 켜짐
    time.sleep(0.5) # 0.5초간 지연
    GPIO.output(led_pin, False) # led 꺼짐
    time.sleep(0.5) # 0.5초간 지연

except KeyboardInterrupt:
  pass

GPIO.cleanup()

# 1초 주기로 led가 켜졌다 꺼졌다 함 => 1Hz의 주파수

 

LED 제어

PWD 제어

전기 펄스의 주파수와 폭을 조절하는 것을 PWM 출력 제어라고 함

주파수 : 1초동안 반복되는 사이클의 개수, 단위는 Hz

1Hz : 1초에 1회

100Hz : 1초에 100회

 

PWM 클래스

sleep을 안걸어줘도 됨

import RPi.GPIO as GPIO

led_pin = 18

GPIO.setmode(GPIO.BCM)

GPIO.setup(led_pin, GPIO.OUT)

pwm = GPIO.PWM(led_pin, 1.0) # 1.0Hz
# 첫번째 인자 : 핀 번호, 두번째 인자 : 주파수 값
pwm.start(50.0) # 0.0~100.0
# start함수 호출, 파형 내보내기 시작 / 사각파형의 HIGH 구간의 비율을 나타냄

try:
  while True: # led 핀으로 나가는 PWM 파형 유지
    pass
except KeyboardInterrupt:
  pass

pwm.stop() # pwm 객체에 대해 stop 함수 호출(PWM 파형 출력 멈춤)
GPIO.cleanup()

# 1초 주기로 점멸

부저

떴다떴다 비행기 연주

import RPi.GPIO as GPIO
import time

buzzer_pin = 18

GPIO.setmode(GPIO.BCM)

GPIO.setup(buzzer_pin, GPIO.OUT)

pwm = GPIO.PWM(buzzer_pin, 1.0)
pwm.start(50.0)

melody = [330,294,262,294,330,330,330,294,294,294,330,330,330,330,294,262,294,330,330,330,294,294,330,294,262]
# melody = [262,294,330,349,392,440,494,523]
# 음에 해당하는 주파수

for note in range(0, 25): # note 변수 값을 0부터 25 미만의 정수에 대해 아래 두줄을 수행
  pwm.ChangeFrequency(melody[note]) # pwm 객체에 대해 ChangeFrequency 함수를 호출해 melody[note] 주파수로 설정
  time.sleep(0.5)

pwm.ChangeDutyCycle(0.0) # pwm 객체에 대해 ChangeDutyCycle 함수를 호출해 사각 파형의 HIGH 구간을 0.0%로 설정 => 부저음 안남

pwm.stop()
GPIO.cleanup()

 

 

서브모터

import RPi.GPIO as GPIO
import time

servo_pin = 18

GPIO.setmode(GPIO.BCM)

GPIO.setup(servo_pin, GPIO.OUT)
# pwm.stop() # 강제로 멈추기
pwm = GPIO.PWM(servo_pin, 50) # 50Hz
pwm.start(3.0) #0.6ms

# time.sleep(2.0)
# pwm.ChangeDutyCycle(0.0)

# for cnt in range(0, 3):
#   pwm.ChangeDutyCycle(3.0)
#   time.sleep(1.0)
#   pwm.ChangeDutyCycle(12.5)
#   time.sleep(1.0)

for t_high in range(30, 125):
  pwm.ChangeDutyCycle(t_high/10.0)
  time.sleep(0.02)
  
pwm.ChangeDutyCycle(3.0)
time.sleep(1.0)
pwm.ChangeDutyCycle(0.0)

pwm.stop()
GPIO.cleanup()

아주 미세하게 톱니 바퀴가 돈다...

 

input

사용자 입력을 받는 함수

 

버튼

# 버튼 입력 콘솔창 확인
import RPi.GPIO as GPIO

button_pin = 27

GPIO.setmode(GPIO.BCM)

GPIO.setup(button_pin, GPIO.IN)

try:
  while True:
    buttonInput = GPIO.input(button_pin)
    print(buttonInput)

except KeyboardInterrupt:
  pass

GPIO.cleanup()

버튼과 led 연결

# 버튼 값에 따라 LED 켜기
import RPi.GPIO as GPIO

button_pin = 27
led_pin = 22

GPIO.setmode(GPIO.BCM)

GPIO.setup(button_pin, GPIO.IN)
GPIO.setup(led_pin, GPIO.OUT)

try:
  while True:
    buttonInput = GPIO.input(button_pin)
    GPIO.output(led_pin, buttonInput)

except KeyboardInterrupt:
  pass

GPIO.cleanup()


# 버튼 누르면 켜지고 다시 누르면 꺼지게 하기
import RPi.GPIO as GPIO

button_pin = 27
led_pin = 22

GPIO.setmode(GPIO.BCM)

GPIO.setup(button_pin, GPIO.IN)
GPIO.setup(led_pin, GPIO.OUT)

buttonInputPrev = False
ledOn = False

try:
  while True:
    buttonInput = GPIO.input(button_pin)

    if buttonInput and not buttonInputPrev:
        print("rising edge")
        ledOn = True if not ledOn else False
        # ledOn이 true면 false로 하고 false면 true로 한다
        GPIO.output(led_pin, ledOn)
    elif not buttonInput and buttonInputPrev:
        print("falling edge")
    else:
        pass

    buttonInputPrev = buttonInput

except KeyboardInterrupt:
  pass
  
  GPIO.cleanup()

버튼 인터럽트로 LED 켜기

GPIO.add event callback

인터럽트 : 프로그램 실행 중 CPU의 현재 처리 순서를 중단시키고 다른 동작을 수행하도록 요구하는 시스템 동작

# 버튼 인터럽트로 LED 켜기
import RPi.GPIO as GPIO

led_state = False
led_state_changed = False
def buttonPressed(channel):   # 이벤트 발생 시 처리 함수
  global led_state            # led_state 전역 변수 선언
  global led_state_changed    # led_state_change 전역 변수 선언
  led_state = True if not led_state else False # led state가 true면 false로 바꾸고, false면 true로 바꿈
  led_state_changed = True    # 함수 처리 후 led_state_changed 변수 True로 처리

button_pin = 27
led_pin = 22

GPIO.setmode(GPIO.BCM)

GPIO.setup(led_pin, GPIO.OUT)

GPIO.setup(button_pin, GPIO.IN)
GPIO.add_event_detect(button_pin, GPIO.RISING) # event 감지하는 방법 : GPIO 핀이 low에서 high로 올라갈 때 감지
GPIO.add_event_callback(button_pin, buttonPressed) # event 감지 후 불러올 함수 선언 callback

try:
  while True:
    if led_state_changed == True: # led_state_changed가 True면 False로 다시 돌려놓음
      led_state_changed = False
      GPIO.output(led_pin, led_state)

except KeyboardInterrupt:
  pass

GPIO.cleanup()

 

* 백업을 잊지 말자 : 우클-download

 

쓰레드 Thread

프로세스 : 실행중인 프로그램

쓰레드 : 프로세스 내에서 실행되는 작은 작업의 단위

쓰레드의 동기화 이슈 : 여러 스레드가 동일한 자원(데이터)에 접근 시 동기화 이슈 발생

=> 동일 자원을 여러 스레드가 동시 수정 시, 각 스레드의 결과에 영향을 줌

==> Lock 처리 필요 설명 링크 참고

* 쓰레드와 락은 면접 시에도 많이 물어보는 중요한 항목인만큼 개념 정리를 잘 하자!

import threading
import time

flag_exit = False
def t1_main():
  while True:
    print("\tt1")
    time.sleep(0.5)
    if flag_exit: break

t1 = threading.Thread(target=t1_main)
t1.start()

try:
  while True:
    print("main")
    time.sleep(1.0);

except KeyboardInterrupt:
  pass

flag_exit = True
t1.join()

 


 

느낀 점

복습할 사항 : vi, nano 에디터 연습

                  쓰레드, 락 개념 이해 쓰레드

손으로 조작하며(전선 연결하고 저항 꽂고)하니까 재밌다!

바로바로 실행도 되니까 더 재밌다!