5

I will be using an Arduino as a bridge between a computer high-level Java client and some low-level hardware computing units (e.g. other Arduinos). I need to find a solution to periodically communicate in both ways. It should be possible to send digital, analog inputs to the PC and receive digital, analog outputs from the PC via serial.

I have very specific requirements for my project to work:

  1. Lowest possible latency in both ways. High latency would cause instability of controlled systems.

  2. Extremely constant, possibly user-defined update period. Varying sample rate would cause inaccuracies in the control.

I need a very fast solution possible for update frequency of 100 Hz and higher.

So far I have tried to send data via Firmata to my java client using time interrupt.

ISR(TIMER1_COMPA_vect) {
  Firmata.sendAnalog(analog, analogRead(analog));
}

The messages however don't come at a very constant rate and are sometimes held up for twice the sample period or more which is unnaceptable. For higher frequencies this happens even more often. I suspect some kind of a buffer. Do you have any idea where should I look for bottlenecks? Would it be benefiting to design my own communication protocol and ditch Firmata?

EDIT: Look at the attached diagram . Blue lines are "inputs", green lines "outputs". Right now I am trying to design the "Arduino (Bridge)" enter image description here

8
  • You might want to just use millis() and delay to help avoid variance in the sampling rate. For latency, IMHO it'd be better to get a very high baud rate. You could reduce errors with this library here. – Anonymous Penguin Apr 15 '14 at 20:48
  • I thought using hardware timed interrupt should be significantly more accurate. So nothing in the loop() can slow down the messages. Am I wrong? – SagiCZ Apr 15 '14 at 20:51
  • You're correct. They would be more accurate, but do remember that, if you want it to always be consistent, you'll have to add a little "padding time" to most code to make sure that something a little longer doesn't hold back the next iteration. It won't make it faster, but it most likely will regulate the time between iterations well. Since I don't know your application, the solution in the first comment was the easiest :) – Anonymous Penguin Apr 15 '14 at 20:53
  • A USB interface itself may be a poor fit for an application requiring low latency. It's possible that it would just barely work at the rate you need with very efficient software drivers on both ends, but you should consider the very fact of using USB to itself add a millisecond or more of latency, and your interval is less than 10 ms. Normally, a control loop should be moved entirely outboard of the USB - ie, use a more capable embedded board ("Arduino" or otherwise) and run the entire control loop on it, passing only non-realtime settings/status over the USB. – Chris Stratton Apr 16 '14 at 17:15
  • 1
    Using hardware timers will be WAY better then one of the arduino constructs like millis(). It'll also be far more deterministic regarding timing constraints. Of course, if you're including the USB's latency (anywhere from 10-200 mS, unpredictable and uncontrollable), you're probably SOL. – Connor Wolf Apr 20 '14 at 12:25
1

Lowest possible latency in both ways. High latency would cause instability of controlled systems.

the fact that you are using a not-real-time OS introduce a lot of unpredictable latency, the use of a visrtual machine over that os then add a bit more. Fast communication can be obtained increasing the baudrate, that will decrease the latency between the sample and the elaboration. Also sending RAW data instead of string will be faster (no convertion AND less byte send), and finally decreasing the overhead caused by the protocol.

For example Firmata by default use a low baudrate AND will add a lot of overhead to send WHAT kind of operation is doing. Writing your own communication protocol is better.

For example: analogRead use 10bit, so you may send a raw int, 2 byte, 16bit, so 6 bit are lost.. or you can "compress" with a bit of bitwise operation 4 read (40 bit) into 5 byte (40bit, no bit loss) instead of 8(int size * 4)!

AnalogRead is a really slow operation by default on arduino (~200us), but can be faster if you set up a lower prescaler (attention, lower prescaler means less ADC precision. at prescaler 16 guaranteed precision is 8bit, if my memory is good)

Extremely constant, possibly user-defined update period. Varying sample rate would cause inaccuracies in the control.

On the PC side, if you need micro/nano second precision you need a real time os, newest linux kernel add a new special schedule but i think is still hard to find documentation. If less precision is ok, just use a timer.

On the arduino side, using a hardware timer is the best way, see LeOS for a nice scheduler on arduino

Please note HardwareSerial on the arduino side use interrupt to send data, so using it inside an ISR (like you are doing now or with LeOS) is really usafe and deadlock prone. Also ISR will "slow down" each others, as they cannnot be executed parallel; and analogRead is a realtivly slow operation.. I would use timer to set up a flag, and in the loop if i see the flag, start the analogread, Serial.write and finally Serial.flush (to be sure to not fill Serial buffer, causing a lot of trouble on the arduino reprogrammation reset)

