2013-06-09 5 views
0

저는 Arduino (컴퓨터의 X360 컨트롤러 사용)를 통해 로봇을 무선으로 제어하려고합니다. 대기 시간이 매우 짧습니다. 나는 Wifi를 선택했기 때문에 (사실 비디오 스트리밍을 할 것입니다.) 약간의 테스트를 거친 후에 TCP를 사용하여 거대한 지연을 보았습니다. 이것은 정상적인가요 (54Mbits/s로, 그것은 안됩니다!)? 제어 가능하도록 어떻게 줄일 수 있습니까?Wi-Fi를 통한 간단한 TCP 통신이 너무 느립니다 (초 지연)?

서버 코드 (아두 이노 스케치) :

#include <SPI.h> 
#include <Ethernet.h> 

byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0x48, 0x0D }; 
byte ip[] = { 192, 168, 0, 11 };  
byte gateway[] = { 192, 168, 0, 254 }; 
byte subnet[] = { 255, 255, 255, 0 }; 
byte localPort = 99; 

EthernetServer server = EthernetServer(localPort); 

void setup() 
{ 
    // initialize the ethernet device 
    Ethernet.begin(mac, ip, gateway, subnet); 
    Serial.begin(9600); 

    // start listening for clients 
    server.begin(); 
    Serial.println("Server ready"); 
} 

void loop() 
{ 
    // if an incoming client connects, there will be bytes available to read: 
    EthernetClient client = server.available(); 
    if (client == true) { 
    Serial.println("Received:"); 

    byte received = 0; 
    while((received = client.read()) != -1) { 
     Serial.println(received); 
     server.write(received); 
    } 

    Serial.println("Over\n"); 
    } 
} 

클라이언트 코드 (PC, QtCreator는) :

#include <QTextStream> 
#include <QTCPSocket> 

QString arduinoIP = "192.168.0.11"; 
char arduinoPort = 99; 

int main(void) 
{ 
    QTcpSocket socket; 
    QTextStream in(stdin); 
    QTextStream out(stdout); 

    out << "Connection... "; out.flush(); 
    socket.connectToHost(arduinoIP, arduinoPort); 
    if(!socket.waitForConnected(5000)) { 
     out << socket.errorString() << "\n"; 
    } 
    else { 
     out << "OK\n"; out.flush(); //I don't know why \n doesn't flush 

     out << "Type a message to send to the Arduino or quit to exit\n"; out.flush(); 

     QString command; 
     in >> command; 

     while(command != "quit") { 
      QByteArray bufOut = command.toUtf8(); 
      socket.write(bufOut); 
      socket.waitForReadyRead(1000); //Wait for answer (temp) 
      out << "Answer: " << socket.readAll() << "\n"; 
     } 
    } 

    return 0; 
} 

당신의 도움에 미리 감사드립니다.

감사합니다, 미스터 Mystère

+0

나는 또한 게시하는 것은 좋은 생각 일 것이다라고 생각했다가 있기 때문에 그 절대적으로 (검색 시간 후 나의 지식에) HTTP를 사용하지 않고 이더넷/wifi를 통해 PC와 arduino 사이의 통신을위한 간단한 응용 프로그램 (서버 및 클라이언트)을 찾을 수있는 웹에서. 일반적으로이 댓글은 Google에서 색인을 생성하고이를 찾는 사람들을 도울 정도로 충분해야합니다. 이를 염두에두고이 코드를 개선하는 데 언제든지 도움을주십시오. –

답변

3

TCP 연결은 데이터의 안정적인 전송을 제공하기 위해 더 많은 패킷을 필요로합니다. TCP는 낮은 대기 시간을 의미하지 않으며, 데이터의스트림을 안정적으로 전송하기위한 것입니다. 예를 들어 파일을 보내는 경우 모든 패킷을 수신하여 올바른 순서로 함께 연결해야합니다.

대역폭과 대기 시간과 관련이 없다는 사실을 알 수 있습니다. 대부분의 스트리밍 비디오 시스템은 데이터를 미리 버퍼링하여 전송 스트림에 중단이 없다는 환상을 제공합니다. 기본 동작은 전송 대기 시간이 불안정 할 수 있지만 버퍼링 된 데이터는 연속 스트림의 인식을 유지한다는 것입니다.

응용 프로그램의 경우 UDP를 사용하는 것이 좋습니다.

UDP on Arduino

TCP는 UDP 작은 메시지입니다 스트림입니다. 귀하의 결정은 질문에 피벗 될 것입니다 :

패킷이 전송되었지만 수신 된 적이없는 경우의 영향은 무엇입니까?

컨트롤러 입력의 경우 손실 된 데이터를 무시하고 다음 전송을받는 것이 더 나을 수 있습니다. 나는 당신의 질문에서 컨트롤러의 상태를 반복적으로 보내고 있다고 가정합니다 (왼쪽 아래로 위로?) 그렇다면 UDP를 선택하십시오. TCP를 선택하면 다음 데이터를 보내기 전에이 손실 된 데이터를 계속 복구하는 동작이 계속됩니다. 유스 케이스에서는 스트림 복구를 시도하는 대신 다음 컨트롤러 상태를 전송할 수도 있습니다.

+0

아주 잘 답변을 제시, 많이 감사드립니다. UDP를 고려한 이유는 UDP가 더 빠르다고 들었 기 때문에 데이터를 잃어 버렸기 때문에 TCP를 선호했기 때문입니다 (버튼에 대한 명령 대신 모든 상태를 보내야 만합니다). 처리량이 안전 프로토콜에 충분합니다. 나는 UDP로 전환해서 알려 드리겠습니다. - 주제가 잘못되었다고 표시하거나이 질문을 열어두면 UDP에 대해 다른 주제를 다시 표시해야합니까? –

