arduino_uip
arduino_uip copied to clipboard
UDP unresponsive to incoming packets, still sending outgoing data
Hi,
Thank you for this library. It is wonderful. I'm having a hard time debugging an issue.
I have a system with 21 nodes (arduino nano + ENC28J60, as well as Maxbotix MB1260 ultrasonic range finder, relay module, and limit switch) controlled from a central computer via OSC messaging. After some length of time (1-3 hrs) individual nodes become unresponsive to incoming UDP packets. They still sending outgoing packets to the computer (for instance if I trigger the limit switch) but do not respond to incoming messages to ping the ultrasound or switch the relay.
There is no pattern to which nodes freeze. As far as I can tell it may relate to the density of control messages sent: with all 21 online, sending lots of control messages back and forth, I get more freezes.
I am unable to replicate the problem on a home setup with only two nodes. They run fine for hours with lots of relay on/off and pinging control messages.
The code on the arduinos is relatively simple. I wonder if you see any obvious problems such as my use of Udp.flush()/Udp.stop()/Udp.begin() and Ethernet.begin(). Or if anything leaps out to you as a reason for periodic unresponsiveness:
#include <UIPEthernet.h>
#include <OSCMessage.h>
#include <OSCBundle.h>
//#define DEBUG
// update this id for each control unit between 1 - 21
#define UNIT_ID 2
// string / osc address voodoo using preprocessor
#define xstr(s) str(s)
#define str(s) #s
#define MAKE_MAC_PAIR(value) value + 16
// OSC ADDRESSES
#define RANGE_ADDR "/br/" xstr(UNIT_ID) "/range"
#define PONG_ADDR "/br/" xstr(UNIT_ID) "/pong"
#define LIMIT_ADDR "/br/" xstr(UNIT_ID) "/limit"
#define RELAY_ADDR "/br/" xstr(UNIT_ID) "/relay"
// Networking / UDP Setup
EthernetUDP Udp;
// arduino address
IPAddress ip(192,168,3,UNIT_ID);
const unsigned int inPort = 8888;
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, MAKE_MAC_PAIR(UNIT_ID) }; // different mac for each arduino
// destination address
IPAddress targetIP(192, 168, 3, 100);
const unsigned int targetPort = 57120;
// reset network module, which occasionally freezes
// the reset takes next to no time
long lastReset = -50000;
long resetInterval = 10000;//10000;
// Arduino I/O pins
const int relayPin = 6; // relay control
const int limitPin = 7; // limit switch
const int triggerPin = 9; // trigger ultrasound ping
#if UNIT_ID == 10
const int echoPin = 2; // pulse-in from ultrasonic rangefinder
#else
const int echoPin = 8; // pulse-in from ultrasonic rangefinder
#endif
// Range-finder calibration
// rangefinder
const int echoTimeout = 90000; //#define MAX_DISTANCE 400 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
#define US_ROUNDTRIP_IN 146 // Microseconds (uS) it takes sound to travel round-trip 1 inch (2 inches total), uses integer to save compiled code space.
// Notifications
// periodic transmission of relay state and limit switch
const int transferInterval = 200;
long lastTransfer = 0;
// Arduino state
byte limitState = HIGH;
byte relayState = HIGH;
//--------------------------------//
// SETUP //
//--------------------------------//
void setup() {
#ifdef DEBUG
Serial.begin(9600);
#endif
Ethernet.begin(mac,ip);
Udp.begin(inPort);
pinMode(relayPin, OUTPUT);
pinMode(limitPin, INPUT);
pinMode(triggerPin, OUTPUT);
pinMode(echoPin, INPUT);
// disable maxbotix
digitalWrite(triggerPin, LOW);
executeRelayState();
}
//--------------------------------//
// MAIN LOOP //
//--------------------------------//
void loop(){
// read incoming udp packets
OSCMessage msgIn;
int size;
int success;
// while (Udp.parsePacket() > 0) ; // discard any previously received packets
if( (size = Udp.parsePacket())>0)
{
//while((size = Udp.available()) > 0)
while(size--)
msgIn.fill(Udp.read());
// route messages
if(!msgIn.hasError()) {
msgIn.route("/ping", pingOSCHandler);
msgIn.route("/relay", relayOSCHandler);
}
//finish reading this packet:
Udp.flush();
//restart UDP connection to receive packets from other clients
Udp.stop();
success = Udp.begin(inPort);
}
// read limit switch
byte newLimitState = digitalRead(limitPin);
// shut off motor at top no matter what
if(newLimitState == LOW) {
byte lastRelayState = relayState;
relayState = HIGH; // off
executeRelayState();
}
if(newLimitState != limitState) {
// store new state
limitState = newLimitState;
// notify host
sendAndRestart(LIMIT_ADDR, (byte)limitState);
};
// periodically send limit state
if((millis() - lastTransfer) > transferInterval) {
executeRelayState();
// notify host
sendAndRestart(LIMIT_ADDR, (byte)limitState);
lastTransfer = millis();
}
// reset ethernet chip periodically
if(millis() - lastReset > resetInterval) {
Ethernet.begin(mac,ip);
lastReset = millis();
}
// restart with new connection
Udp.stop();
Udp.begin(inPort);
}
//--------------------------------//
void sendAndRestart(char * addr, byte val) {
OSCMessage msg(addr);
msg.add((byte)val);
Udp.beginPacket(targetIP, targetPort);
msg.send(Udp); // send the bytes to the SLIP stream
Udp.endPacket(); // mark the end of the OSC Packet
msg.empty(); // free space occupied by message
// restart UDP connection so we are ready to accept incoming ports
Udp.stop();
Udp.begin(inPort);
}
void sendAndRestart(char * addr, unsigned long val) {
OSCMessage msg(addr);
msg.add((int32_t)val);
Udp.beginPacket(targetIP, targetPort);
msg.send(Udp); // send the bytes to the SLIP stream
Udp.endPacket(); // mark the end of the OSC Packet
msg.empty(); // free space occupied by message
// reset UDP connection so we are ready to accept incoming ports
Udp.stop();
Udp.begin(inPort);
}
//--------------------------------//
void executeRelayState() {
// digital write changed value
digitalWrite(relayPin, relayState);
// notify control with new state
sendAndRestart(RELAY_ADDR, relayState);
}
void relayOSCHandler(OSCMessage &msg, int addrOffset){
int inValue = msg.getInt(0);
#ifdef DEBUG
Serial.print("rx ");
Serial.println(inValue);
#endif
byte lastRelayState = relayState;
relayState = (inValue == 1);
if(lastRelayState != relayState)
executeRelayState();
}
void pingOSCHandler(OSCMessage &msg, int addrOffset) {
unsigned long duration;
unsigned long range;
#ifdef DEBUG
Serial.print("rx - ping: ");
Serial.println(" * )))))");
#endif
// acknowledge to host
sendAndRestart(PONG_ADDR, (byte)0);
// send out the ping
digitalWrite(triggerPin, HIGH);
delayMicroseconds(20); // held high for a minimum of 20uS
duration = pulseIn(echoPin, HIGH);//, echoTimeout); // optional timeout in microseconds, 95000 uS is 95ms
range = duration / US_ROUNDTRIP_IN; // range calculated from echo time, more accurate
// disable ranging
digitalWrite(triggerPin, LOW);
// 2cm / analogInUnit * 0.393701 in/cm = inches/analogInUnit
// if(range == 0) range = analogRead(A0) * 0.393701 * 2.0; // range from analog
//range=analogRead(A0);
#ifdef DEBUG
Serial.println(" * (((((");
Serial.println(range);
#endif
sendAndRestart(RANGE_ADDR, (unsigned long)range);
}
//--------------------------------//
/* Configuration via OSC */
//--------------------------------//
// removed
Many thanks in advance,
Robert
Hey,
for me nearly the same here - controlling a LED Strip with an arduino nano and ENC28J60. First connect with android Controll app (https://play.google.com/store/apps/details?id=com.charlieroberts.Control&hl=en) works like a charm. I see the network traffic at the rj45 jack when changing color via the app - and i see the RX/TX led on the nano when changing the color. When i close the app and restart it - select the destination ip - i can see the rj45 jack led responses to the color change but it looks like the nano did not receive any packet (the RX/TX led stays off).
So i can reproduce it with a second connect - after reset the arduino everything works until the second connection...
I have exactly the same problem like nibelungen, are there any news about this?
Try this: https://github.com/TMRh20/arduino_uip The same library with some improvements