7
  • "... but can be faster if you set up a lower prescaler ..." Or if you forgo analogRead() altogether and just have the ADC dump its results into a volatile variable when finished converting and read from that variable upon request. – Ignacio Vazquez-Abrams Apr 16 '14 at 3:41
  • i dont see how the adc read finished interrupt can help, expecially if not setting the adc. Or are you suggesting to use register insted of snalogread – Lesto Apr 16 '14 at 6:57
  • You set the ADC to autotrigger (off, say, a timer), and have the completion ISR dump the value into the variable. You then read from this variable instead of accessing the ADC directly. – Ignacio Vazquez-Abrams Apr 16 '14 at 7:04
  • thank you, these are some great ideas.. When it comes to the PC client side I am not going for the RTOS route so I would like to implement the second approach you suggested -> "just use a timer". Could you elaborate on that a little bit? How does timer help me compared to uninterrupted listening to the port? Did you mean I can time the message processing for the cost of being "behind" one or two periods? That would probably be acceptable. – SagiCZ Apr 16 '14 at 7:53
  • +SagiCZ i was talking about sheduled action. To read the data event or blocking call are optimal solution – Lesto Apr 16 '14 at 7:58
1

could you be more specific with your question ? From what I understood:

  • you have a client java program acting as the "brain" of your system
  • your control is time sensitive. You have a PID or other regulation loop running on the pc
  • you have or plan to have multiple arguing boards on your system and you need to communicate with them.
  • you are dealing with analog IOs

bridging

If you want to stick to serial port,you have to use RS485 or RS422. Those can work as a bus. Protocol on top of that can be Modbus. Note that this has a higher latency and you need at least 2 serial ports on your bridge

I2C. Lower latency 2 wires bus. Command oriented,runs at 400 kHz. So you have plenty of time to send/receive data

SPI even lower latency as bytes are sent as stream .arduino mega has 5 pins for it. Note that you have to deal with the addressing yourself in this case.

Arduino like many micro controllers is bad as doing many tasks at the same time like for the bridging case. I would avoid using an arduino in this case

latency

As already answered, ADC conversion takes time and you cannot nest interrupt. Your minimum latency can be computed from the specifications of the arduino. The maximum latency is a value you fix yourself. Knowing the amount of time to send one byte on the communication port, You can decide between options like

  • run the AD conversion in a loop outside interrupt, put the value inside a variable and do the communication a synchronously inside an interrupt
  • run the AD conversion interrupt based and the communication in the main loop of operation

conclusions

Don't do hardware in the loop using a PC. The latency and lack of strict timing possibilities worsened by the use of java make it a dead end with your current setup.

Use a stronger micro controller like an AVR32 with USB running the brain of your system. You can also use a raspberries pi or a beaglebone. Those runs "standard" Linux distributions and so you can use a PC like approach.

In any case guidelines are :

  • try to stay as close to the micro controller as possible and avoid abstraction libraries and OSes
  • don't use a pc for hardware in the loop
  • try to make your task run a synchronously as much as possible
  • keep your interrupt routines as small as possible
2
  • Maybe I could forget about serial but still use Arduino and USB connection. I think there might be a way to set up the connection as a HID device or something entirely different from Serial. Your conclusion and final suggestions unfortunately dismiss the project's point. Which is to simulate with hardware in the loop but also visualize the simulated robot in java game engine. I don't think it should be impossible to send the data so fast. I know that for example external audio cards have latency of about 1 ms and send the data with rate of 20 kHz or similar through USB. – SagiCZ Apr 21 '14 at 8:07
  • I have edited the question with a diagram to help you understand. – SagiCZ Apr 21 '14 at 8:16
0

I have had great success removing serial from such an example and setting up a closed network and then Ethernet enabling all the arduino devices. I then have a DCHP and SNTP server in the closed network. The PC etc are all in the closed network. I then setup a MQTT server (see www.mosquitto.org) and use the arduino PubSub library on the arduino. I get extremely short round trips with pretty consistent response times and this has the advantage that multiple sources can publish or subscribe to the data steams created. The SNTP server is used so that all the devices get the same time reference to use and I time stamp all messages and can then work out message sequence etc even if they are physically delayed slightly by an Ethernet collision! although in a closed network this is minimized.

2
  • This sounds promising. Did you use Arduino ethernet shield? Could you provide more details or point me in a direction to learn about details of this implementation? Ditching serial has been my newest idea :) – SagiCZ Apr 21 '14 at 8:11
  • @SagiCZ If you are looking for a high-performance PubSub based communication protocol, without the overhead of MQTT broker, you should have a look to my project, it is pretty much that, point-to-point protocol, lightweight C library and a python CLI to communicate with the device, open plots,etc : github.com/Overdrivr/pytelemetrycli – Overdrivr Feb 9 '16 at 17:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.