+0

매력처럼 작동합니다. 고마워, 그건 큰 차이 야! –

2

는 당신이 그 꽤 총론을 확인 했습니까?

1) Wi-Fi 스펙트럼을 확인 했습니까? 겹치는 채널은 패킷을 떨어 뜨립니다. 이러한 패킷은 약간의 추가 지연으로 재전송됩니다. 유용한 도구 :

2) Arduino가 네트워크의 다른 장치의 브로드 캐스트 패킷으로 넘치지 않습니까? 브로드 캐스트 패킷을 확인하고 무시하면 네트워크 스택이 많이 바쁠 수 있습니다. TCP 연결의 패킷을 삭제하고 재전송 할 수 있습니다. PC와 Arduino를위한 개인용 AP를 시험해보고 성능을 살펴보십시오.

+0

답변 해 주셔서 감사합니다. 컴퓨터와 arduino + 이더넷 쉴드는 모두 AP 모드의 TP-LINK 나노에 연결되어 있습니다. 나는 내일 스펙트럼을 점검 할 것이고 그에 따라 채널을 변경해야 할 수도 있지만 그런 지연에 책임이있을 수 있는가? –

+1

나는 미라 캐스트 솔루션을 연구 중이다. 이 표준은 Wi-Fi를 통해 비디오를 전송합니다. 정말로 나쁜 Wi-Fi 환경에서 대기 시간은 정상보다 400ms 더 길어질 수 있습니다 (초 단위가 아닙니다!). 우리는 또한 UDP를 사용하여 비디오 데이터를 전송합니다. 다음 명령을 참조하십시오. Arduino에 어떤 프로세서가 있는지 공유 할 수 있습니까? 저는 기본 마이크로 컨트롤러에서 lwip으로 2 년 전에 일했습니다. 많은 트래픽이 lwip의 네트워크 스택에 의해 수신 되었다면, 마이크로 컨트롤러는 상당히 느려졌다. 그것이 내가 사설망을 사용하도록 요청한 이유입니다. –

+0

Arduino 메가 2560입니다. jdr5ca와 마찬가지로 대기 시간은 사전 버퍼링에서 나올 수 있으므로 UDP 통신을 대신 고려하여 다시 연락 드리겠습니다. –

0

UDP 정말 빠르고, 내가 대신이 테스트 코드를 사용 :

#ifndef MAINWINDOW_H 
#define MAINWINDOW_H 

#include <QMainWindow> 
#include <QTimer> 
#include <QVBoxLayout> 
#include <QSpinBox> 
#include <QtNetwork/QUdpSocket> 

class MainWindow : public QMainWindow 
{ 
    Q_OBJECT 

public: 
    explicit MainWindow(QWidget *parent = 0); 
    ~MainWindow(); 

public slots: 
    void onTimer(); 

private: 
    QTimer timer; 
    QVBoxLayout layout; 
    QWidget centralW; 
    QSpinBox sendBox; 
    QSpinBox receiveBox; 

    QUdpSocket *socket; 
}; 

#endif // MAINWINDOW_H 

#include "mainwindow.h" 

MainWindow::MainWindow(QWidget *parent) : 
    QMainWindow(parent) 
{ 
    connect(&timer, SIGNAL(timeout()), this, SLOT(onTimer())); 
    timer.start(100); 
    sendBox.setMaximum(1000); 
    layout.addWidget(&sendBox); 
    receiveBox.setMaximum(1000); 
    layout.addWidget(&receiveBox); 
    centralW.setLayout(&layout); 
    setCentralWidget(&centralW); 

    socket = new QUdpSocket(this); 
} 

MainWindow::~MainWindow() 
{ 
} 

void MainWindow::onTimer() { 
    QByteArray datagram = QByteArray::number(sendBox.value()); 
    socket->writeDatagram(datagram.data(), datagram.size(), QHostAddress("192.168.0.11"), 99); 

    if(socket->hasPendingDatagrams()) { 
     datagram.resize(socket->pendingDatagramSize()); 
     socket->readDatagram(datagram.data(), datagram.size()); 
     receiveBox.setValue(QString(datagram.data()).toInt()); 
    } 
} 

그리고 서버 측

:

#include <SPI.h>   // needed for Arduino versions later than 0018 
#include <Ethernet.h> 
#include <EthernetUdp.h>   // UDP library from: [email protected] 12/30/2008 

byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0x48, 0x0D }; 
byte ip[] = { 192, 168, 0, 11 };  
byte gateway[] = { 192, 168, 0, 254 }; 
byte subnet[] = { 255, 255, 255, 0 }; 
byte localPort = 99; 

EthernetUDP Udp; 

void setup() { 
    Ethernet.begin(mac,ip); 
    Udp.begin(localPort); 

    Serial.begin(9600); 
} 

void loop() { 
    // if there's data available, read a packet 
    int packetSize = Udp.parsePacket(); 
    if(packetSize) 
    { 
    static char buffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet, 

    //Udp.read does not erase the rest of the buffer, without that we would 
    //get 989 instead of 98 after having entered 999 for example 
    for(int i = 0; i < UDP_TX_PACKET_MAX_SIZE; ++i) buffer[i] = 0; 

    Udp.read(buffer,UDP_TX_PACKET_MAX_SIZE); 
    Serial.println(buffer); 

    // send a reply, to the IP address and port that sent us the packet we received 
    Udp.beginPacket(Udp.remoteIP(), Udp.remotePort()); 
    Udp.write(buffer); 
    Udp.endPacket(); 
    } 
}