I'm trying to build a quadrocopter and control it with my Computer over wifi.
My setup:
Arduino with Ethernet Shield mounted on the quadrocopter
Ethernet Shield connected via LAN to a wifi router also mounted on the quadrocopter
Computer connected to quadrocopters wifi
Xbox Controller connected to computer
My problem is to get a save (bidirectional) connection to the quadrocopter, so I can fly with it without worrying about loosing the connection.
My goal is to send commands like speed, direction etc. to the Arduino and to get back a feedback like pitch, roll etc.
My Arduino server code:
void loop()
{
EthernetClient client = server.available(); //if server got a client, create a client to handle it
if (client && client. connected) { //check if client is ready and connected
if (client.available()) { //check for incoming data
data = client.readStringUntil('|'); //the data has alway this format: XXX;XXX;XXX;XXX;XXX;|
data.trim();
client.flush();
for(int i = 0; i < 5; i++){ //split the string and convert it to integers
lastcomma = comma;
comma = data.indexOf(';', comma + 1);
if(comma < 1){
comma = data.length();
}
substrg[i] = data.substring(lastcomma, comma);
substrg[i].toCharArray(buffer, 32);
int values[i] = atoi(buffer);
Serial.print(values[i]);
Serial.print("\t");
comma++;
if( i == dataToRecieve-1){
comma = 0;
lastcomma = 0;
}
}
P = values[0]; P = P/100; //get understandable names for the variables
I = values[1]; I = I/100;
D = values[2]; D = D/100;
ARM = values[3];
SPEED = values[4] + 20;
FRONT.SetTunings(P, I, D); //set new PID tunings
BACK.SetTunings(P, I, D);
int kalXint = kalAngleX;
int kalYint = kalAngleY;
int xOutint = 0;
client.print(kalXint); //send a message back to the computer
client.print(";"); // format is XXX;XXX;XXX;|
client.print(kalYint);
client.print(";");
client.print(xOutint);
client.print(";");
client.print("|");
}
}
}
}
I'm running an processing script on the computer, which is doing pretty much the same, except it runs as client.
But the TCP/IP protocoll checks for droped packets and the UDP doesn't. So I thougth it is better to use TCP/IP...
Maybe I can give the code a "command structure". Instead of sending all the values every loop, it would send the values only when it's needed.
This structure would look like this: command:value| (f.ex.: command = kalmanX, value = 180°)
Does this make sense?
More than trying to force the client/server architecture to do something it is not intended to do.
But the TCP/IP protocoll checks for droped packets and the UDP doesn't. So I thougth it is better to use TCP/IP...
There are, of course, tradeoffs. What can you do about a dropped packet in the time you have to deal with a packet? Not much. If the packets arrive often enough, a dropped packet isn't the end of the world.
PaulS:
There is not a continuous connection, using TCP/IP. The connection exists only long enough to transfer ONE GET request/one response.
Speaking about networking in general, TCP/IP will let you go back and forth as many times as you like. It sounds like you are describing HTTP, which is get/response oriented, but you can use a different protocol like telnet or even make up your own TCP/IP protocol and do as much back and forth as you want within a single persistent TCP socket.
That said, I don't know if the Ethernet Arduino shield or library will let you use non-HTTP TCP protocols?
I think in the past the below http code was doing ~15 transactions per second when the fast data was selected. The page has a counter so the updates can be timed. YMMV
// zoomkat's meta refresh data frame test page 5/25/13
// use http://192.168.1.102:84 in your brouser for main page
// http://192.168.1.102:84/data static data page
// http://192.168.1.102:84/datastart meta refresh data page
// for use with W5100 based ethernet shields
// set the refresh rate to 0 for fastest update
// use STOP for single data updates
#include <SPI.h>
#include <Ethernet.h>
const int analogInPin0 = A0;
const int analogInPin1 = A1;
const int analogInPin2 = A2;
const int analogInPin3 = A3;
const int analogInPin4 = A4;
const int analogInPin5 = A5;
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 192, 168, 1, 102 }; // arduino ip in lan
byte gateway[] = { 192, 168, 1, 1 }; // internet access via router
byte subnet[] = { 255, 255, 255, 0 }; //subnet mask
EthernetServer server(84); //server port
unsigned long int x=0; //set refresh counter to 0
String readString;
//////////////////////
void setup(){
Serial.begin(9600);
// disable SD SPI if memory card in the uSD slot
pinMode(4,OUTPUT);
digitalWrite(4,HIGH);
Ethernet.begin(mac, ip, gateway, gateway, subnet);
server.begin();
Serial.println("meta refresh data frame test 5/25/13"); // so I can keep track of what is loaded
}
void loop(){
EthernetClient client = server.available();
if (client) {
while (client.connected()) {
if (client.available()) {
char c = client.read();
if (readString.length() < 100) {
readString += c;
}
//check if HTTP request has ended
if (c == '\n') {
//check get atring received
Serial.println(readString);
//output HTML data header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println();
//generate data page
if(readString.indexOf("data") >0) { //checks for "data" page
x=x+1; //page upload counter
client.print("<HTML><HEAD>");
//meta-refresh page every 1 seconds if "datastart" page
if(readString.indexOf("datastart") >0) client.print("<meta http-equiv='refresh' content='1'>");
//meta-refresh 0 for fast data
if(readString.indexOf("datafast") >0) client.print("<meta http-equiv='refresh' content='0'>");
client.print("<title>Zoomkat's meta-refresh test</title></head><BODY>
");
client.print("page refresh number: ");
client.print(x); //current refresh count
client.print("
");
//output the value of each analog input pin
client.print("analog input0 is: ");
client.print(analogRead(analogInPin0));
client.print("
analog input1 is: ");
client.print(analogRead(analogInPin1));
client.print("
analog input2 is: ");
client.print(analogRead(analogInPin2));
client.print("
analog input3 is: ");
client.print(analogRead(analogInPin3));
client.print("
analog input4 is: ");
client.print(analogRead(analogInPin4));
client.print("
analog input5 is: ");
client.print(analogRead(analogInPin5));
client.println("
</BODY></HTML>");
}
//generate main page with iframe
else
{
client.print("<HTML><HEAD><TITLE>Zoomkat's frame refresh test</TITLE></HEAD>");
client.print("Zoomkat's Arduino frame meta refresh test 5/25/13");
client.print("
Arduino analog input data frame:
");
client.print(" <a href='http://192.168.1.102:84/datastart' target='DataBox' title=''yy''>META-REFRESH</a>");
client.print(" <a href='http://192.168.1.102:84/data' target='DataBox' title=''xx''>SINGLE-STOP</a>");
client.print(" <a href='http://192.168.1.102:84/datafast' target='DataBox' title=''zz''>FAST-DATA</a>
");
client.print("<iframe src='http://192.168.1.102:84/data' width='350' height='250' name='DataBox'>");
client.print("</iframe>
</HTML>");
}
delay(1);
//stopping client
client.stop();
//clearing string for next read
readString="";
}
}
}
}
}
I'm trying to build a quadrocopter and control it with my Computer over wifi.
...
My goal is to send commands like speed, direction etc. to the Arduino and to get back a feedback like pitch, roll etc.
Personally, I'd say don't even try. I doubt wifi will have quick enough responsiveness for adequate control of a flyer. Unless maybe the flyer has an extreme amount of autonomous smarts. Also, with wifi, range will be very limited. You'd probably do better with longer-range XBee modules or maybe RFM22 radios. I'm sure their responsiveness will also be much better. 100-200mW transmit power.
As far as it getting out of range, I've thought about this with my [ground] robots. A flyer is easy since, if it loses contact, you can have it go into an increasing-spiral circling pattern. With my robots, I thought to have the robot remember its past few directional commands from the base station, and if signal is lost, then backtrack the commands in reverse.
SurferTim:
But with the wireless router, the Arduino, and assorted control stuff onboard, weight may be an issue.
I wondered about this. Why not use a wifi shield instead of Ethernet+router?
Transmit power. My router has a 500mw radio onboard, and provides power for the Arduino over a usb port, and allows a telnet-like connection to the Arduino usb port.
edit: Transmitting with that power setting is illegal in many countries. Many places have a 100mw transmit limit.