본문 바로가기

토이 프로젝트

Arduino 보드와 PC(C# 사용)간에 UDP 통신을 사용하여 메시지 주고 받기

1. 개념

https://powerdeng.tistory.com/227

 

TCP와 UDP

TCP와 UDP의 차이 TCP는 접속을 하고 서로 통신하지만 UDP는 접속하지 않고 통신한다. 사물 인터넷(IoT)에서 TCP와 UDP의 차이 1. TCP 사물 인터넷(IoT)에서는 기본적으로 사물(보드)이 많다는 가정이 있다

powerdeng.tistory.com

 

2. 개요

Wi-Fi 공유기에 IoT 보드와 PC( C#으로 UDP 서버 역할)가 연결되면 같은 공유기에 연결된 것들끼리는 UDP 통신이 가능하다. 따라서 이를 이용하여 보드에서 PC로 "나는 ESP8266보드이다!!"라고 메시지를 보내고, PC에서 보드로는 "나는 C# UDP 클라이언트이다!"라고 메시지를 보내는 프로젝트를 진행하려고 한다.

<참고 자료>

보드 정보: WeMos D1 R1

https://www.devicemart.co.kr/goods/view?no=1312096

 

아두이노 우노 IoT 보드 WeMos D1 R1 [SZH-EK080]

WeMos D1 R1 보드는 와이파이(ESP-8266EX)가 내장된 Arduino Uno 호환 보드입니다.

www.devicemart.co.kr

 

3. 진행 과정

1번. IoT보드가 UDP 통신이 가능한 클라이언트로 만든다.

2번. C#으로 서버 역할을 할 UDP 클라이언트를 만든다.

3번. 1번과 2번이 서로 연결되는지 확인한다.

 

4. IoT보드가 UDP 통신이 가능한 클라이언트 만들기

1) 개발 환경 설정

① Arduino IDE 다운로드

아래의 링크에서 Arduino IDE를 다운로드한다(여기서는 2.3.2 버전을 사용하였다.)

https://www.arduino.cc/en/software

 

Software

Open-source electronic prototyping platform enabling users to create interactive electronic objects.

www.arduino.cc

 

② 보드매니저 URL 추가

Arduino IDE 상단 File 탭에서 Preferences을 선택하면 아래의 그림1이 나온다.

그림1

그림1에 표시된 것처럼 추가적인 보드매니저 URL에 아래의 링크를 추가한다.

https://arduino.esp8266.com/stable/package_esp8266com_index.json

 

③ 보드 설치

아래 그림2에 표시된 부분을 눌러서 보드 매니저에 들어간 뒤, ESP8266을 검색하여 해당 보드를 설치한다.

여기서는 3.1.2 버전을 사용하였다.

그림2

 

④ 보드 및 포트 설정

WeMos 보드를 컴퓨터에 연결한 뒤 아래 그림3에 표시된 부분을 눌러서 Select other board and port를 누른다.

그림3

 

아래 그림4처럼 WeMos 보드를 검색하여 LOLIN(WeMos) D1 R1와 연결된 포트를 선택하고 OK를 누른다.

그림4

 

⑤ 보드 정상 작동 확인

아래 그림5처럼 상단 File 탭에서 Examples -> ESP8266 -> Blink를 선택한다.

그림5

 

아래 그림6에 표시된 부분을 눌러서 Blink 예제를 보드에 Upload한다.

그림6

 

정상적으로 Upload가 되면 아래 동영상처럼 Wi-Fi 칩부분의 LED가 깜빡거린다. 

 

2) 코드 작성

여기서 작성한 코드는 아래 경로의 UDP 코드를 기본으로 작성했다.

File -> Examples -> ESP8266WiFi -> Udp

 

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>

// 사물인터넷보드가 와이파이 공유기와 연결하기 위한 ID, PW를 입력해야 한다.
#ifndef STASSID
#define STASSID "미래기술"
#define STAPSK "hynux17830"
#endif

// IoT보드에서 사용할 포트번호
unsigned int localPort = 60000;  // local port to listen on

// 송수신 데이터의 버퍼를 생성한다.
char packetBuffer[UDP_TX_PACKET_MAX_SIZE + 1];      // buffer to hold incoming packet,
char ReplyBuffer[] = "나는 ESP8266보드이다!!\r\n";  // a string to send back

// UDP 통신을 위한 클래스
WiFiUDP Udp;

unsigned long t = 0;

void setup() {
  // 와이파이 공유기와 접속하기 위한 절차가 진행된다.
  Serial.begin(9600);
  WiFi.mode(WIFI_STA);
  WiFi.begin(STASSID, STAPSK);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(500);
  }
  Serial.print("Connected! IP address: ");
  Serial.println(WiFi.localIP());
  Serial.printf("UDP server on port %d\n", localPort);

  // 상단에 지정된 포트를 UDP 통신에 개구멍으로 쓴다.
  Udp.begin(localPort);
}

