시작은 미약하였으나 , 그 끝은 창대하리라

[Python] MQTT를 이용한 자이로센서 값 전송 (raspberry pi 이용) 본문

프로그래밍/MQTT

[Python] MQTT를 이용한 자이로센서 값 전송 (raspberry pi 이용)

애플파ol 2022. 8. 15. 00:01

(들어가기전에->

1. 자이로센서는 MPU6050 사용하였습니다 )

 

(한국인이 좋아하는 결론부터 말하기)

 

자이로센서 값(데이터)를 전송하는 코드.

'''
        Read Gyro and Accelerometer by Interfacing Raspberry Pi with MPU6050 using Python
	http://www.electronicwings.com
'''
import smbus			        #import SMBus module of I2C
from time import sleep          

#some MPU6050 Registers and their Address
PWR_MGMT_1   = 0x6B
SMPLRT_DIV   = 0x19
CONFIG       = 0x1A
GYRO_CONFIG  = 0x1B
INT_ENABLE   = 0x38
ACCEL_XOUT_H = 0x3B
ACCEL_YOUT_H = 0x3D
ACCEL_ZOUT_H = 0x3F
GYRO_XOUT_H  = 0x43
GYRO_YOUT_H  = 0x45
GYRO_ZOUT_H  = 0x47


def MPU_Init():
	#write to sample rate register
	bus.write_byte_data(Device_Address, SMPLRT_DIV, 7)
	
	#Write to power management register
	bus.write_byte_data(Device_Address, PWR_MGMT_1, 1)
	
	#Write to Configuration register
	bus.write_byte_data(Device_Address, CONFIG, 0)
	
	#Write to Gyro configuration register
	bus.write_byte_data(Device_Address, GYRO_CONFIG, 24)
	
	#Write to interrupt enable register
	bus.write_byte_data(Device_Address, INT_ENABLE, 1)

def read_raw_data(addr):
	#Accelero and Gyro value are 16-bit
        high = bus.read_byte_data(Device_Address, addr)
        low = bus.read_byte_data(Device_Address, addr+1)
    
        #concatenate higher and lower value
        value = ((high << 8) | low)
        
        #to get signed value from mpu6050
        if(value > 32768):
                value = value - 65536
        return value


bus = smbus.SMBus(1) 	# or bus = smbus.SMBus(0) for older version boards
Device_Address = 0x68   # MPU6050 device address

MPU_Init()

print (" Reading Data of Gyroscope and Accelerometer")

while True:
	
	#Read Accelerometer raw value
	acc_x = read_raw_data(ACCEL_XOUT_H)
	acc_y = read_raw_data(ACCEL_YOUT_H)
	acc_z = read_raw_data(ACCEL_ZOUT_H)
	
	#Read Gyroscope raw value
	gyro_x = read_raw_data(GYRO_XOUT_H)
	gyro_y = read_raw_data(GYRO_YOUT_H)
	gyro_z = read_raw_data(GYRO_ZOUT_H)
	
	#Full scale range +/- 250 degree/C as per sensitivity scale factor
	Ax = acc_x/16384.0
	Ay = acc_y/16384.0
	Az = acc_z/16384.0
	
	Gx = gyro_x/131.0
	Gy = gyro_y/131.0
	Gz = gyro_z/131.0
	

	print ("Gx=%.2f" %Gx, u'\u00b0'+ "/s", "\tGy=%.2f" %Gy, u'\u00b0'+ "/s", "\tGz=%.2f" %Gz, u'\u00b0'+ "/s", "\tAx=%.2f g" %Ax, "\tAy=%.2f g" %Ay, "\tAz=%.2f g" %Az) 	
	sleep(1)  # 1초당 자이로센서 값 받아들임.

파일을 실행시키게 되면,

아래와 같이 터미널에 자이로센서 값이 출력이 된다.

 

자이로 값이 출력 됨.

☞ 출력값 의미

  • Gx =도 / 초 단위의 자이로 X 축 데이터
  • Gy =도 / 초 단위의 자이로 Y 축 데이터
  • Gz =도 / 초 단위의 자이로 Z 축 데이터
  • Ax = 가속도계 X 축 데이터 (g)
  • Ay = 가속도계 Y 축 데이터 (g)
  • Az = 가속도계 Z 축 데이터 (g) 

 

<본판으로 들어와서 자이로 센서 값 MQTT를 이용해 전송을 해보자.>

-> 프린트로 사용한 부분을 단순히 변수로 받아주기만 하면 되는것이다.

1. Publisher Code 

import smbus		               #import SMBus module of I2C
from time import sleep          
import paho.mqtt.client as mqtt



