산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

라즈베리 파이 2 + 윈도우 10 IoT Core에서 블루투스 시리얼 통신 구현하기

부품 및 소모품

라즈베리 파이 2 + 윈도우 10 IoT Core에서 블루투스 시리얼 통신 구현하기 라즈베리 파이 2 모델 B × 1
범용 블루투스 USB 동글 × 1
라즈베리 파이 2 + 윈도우 10 IoT Core에서 블루투스 시리얼 통신 구현하기 아두이노 우노 × 1
라즈베리 파이 2 + 윈도우 10 IoT Core에서 블루투스 시리얼 통신 구현하기 SparkFun 블루투스 모뎀 - BlueSMiRF Silver × 1

앱 및 온라인 서비스

라즈베리 파이 2 + 윈도우 10 IoT Core에서 블루투스 시리얼 통신 구현하기 Microsoft Windows 10 IoT Core
라즈베리 파이 2 + 윈도우 10 IoT Core에서 블루투스 시리얼 통신 구현하기 Microsoft Visual Studio 2015

프로젝트 소개

자세한 내용

이 프로젝트는 embedded101.com의 "Win 10 IoT-Core: Bluetooth Universal Windows Serial App"에서 자세히 다룹니다.

개요

이 프로젝트는 라즈베리 파이 2 같은 IoT Core 장치를 범용 블루투스 USB 동글을 통해 임베디드 블루투스 장치와 블루투스 시리얼 프로파일(SPP)로 연결하는 유니버설 윈도우 앱(UWP)입니다.

배경

블루투스는 근거리 피어투피어 네트워킹을 지원합니다. 와이파이와 달리 1:1 연결이며, 두 장치가 연결되어 데이터를 주고받습니다. 대칭적 연결(시리얼 프로파일로 원시 데이터 교환)도 가능하지만, 보통 비대칭적입니다(한쪽이 특정 데이터 포맷을 생성해 다른 쪽이 소비). 예: 휴대폰이 A2DP 프로파일로 오디오를 헤드셋(HSP 프로파일)로 스트리밍. OBEX(Object Exchange)는 양쪽이 데이터를 교환하는 대칭 연결입니다.

마이크로소프트 IoT Core 블루투스 샘플은 GATT(Generic Attribute Profile)를 사용해 블루투스 저에너지(BLE) 프로토콜의 프로파일 검색·기술 서비스를 제공합니다. 저전력 심플 기기가 데이터를 생성하면 복잡한 프로세서가 소비하는 구조죠.

이 프로젝트는 훨씬 단순합니다. 오직 SPP(Serial Port Profile)만 다루며, RFCOMM 프로파일 기반입니다. 아주 오래된 USB 블루투스 동글로 개발되어 어떤 동글이든 작동할 것입니다.

IoT 앱

간단한 블루투스 시리얼 UWP(윈도우 10) 테스트 앱입니다. 앱 실행 시 장치와 페어링된 모든 블루투스 장치를 리스트로 열거합니다. 하나를 더블클릭하면 연결을 시도합니다. 텍스트박스에 보낼 텍스트를 입력하고 버튼을 누르면 전송. 수신된 텍스트는 자동으로 수신란에 표시됩니다. 따라서 상대측(아두이노)이 받은 문자를 그대로 에코백하면 보낸 텍스트가 수신란에 다시 나타납니다.

라즈베리 파이 2 + 윈도우 10 IoT Core에서 블루투스 시리얼 통신 구현하기

엔드포인트(아두이노 측)

테스트용으로 블루투스 어댑터를 장착한 아두이노 우노를 사용합니다. 블루투스 연결로 수신한 문자를 그대로 에코백하는 간단한 실드 코드입니다.

실드 설정(Setup):

// 시리얼 루프백 앱
// 설정 단계
// 연결된 시스템에 의해 시작됨
// 블루투스에서 사용할 수 있음: BT 장치의 RxTx를 아두이노 TxRx에 연결
// 프로그래밍 전에는 BT 어댑터를 분리해야 함
void setup() {
  // 내 어댑터 보드레이트 115200
  // 아두이노-BT 어댑터 포트 속도
  // BT 어댑터가 커맨드 모드일 때 설정
  // 이건 BT 무선 속도가 아님(설정 불가)
  Serial.begin(115200);
  delay(333);
  while (!Serial) ;
  delay(1000);
  Serial.println("The quick brown fox jumps over the lazy dog!");
}

실드 루프(Loop):

void loop() {
  char ch = Serial.read();
  while (255 == (byte)ch) {
    ch = Serial.read();
  }
  Serial.print(ch);
}

페어링

블루투스는 P2P이므로 연결 전 페어링이 필수입니다. 앱 내에서 하지 않습니다. 패스키 페어링은 임베디드 기기 간에 까다로울 수 있습니다(헤드리스, 팝업 미지원 등). IoT Core 웹 포털이나 SSH 쉘에서 실행하는 명령줄 유틸리티로 페어링합니다. 최신 OS 웹 포털은 패스키 페어링을 지원합니다(윈도우 10 RTM 당시엔 없었음). 자세한 내용은 위 링크의 글 참조.

프로젝트 시작

Visual Studio 2015에서 유니버설 윈도우 앱 템플릿으로 프로젝트 생성:

New Project → Visual C# → Windows → Blank App (Universal Windows)

앱 UI 만들기 (XAML)

위 레이아웃과 비슷하게 UI 구성:

