티스토리 뷰

IoT가 부각되면서 mqtt를 이용하는 센서/어플리케이션이 늘어나고 있다.


mqtt는 TCP/IP를 기반으로 하고 있는 프로토콜로  설정 및 사용이 정말 간단하다.


TCP/IP 통신을 짤 때마다 프로토콜 설계가 꽤나 귀찮았는데 mqtt를 사용하면 굉장히 편해진다.



0912embmqtt01

사실 1:1 통신이라면 프로토콜 설계 없이 그냥 TCP/IP를 써서 메세지를 주고 받아도 잘 될 것이다.


mqtt는 기본적으로 N:N 통신을 할 때 유용한 프로토콜이다. (예를 들면 다양한 센서로부터 값을 수신하여 업로드해야 할때)


더불어 Topic이라는게 존재하여 내가 원하지 않는 데이터는 필터링 할 수 있다.


위 그림에서 알 수 있듯이  mqtt는 기본적으로 서버(브로커)와 publisher, subscriber가 필요하다.


서버는 내가 만들어 사용해도 되고 mqtt측 공용 서버를 사용해도된다. (서버 구축이 용이하므로 만드는걸 추천)


publisher는 데이터를 송신하는 쪽으로 토픽을 정해서 데이터를 publish할 수 있다.


subscriber는 데이터를 수신하는 쪽으로 원하는 토픽을 지정하면 해당 토픽으로  publish된 data가 날아온다.


여기서는 ubuntu/raspberry 에서의 설정법만 다루겠다.(윈도우도 마찬가지로 쉽게 설정 및 사용가능하다.)


인터넷마다 다른데 나의 경우에는 apt-get으로 쉽게 설치 가능했다.


sudo apt-get install mosquitto


sudo apt-get install mosquitto-clients


위 명령어를 실행하면 설치 끝! 나의 경우엔 별도의 설정도 필요 없었다.





#include 
struct mosquitto *mosq=NULL;
void mq_init()
{
		mosquitto_lib_init();
	
	mosq=mosquitto_new(NULL,true,NULL);
	mosquitto_message_callback_set(mosq,message_callback);
	if(mosquitto_connect(mosq,"192.168.0.248",1883,60))
	{
			printf("mqtt connect error\r\n");;
	}
	mosquitto_subscribe(mosq,NULL,"pidrone/CMD/#",0);
}

void mq_start()
{
					int rc=mosquitto_loop_start(mosq);
				while(rc)
				{
					printf("connection error!\r\n");
					usleep(20000);
					mosquitto_reconnect(mosq);
				}
}

int mq_send(const char *topic,const char *msg)
{
	return mosquitto_publish(mosq,NULL,topic,strlen(msg),msg,0,0);
}

void mq_close()
{
	mosquitto_destroy(mosq);
	mosquitto_lib_cleanup();
}


각 함수를 자세히 보면 mq_init에서는 mosquitto 변수를 생성하고 메세지가 들어올경우 실행할 함수를 설정한다.


저의 경우는 같은 네트워크 안에 서버를 만들었기때문에 서버의 ip를 적었지만 서버 도메인이 있을경우 도메인을 적으셔도 됩니다.(기본포트 1883)


subscribe함수는 수신할 메세지의 토픽을 정하는데 '/'을 이용해 하위 토픽을 구분할 수 있고


'#'를 이용해 하위토픽 전체를 선택할 수 있다.  저의 경우엔 cmd의 하위 토픽을 다 선택한거죠.


mq_start를 통해 통신이 시작되며 연결이 끊겼을시 재연결을 요청할 수 있다.


mq_send는 mosquitto_publish함수를 축약한 것으로 topic과 msg만 넣으면 데이터를 송신해준다.


mq_close는  통신 종료를 위한 함수이다.




char *mqbuf=(char *)malloc(70*sizeof(char));
void message_callback(struct mosquitto *mosq,void *obj,const struct mosquitto_message *message)
{
	bool match =0;
	char *msg;
	char *s1;
	char *s2;
	int getid;
	float getvalue;
	
	mosquitto_topic_matches_sub("pidrone/CMD/PI",message->topic,&match);
	if (match)
	{
		msg=(char *)message->payload;
		//printf("got message '%.*s' for topic '%s'\r\n",message->payloadlen,(char*) message->payload,message->topic);
		printf("pi command= %i\r\n",atoi(msg));		
	}
	
		mosquitto_topic_matches_sub("pidrone/CMD/DC",message->topic,&match);
	if (match)
	{
		msg=(char *)message->payload;
		s1=strtok(msg,",");
		s2=strtok(NULL,"\r");
		getid=atoi(s1);
		getvalue=atof(s2);
		if(getid==dc.id)
		{
			dc.setvalue=getvalue;
			printf("dc %i command=%.1f\r\n",dc.id,dc.setvalue);	
		}
	}
	
	
}

mq_start에서 사용한것처럼 메세지가 오면 실행되는 함수 이다. 본인이 발행한 메세지 크기에 맞게 버퍼를 만들어준다.

mosquitto_topic_matches_sub함수를 사용하면 도착한 메세지가 우리가 원하는 토픽과 일치하는지 알려준다.

위 함수처럼 토픽을 세분화해 명령을 구분해주면 좋다. 메세지는 기본적으로 message라는 포인터에 담겨있고

message->payload를 가져오면 된다. 명령어는 알아서 원하는대로 처리하면된다.

위 코드는 라즈베리 쪽 코드이지만 그대로 가져다가 우분투에서 써도 된다.

우분투는 mosquitto/mosquitto-clients패키지를 설치하면 서버가 실행되므로 따로 실행할 필요 없다.(윈도우는 따로 실행해야함)

단순히 데이터를 들어오는지 확인하고 간단한 명령을 줄때엔 별도로 코드를 짤 필요 없다.

mosquitto_sub -h 192.168.0.248 -t pidrone/# -v

192.168.0.248에 해당하는 서버를 이용하여 pidrone 토픽 및 하위 토픽으로 들어오는 모든 메세지를 수신하는 명령어이다.

라즈베리 쪽에서 위 코드들을 이용해 데이터를 보내면 다음과 같은 메세지가 출력된다.

pidrone/SONAR 3,178,0
pidrone/GPS 36.373972,127.362697,-1.800000,0
pidrone/IMU : roll:179.210544, pitch:0.142148, yaw:28.499893,0
pidrone/PI measured time is 3384s.

좌측에는 토픽이 표시되고 메세지 내용이 출력된다.

mosquitto_pub -h 192.168.0.248 -t pidrone/CMD/BL -m "8,0\r"

위 명령어는 위와 같은 서버에 pidrone/CMD/BL 토픽으로 "8,0"이라는 메세지를 publish한다.

따라서 간단한 모터제어 쯤은 따로 코드를 짜지 않고도 가능하다.



mqtt는 어떤 플랫폼에서든 간단히 설치하고 쓸 수 있으니 관심 있는 사람들은 한번쯤 테스트해보길 추천한다.






댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함