#some MPU6050 Registers and their Address
PWR_MGMT_1   = 0x6B
SMPLRT_DIV   = 0x19
CONFIG       = 0x1A
GYRO_CONFIG  = 0x1B
INT_ENABLE   = 0x38
ACCEL_XOUT_H = 0x3B
ACCEL_YOUT_H = 0x3D
ACCEL_ZOUT_H = 0x3F
GYRO_XOUT_H  = 0x43
GYRO_YOUT_H  = 0x45
GYRO_ZOUT_H  = 0x47


def MPU_Init():
	#write to sample rate register
	bus.write_byte_data(Device_Address, SMPLRT_DIV, 7)
	
	#Write to power management register
	bus.write_byte_data(Device_Address, PWR_MGMT_1, 1)
	
	#Write to Configuration register
	bus.write_byte_data(Device_Address, CONFIG, 0)
	
	#Write to Gyro configuration register
	bus.write_byte_data(Device_Address, GYRO_CONFIG, 24)
	
	#Write to interrupt enable register
	bus.write_byte_data(Device_Address, INT_ENABLE, 1)

def read_raw_data(addr):
	#Accelero and Gyro value are 16-bit
        high = bus.read_byte_data(Device_Address, addr)
        low = bus.read_byte_data(Device_Address, addr+1)
    
        #concatenate higher and lower value
        value = ((high << 8) | low)
        
        #to get signed value from mpu6050
        if(value > 32768):
                value = value - 65536
        return value


bus = smbus.SMBus(1) 	# or bus = smbus.SMBus(0) for older version boards
Device_Address = 0x68   # MPU6050 device address

MPU_Init()

print (" Reading Data of Gyroscope and Accelerometer")




def on_connect(client, userdata, flags, rc):
    if rc == 0:
        print("connected OK")
    else:
        print("Bad connection Returned code=", rc)


def on_disconnect(client, userdata, flags, rc=0):
    print(str(rc))


def on_publish(client, userdata, mid):
    print("In on_pub callback mid= ", mid)


client = mqtt.Client()

client.on_connect = on_connect
client.on_disconnect = on_disconnect
client.on_publish = on_publish
   
client.connect('111.111.111.119', 20518)   # 접속하고 싶은 ip와 port번호 입력


while True:
    	
	#Read Accelerometer raw value
	acc_x = read_raw_data(ACCEL_XOUT_H)
	acc_y = read_raw_data(ACCEL_YOUT_H)
	acc_z = read_raw_data(ACCEL_ZOUT_H)
	
	#Read Gyroscope raw value
	gyro_x = read_raw_data(GYRO_XOUT_H)
	gyro_y = read_raw_data(GYRO_YOUT_H)
	gyro_z = read_raw_data(GYRO_ZOUT_H)
    

	#Full scale range +/- 250 degree/C as per sensitivity scale factor
	Ax = acc_x/16384.0
	Ay = acc_y/16384.0
	Az = acc_z/16384.0
	
	Gx = gyro_x/131.0
	Gy = gyro_y/131.0
	Gz = gyro_z/131.0
	data="%.2f " %Gx + "%.2f " %Gy + "%.2f " %Gz +"%.2f " %Ax + "%.2f " %Ay + "%.2f" %Az
	
	client.publish('gyro', data,0)
	
	
	sleep(0.2)  # 0.2 초당 data가 전송됨.
 
client.disconnect()

참고)   1. 잘보면 data 변수 받는곳에 공백(space)이 있는데 이것은 내가 subscribe코드에서 공백을 기준으로 DB에 담기

               때문이다. 

            2. 자이로 센서값을 굳이 확실하게 다 받을 필요가 없어 QOS level 0으로 설정함.

 

2. Subscriber Code

  (이 코드에는 DB사용 부분이 없습니다)

별거없다. 그냥 pub와 동일한 '토픽명', 'QOS level'만 설정해주면 된다.

import paho.mqtt.client as mqtt

def on_connect(client, userdata, flags, rc):
    if rc == 0:
        print("connected OK")
    else:
        print("Bad connection Returned code=", rc)

def on_disconnect(client, userdata, flags, rc=0):
    print(str(rc))

def on_subscribe(client, userdata, mid, granted_qos):
    print("subscribed: " + str(mid) + " " + str(granted_qos))

def on_message(client, userdata, msg):
    print(str(msg.payload.decode("utf-8")))



# 새로운 클라이언트 생성
client = mqtt.Client()