ConnectDevices는 ListBox로, ItemsSource를 PairedDevices(나중에 설명)에 바인딩, ItemTemplate로 TextBlock을 PairedDeviceInfo의 Name 속성에 바인딩. 더블탭 이벤트(ConnectDevices_DoubleTapped)로 연결 시작.

<ListBox x:Name="ConnectDevices" ItemsSource="{Binding Source={StaticResource PairedDevices}}" Margin="10" DoubleTapped="ConnectDevices_DoubleTapped" Width="Auto" Height="Auto">
  <ListBox.ItemTemplate>
    <DataTemplate>
      <TextBlock Text="{Binding Name}" />
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

앱 구성 (Package.appxmanifest)

Capabilities 섹션을 아래와 같이 수정:

<Capabilities>
  <Capability Name="internetClient" />
  <DeviceCapability Name="bluetooth.rfcomm">
    <Device Id="any">
      <Function Type="name:serialPort"/>
    </Device>
  </DeviceCapability>
</Capabilities>

internetClient는 기본 포함. 이 앱엔 불필요하니 지워도 되지만 남겨둠.

페어링된 장치 정보

앱 시작 시 페어링된 장치 열거:

DeviceInformationCollection DeviceInfoCollection
  = await DeviceInformation.FindAllAsync(RfcommDeviceService.GetDeviceSelector(RfcommServiceId.SerialPort));

이 컬렉션을 ObservableCollection으로 변환해 ListBox 바인딩용으로 사용:

_pairedDevices = new ObservableCollection<PairedDeviceInfo>();

DeviceInfoCollection을 순회하며 각 항목으로 PairedDeviceInfo 객체 생성 후 _pairedDevices에 추가.

PairedDeviceInfo 클래스 속성:

적절한 생성자 포함. DeviceInformation은 Windows.Devices.Enumeration.DeviceInformation.

리스트박스에는 Name 필드 표시. 장치 선택(더블클릭) 시 해당 항목의 DeviceInformation이 연결에 사용됨.

연결

DeviceInformation으로 RFCOMM 서비스 얻고, StreamSocket으로 엔드포인트 호스트명(실제는 블루투스 MAC 주소)과 서비스명으로 연결:

_service = await RfcommDeviceService.FromIdAsync(DeviceInfo.Id);
_socket = new StreamSocket();
await _socket.ConnectAsync(_service.ConnectionHostName, _service.ConnectionServiceName);

성공 시 소켓이 의미 있는 값(널 아님). 당연히 try-catch로 예외 처리.

송수신은 소켓의 InputStream, OutputStream 속성 활용.

텍스트 수신

수신은 비결정적이므로 별도 스레드에서 비동기로 루프 실행. 취소 토큰으로 중단 가능.

private async void Listen() {
  ReadCancellationTokenSource = new CancellationTokenSource();
  if (_socket.InputStream != null) {
    dataReaderObject = new DataReader(_socket.InputStream);
    while (true) {
      await ReadAsync(ReadCancellationTokenSource.Token);
    }
  }
}
DataReader dataReaderObject;
private CancellationTokenSource ReadCancellationTokenSource;
private async Task ReadAsync(CancellationToken cancellationToken) {
  uint ReadBufferLength = 1024;
  cancellationToken.ThrowIfCancellationRequested();
  dataReaderObject.InputStreamOptions = InputStreamOptions.Partial;
  var loadAsyncTask = dataReaderObject.LoadAsync(ReadBufferLength).AsTask(cancellationToken);
  UInt32 bytesRead = await loadAsyncTask;
  if (bytesRead > 0) {
    string recvdtxt = dataReaderObject.ReadString(bytesRead);
  }
}

텍스트 송신

송신은 UI 액션에서 발생하므로 본질적으로 동기적(하지만 UI 블로킹 방지 위해 await 사용).

private async void Send(string msg) {
  Task storeAsyncTask;
  DataWriter dataWriteObject = new DataWriter(_socket.OutputStream);
  dataWriteObject.WriteString(msg);
  storeAsyncTask = dataWriteObject.StoreAsync().AsTask();
  UInt32 bytesWritten = await storeAsyncTask;
}

버튼 상태 관리

앱 상태에 따라 명령 버튼 활성화/비활성화. 예: 미연결 시 Send/Start Recv 비활성화, 연결 시 활성화 등.

즐기세요! :)

코드

iotbluetoothserial on Github

Codeplex 미러: https://iotgenbluetoothserialuwa.codeplex.com/
Github: https://github.com/djaus2/iotbluetoothserial

제조공정

  1. 고피고(GoPiGo) v2 윈도우 10 IoT 코어 라즈베리파이 3 확장 프로젝트
  2. 아두이노 메가에서 푸시 버튼으로 PWM을 이용해 LED 밝기 제어하기
  3. 아날로그 센서로 정밀 압력 및 공기유속 측정 장치 만들기
  4. 아두이노 나노와 MPU-6050으로 실시간 자이로스코프 게임 만들기
  5. ESP32-CAM과 PIR 센서로 디스코드(Discord) 알림 보안 카메라 만들기
  6. DHT11 온습도 센서 + LED 표시등 + 피에조 부저 프로젝트
  7. Unopad: 아두이노 우노로 만드는 에이블턴 라이브용 MIDI 컨트롤러
  8. 커스텀 아두이노 TV 리모컨: 배터리 구동, 3D 프린트 케이스
  9. 아두이노 블루투스로 LED 제어하기 - HC-05 & MIT App Inventor 입문 가이드
  10. 아두이노로 간단한 장애물 센서 만들기 - IR LED & 포토다이오드 튜토리얼