void loop() {
  // 수신된 데이터의 길이를 받는다.
  int packetSize = Udp.parsePacket();
  if (packetSize) {
    //Serial.printf("Received packet of size %d from %s:%d\n    (to %s:%d, free heap = %d B)\n", packetSize, Udp.remoteIP().toString().c_str(), Udp.remotePort(), Udp.destinationIP().toString().c_str(), Udp.localPort(), ESP.getFreeHeap());

    // UDP 통신으로 데이터를 수신한다.
    int n = Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
    packetBuffer[n] = 0;
    // 받아온 데이터를 출력한다.
    Serial.println(packetBuffer);
  }

  // 1초에 한 번마다 UDP 통신으로 C# UDP 클라이언트에 메시지를 전송한다.
  if (millis() - t > 1000) {
    t = millis();
    // UDP 전송데이터의 시작(목적지의 주소가 필요하다)
    Udp.beginPacket("192.168.2.197", 60001);
    Udp.write(ReplyBuffer);
    // UDP 전송데이터의 끝
    Udp.endPacket();
  }
}

/*
  test (shell/netcat):
  --------------------
    nc -u 192.168.esp.address 8888
*/

 

5. C#으로 서버 역할을 할 UDP 클라이언트 만들기

1) 개발 환경 설정

① Visual Studio Community 설치

여기서는 2022 버전을 사용하였다.

 

② .NET 데스크톱 개발 설치

아래 그림7에 표시된 것 같이 .NET 데스크톱 개발을 체크한 뒤 설치한다.

그림7

 

③ 프로젝트 생성

새 프로젝트 만들기를 누르면 아래 그림8의 화면이 나온다. 

이때 그림8에 표시된 것 처럼 Windows Forms 앱(.NET Framework)를 선택하여 프로젝트를 생성한다.

그림8

 

2) 코드 작성

여기서 작성한 코드는 아래 경로의 예시를 기본으로 작성했다.

https://learn.microsoft.com/ko-kr/dotnet/api/system.net.sockets.udpclient?view=net-5.0

 

UdpClient 클래스 (System.Net.Sockets)

UDP(User Datagram Protocol) 네트워크 서비스를 제공합니다.

learn.microsoft.com

 

<UI>

 

<코드>

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace UDP_IoT_WinForm
{
    public partial class Form1 : Form
    {
        UdpClient udpClient = new UdpClient(60001);
        Thread t;

        bool is_udp_run = false;

        public Form1()
        {
            InitializeComponent();
        }

        void powerdeng_udp()
        {
            try
            {
                Byte[] sendBytes = Encoding.UTF8.GetBytes("나는 C# UDP 클라이언트이다!");

                //udp로 연결될 대상이 있는데 그 대상이 누구든지 그냥 받아 들이겠다.
                IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);

                DateTime dt = DateTime.Now;
                while(is_udp_run)
                {
                    if((DateTime.Now - dt).TotalSeconds > 1)
                    {
                        dt = DateTime.Now;

                        // 1초마다 한번씩 전송한다.
                        udpClient.Connect("192.168.2.195", 60000);
                        udpClient.Send(sendBytes, sendBytes.Length);
                    }
                    

                    // Blocks until a message returns on this socket from a remote host.
                    Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
                    string returnData = Encoding.UTF8.GetString(receiveBytes);
                    /*
                    // Uses the IPEndPoint object to determine which of these two hosts responded.
                    Console.WriteLine("This is the message you received " +
                                                 returnData.ToString());
                    Console.WriteLine("This message was sent from " +
                                                RemoteIpEndPoint.Address.ToString() +
                                                " on their port number " +
                                                RemoteIpEndPoint.Port.ToString());
                    */
                    richTextBox1.Text += returnData + "@" + RemoteIpEndPoint.Address.ToString() + ":" + RemoteIpEndPoint.Port.ToString() +"\n";



                }
                //udpClient.Close();

            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            is_udp_run = true;
            t = new Thread(new ThreadStart(powerdeng_udp));
            t.Start();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            is_udp_run = false;
            if(t != null && t.IsAlive)  t.Abort();
        }
    }
}

 

6. IoT 보드와 PC연결 확인 및 최종 테스트

PC에서는 IoT보드의 메시지가, IoT보드에서는 PC의 메시지가 출력되는 것을 확인할 수 있다.


<참고 자료>

아두이노 IDE 환경설정

https://rockjjy.tistory.com/2453

 

Arduino Uno 호환 WeMos D1 Wifi Board 사용법 알아보기

Arduino Uno 호환 WeMos D1 Wifi Board 의 초기 세팅법과 사용방법에 대해서 알아보고 간단한 웹서버 테스트를 해보도록 하겠습니다 WeMos D1 Wifi Board 는 ESP8266(ESP-12E) 기반의 아두이노 우노와 호환 가능한 W

rockjjy.tistory.com

 

프로젝트 전체적인 과정

https://www.youtube.com/watch?v=mHTFR4CnHxA