# 콜백 함수 설정 on_connect(브로커에 접속), on_disconnect(브로커에 접속중료), on_subscribe(topic 구독),
# on_message(발행된 메세지가 들어왔을 때)
client.on_connect = on_connect
client.on_disconnect = on_disconnect
client.on_subscribe = on_subscribe
client.on_message = on_message

# address : localhost, port: 20518 에 연결
client.connect('localhost', 20518)

client.subscribe('gyro', 0)
    
#print(data)
client.loop_forever()

3. 결과창 

라즈베리파이Publisher 터미널( ip: xxx.xxx.0.6)
서버 Subscriber 터미널 ip: xxx.xxx.xxx.119

----------------  ---------------- ----------------  ---------------- ----------------  ---------------- ----------------  ---------------- ----------------  ---------------- ----------------  ---------------- ----------------  ---------------- ----------------  ---------------- ----------------  ---------------- ----------------  ---------------- ----------------  ---------------- ----------------  ---------------- ----------------  ---------------- ----------------  ----------------

아래서 부터는 DB에 저장하는 Subscriber 코드이다. (PostgreSQL 사용)

<DB저장 하는 방법.>

1. Publisher Code는 위와 동일함.

2. DB저장 Subscriber code

import paho.mqtt.client as mqtt
import psycopg2 as db            # DB용 모듈
from datetime import datetime     # 시간 함수
import time



def on_connect(client, userdata, flags, rc):
    if rc == 0:
        print("connected OK")
    else:
        print("Bad connection Returned code=", rc)

def on_disconnect(client, userdata, flags, rc=0):
    print(str(rc))

def on_subscribe(client, userdata, mid, granted_qos):
    print("subscribed: " + str(mid) + " " + str(granted_qos))
    

def on_message(client, userdata, msg):
    print(str(msg.payload.decode("utf-8")))

    ##index명으로  시간으로 받기 위해 시간을 만들어주는 부분
    now = datetime.now()   
    timestr = time.strftime("%m%d-%H%M%S")     # 초까지 나옴
    timestr_2=timestr + str(now.microsecond)   # 마이크로 초까지 출력하기위함. (초당5개 받음으로)

    ## DB에 데이터 전송(postgreSQL 대문자 사용 X)
    # gyro_value 라는 테이블 / column_name = time(index),gx,gy,gz,ax,ay,az
    query2 = "insert into gyro_value (time,gx,gy,gz,ax,ay,az)  values(%s,%s,%s,%s,%s,%s,%s)"  
    value=str(msg.payload.decode("utf-8")).split(" ")  # split함수 쓰면 list로 변형됨.
    data=(timestr_2,value[0],value[1],value[2],value[3],value[4],value[5])
    cur.execute(query2,data)
    conn.commit()


conn_string="dbname='get_gyro_data' host='localhost' user='kick' password='a1234!'"  # DB 설정시 했던 값.
conn=db.connect(conn_string)
cur=conn.cursor()




# 새로운 클라이언트 생성
client = mqtt.Client()

# 콜백 함수 설정 on_connect(브로커에 접속), on_disconnect(브로커에 접속중료), on_subscribe(topic 구독),
# on_message(발행된 메세지가 들어왔을 때)
client.on_connect = on_connect
client.on_disconnect = on_disconnect
client.on_subscribe = on_subscribe
client.on_message = on_message

# address : localhost, port: 20518 에 연결
client.connect('localhost', 20518)

# gyro topic 으로 메세지 발행
client.subscribe('gyro',0)  


client.loop_forever()

<코드설명>

기본적인 MQTT코드부분은 생략을 하겠다.

def on_message(client, userdata, msg):부분 부터 설명.
 

query2 라는 부분은 위의 주석을 보면 코드를 이해할수 있을거고 (그냥 저렇게 쓰는것 같더라....)

value = ~ 부분은 우리가 아까 publisher 코드에서 공백(space)를 기준으로 데이터를 받았음으로 split(" ")을 함으로

              받았던 6개의 값들이 공백을 기준으로 리스트를 생성하게 된다. 

data= 시간,gx,gy,gz,ax,ay,az 을 담게되고 

cur.excute 를 함으로 DB에 전송을 하게 된다.

conn_string 은 본인들이 DB설정했던 값들을 그대로 해주면 된다.

 

3 결과창.

서버측에서 받은 값들이 출력이 됨과 동시에 

서버측(subsciber) 터미널창 ip:xxx.xxx.xxx.119

아래와 같이 DB테이블에 저장이 됨을 확인할 수 있다. 

DB에 저장된 상태.

(아마 터미널창에 있는 위에 3개의 행들은 내가 DB 에서 삭제해서 없는듯...)

Comments