T 스킨 용 Ble-wifi Range Extender 생성 방법
소개
여보세요! 이 프로젝트는 T-Skin (Tactigon Skin)의 통신 기능 확장을 설명하기 위해 설계되었습니다. 우리는 블루투스 저에너지가 제공하는 것보다 더 먼 거리에서 사용할 수 있기를 원합니다. UDP 프로토콜을 사용하는 Raspberry Pi Zero W를 사용하여 WiFi를 통해 T-Skin에서 개인용 컴퓨터로 데이터를 전송할 계획입니다. BLE 모듈이있는 NodeMCU를 사용하여 Tactigon Skin에 WiFi를 사용하여 전송할 수있는 용량을 제공했습니다.
하드웨어 아키텍처
우리는이 프로젝트에서 많은 하드웨어를 사용하므로 사진이 마음에 들지 않는 데 도움이 될 것이라고 생각했습니다.
Tactigon Skin은 기본적으로 WiFi 통신을 지원하지 않습니다. BLE 모듈이있는 NodeMCU를 사용하여 데이터를 RPi (Raspberry Pi)로 전송함으로써 이러한 제한을 극복했습니다. 우리는 Raspberry가 호스팅하는 개인 네트워크를 사용합니다. 따라서 RPi가 네트워크 액세스 포인트로 사용되므로 공용 네트워크에 액세스 할 필요가 없습니다.
RPi를 액세스 포인트로 구성하는 방법을 배우려면 다음 링크를 따르십시오. Configure Access Point Mode
소프트웨어 아키텍처
프로젝트 인프라가 정의되었으므로 구성 요소의 작동 방식을 살펴 보겠습니다.
BLE에서 UDP 로의 노드
BLE에서 UDP 로의 노드
T-Skin은 가속도계 및 자이로 스코프와 같은 센서에서 데이터를 수집합니다. 이 정보는 BLE를 통해 NodeMCU로 전송하기위한 패킷을 작성하는 데 사용됩니다.
T-Skin은 다음 코드를 사용하여 데이터를 수집합니다.
T_QUAT qMeter;
T_QData qData;
qData = qMeter.getQs();
roll = radToDegree(qData.roll - rollZero);
pitch = radToDegree(qData.pitch - pitchZero);
yaw = radToDegree(qData.yaw - yawZero);
먼저 qMeter 및 qData 변수가 정의됩니다. 이러한 객체는 T_QUAT 및 T_QData 클래스를 사용하여 작성됩니다. 이 변수는 자이로 스코프의 쿼터니언 데이터를 보유합니다. 읽은 데이터는 qMeter.getQs () 문으로 수행됩니다. 그런 다음 별도의 변수를 사용하여 롤, 피치 및 요 값을 저장합니다.
그런 다음 UDP 통신 프로토콜을 사용하여 데이터를 Raspberry Pi Zero W로 보냅니다.
WiFiUDP Udp;
unsigned int UDP_Port = 5000;
char* UDP_IP = "192.168.4.1";
char PacketBuffer[1024];
Udp.beginPacket(UDP_IP, UDP_Port);
Udp.write(PacketBuffer);
Udp.endPacket();
완전한 데이터 패킷이 수신되면 전송을위한 UDP 패킷을 작성하는 데 사용됩니다. 수신자의 포트 및 IP 주소를 정의한 후 데이터가 회선에 기록되고 패킷 전송 절차가 종료됩니다.
연결 실패시 가능한 빨리 재 연결을 시도하도록 NodeMCU를 구성했습니다.
UDP에서 VCOM으로
이 시나리오에서는 Raspberry Pi를 가제트 장치로 구성했습니다. 이를 통해 PC는 통신을 수행하기 위해 PC를 직렬 포트 장치로 식별 할 수 있습니다. Serial Gadget Mode Configuration 링크에서 같은 방식으로 장치를 구성하는 방법을 배울 수 있습니다.
지속적으로 실행되는 Python 스크립트는 UDP 패킷을 가져 와서 Raspberry Pi의 Virtual serial port로 보냅니다. 직렬 포트 모니터 프로그램을 실행하여 PC의 COM 포트를 조사하면 Tactigon Skin에서 수집 한 데이터 스트림을 볼 수 있습니다.
이 시스템의 실제 예는 다음과 같습니다.
결론
우리는 목표를 달성하고 훨씬 더 먼 거리에서 Tactigon Skin을 사용할 수 있었기 때문에이 프로젝트가 성공한 것으로 간주합니다. WiFi 전송을 사용하여 통신 범위를 3 ~ 4 미터에서 40 미터 이상으로 늘릴 수있었습니다. 큰 차이!
이 방법으로 통신을 구현할 때 두 가지 주요 제한 사항에 직면하게됩니다. 첫 번째는 2.4GHz 대역을 사용하는 다른 신호의 잠재적 인 간섭입니다. Raspberry Pi Zero W Wi-Fi 안테나의 최대 범위는 두 번째 제한 요소입니다. LoRa 및 SigFox와 같은 대체 LPWAN 프로토콜을 사용하여 발생할 수있는 신호 문제를 최소화 할 수 있습니다.
T-Skin의 거리 제한을 극복하면 장치의 기능 수준이 크게 향상 될 수 있습니다. 재해 후 수색 및 구조 임무에 사용하기 위해 원격으로 로봇 장치를 제어하거나 인명 피해를 입히지 않고 철거 팀을 지원하는 데 사용할 수 있습니다.
암호
RPi_Tactigon_Extender.py
이 코드는 부팅시 Raspberry Pi Zero W에서 자동으로 실행됩니다.
#!/usr/bin/env python
#UDP SERVER CODE
#To run this script at boot you have te add the following to the /etc/rc.local file in sudo mode
#sudo python /path_to_this_script/script_name.py
#before the exit 0 directive
import os
import sys
import socket
import serial
import time
UDP_PORT = 5000
UDP_IP = '192.168.4.1' #IP address of the machine to whick this script will run
#small delay to ensure that everithing started up
time.sleep(10)
port = serial.Serial("/dev/ttyGS0", baudrate=115200, timeout=0.1)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((UDP_IP, UDP_PORT))
while ((port.in_waiting) <= 0):
data, addr = sock.recvfrom(1024) #store received data
#print(data) #for debug
port.write(data + '\n') #write received data from UDP to the emulated serial port
#if the input buffer of the serial port is NOT empty that means that the shutdown command has been received from the PC
os.system("shutdown now -h")
BLEtoUDP.ino
이 코드는 NodeMCU에 플래시됩니다.
//SENDER
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
//UDP handle
WiFiUDP Udp;
unsigned int UDP_Port = 5000;
char* UDP_IP = "192.168.4.1"; //IP address of the RECEIVER
char PacketBuffer[1024]; //Buffer used for UDP data
//Wifi handle
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";
IPAddress ip(192, 168, 4, 2); //set a static IP for this device
IPAddress gateway(192, 168, 4, 1);
IPAddress subnet(255, 255, 255, 0);
bool flag = false; //to handle complete read of BLE data
int count = 0; //counter for checking correct length of received buffer from BLE, starts from 0 to 19
void setup() {
memset(&PacketBuffer, (char)0, 1024); //set all buffer to 0
pinMode(LED_BUILTIN, OUTPUT); //LOW = WiFi connected; HIGH = WiFi not connected
digitalWrite(LED_BUILTIN, HIGH);
Serial.begin(115200); //BLE serial
WiFi.config(ip, gateway, subnet);
WiFi.mode(WIFI_STA); //station mode
WiFi.begin(ssid, password);
Serial.println();
Serial.print("Wait for WiFi");
//wait for wireless connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
digitalWrite(LED_BUILTIN, LOW);
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: " + WiFi.localIP().toString());
Serial.println();
Udp.begin(UDP_Port); //initialize UDP
}
void loop() {
//if wireless connection drops, try to reconnect to it
while (WiFi.status() != WL_CONNECTED) {
digitalWrite(LED_BUILTIN, HIGH);
delay(500);
Serial.print(".");
}
digitalWrite(LED_BUILTIN, LOW);
if (Serial.available()) {
//read one char at the time and store it to che progressive 'count' position in the buffer array
Serial.read(&PacketBuffer[count], 1);
//checking for carriage return and line feed chars
//replace carriage return (if for any reasons is present) with whitespace to avoid complications in the buffer processing by the receiver
if (PacketBuffer[count] == '\r') PacketBuffer[count] = ' ';
else if (PacketBuffer[count] == '\n') {
//at this point the one buffer from BLE serial is completely processed
PacketBuffer[count] = (char)0;
count = 0; //reset counter
flag = true; //complete data
}
else {
//increment counter for next char read
count++;
}
}
if (flag) {
//start send data from [1] and not [0] due to how data is sent by the T-skin.
//the data in [0] is treated by a serial read as a terminator char (char)0.
//if this data ends up in the buffer that we send the calid data after that char will be ignored
//sending data from 2nd element is less time consuming that shifting all buffer
//Serial.println(&PacketBuffer[1]); //for debug
//here we send via UDP the data from BLE
Udp.beginPacket(UDP_IP, UDP_Port);
Udp.write(&PacketBuffer[1]);
Udp.endPacket();
flag = false; //reset flag for next buffer
memset(PacketBuffer, (char)0, 1024); //set all buffer to 0
}
}