Arduino Yun - JSON over TCP with Node.js

Hey there,

i am trying to receive OSC Messages and write these messages to the key value storage with Node.js on my Arduino Yun. I walked through this tutorial but instead of python I wanted to do it with Node.js. Adventures with Arduino Yun: Control your Yun from your mobile phone using TouchOSC

Receiving OSC Messages works fine and connecting to the TCPJSONServer at 127.0.0.1:5700 on the Linino side obviously works fine as well. But i can't write data to the key value storage. I'm not getting any errors, there is just no data in the storage. I've tried different Node.js packages (json-over-tcp, jsonsocket, json-socket, ...) but with no luck.

The python version from the tutorial works fine at all and is able to write data to the key value storage.
Maybe somebody good at python or Node.s who can help me along and see the difference or an error? That would be great. Thanks!

Node.js Code

var osc = require('node-osc');
var JsonSocket = require('jsonsocket');

var client = new osc.Client('192.168.178.35', 9000); //Smartphone, TouchOSC
var oscServer = new osc.Server(8000, '192.186.178.31'); //Arduino

console.log("trying to connect to TCPJSONSERVER...");
var socket = new JsonSocket(5700, '127.0.0.1');

socket.on('connect', function() {
    console.log("connected");
});

oscServer.on("message", function (msg, rinfo) {
    console.log(msg[1]);
    client.send('/1/label1', msg[1], function () {});
    socket.write({"value":msg[1],"key":"D13","command":"put"});
});

Python Code

from OSC import OSCServer,OSCClient, OSCMessage
import sys
from time import sleep
import types
sys.path.insert(0, '/usr/lib/python2.7/bridge/') # make sure python can see the tcp module

from tcp import TCPJSONClient
													 
#set up the json client and the osc client and server. The server should have the ip of your Yun. 
#The client.connect should have the ip address of you phone. 
json = TCPJSONClient('127.0.0.1', 5700)
server = OSCServer( ("192.168.178.31", 8000) )
client = OSCClient()
client.connect( ("192.168.178.35", 9000) )

#waits for slider change
def handle_timeout(self):
	print ("Timeout")

server.handle_timeout = types.MethodType(handle_timeout, server)

# function to do the work. path refers to the fader name, args refers to the value of the slider
def fader_callback(path, tags, args, source):
	global fader1Feedback
	if path=="/1/fader1":
		fader1Feedback = float(args[0])
		msg = OSCMessage("/1/label1")
		msg.insert(0, fader1Feedback)
		print "%i" % fader1Feedback
		json.send({'command':'put', 'key':'D13', 'value':'%i' % (fader1Feedback)})
		client.send(msg)

#execute
server.addMsgHandler( "/1/fader1",fader_callback)

while True:
	server.handle_request()

server.close()

@schaefer_julian,
I looked at the tutorial. Luckily the author explains what he is doing. However, the whole process is cock-eyed. It appears the author is enamoured with server technology or just does not know what he want to accomplish.

Your code appears to be faithful, although I have not tested it.

What are you trying to do?
What have you done to validate/verify the operation of your code?

Jesse

Hey Jesse,

thanks for your response. I am trying to send midi data via OSC wirelessly from Ableton Live to the Arduino Yun. The idea is that the microcontroller will transform the midi data to light signals, so each midi note will be represented by a single led for example. A unique kind of light organ.

This is how i tried to verify my program:

When I do the process with python I can send OSC messages from my smartphone with TouchOSC to the Arduino and print it to the console.

It is also possible to place the data to key value storage when I do it with python. I checked this with the web interface my Yun has.

When I do the process with node.js I can send OSC messages from my smartphone to the Arduino as well. Obviously I also can connect to the TCPJSONServer because the ON event is triggered and there is no error at all.

But writing data to the key value storage is not working. The web infertace says there is no data in the storage. Maybe there is something wrong with the json string I'm trying to place there?

Why do you think this approach is cockeyed? Is there a more elegant way to do this?

Best, Julian

@Julian,
Yes. Getting directly to the point, the Yun is, and has, a builtin server. As such, you can send data to the server, store the data on the server and talk directly to the IO pins from the server. In addtion the bridge software has a limitation of 4 transaction per second - which would give a weak interface to your light show. A moderate change in the design will give you better and more flexibility for performance.

First, here are the two (2) article that will help you get started:

With these article you can change from the slow design (4/sec) to faster design (878/s) (or ~100k samples per second).

On your original design and it being cockeyed, this design is using the web cache (built into the webserver) as a means of transport and storage. The part that makes this really cockeyed is the use of the cache. The cache is not symmetrical, meaning (for instance) if you write a value to the interface, then the webinterface assumes that the IO pins reacted correctly. So, if you set a value and someone comes and changes the value behind the back of the interface, the interface will give you the value you wrote - not the real value of the device!

So, I would assume you would want the better speed and better control.

Do you have any questions?

Jesse

@jessemonroy650

thanks. I will try to speed up the Bridge. But what do you prefer to use instead of the key value storage (webcache) at all? I thought this would be the only/best option to communicate between ATMega and Linux. I found this thread (http://forum.arduino.cc/index.php?topic=188998.0), they talking about quite the same...

@schaefer_julian,
you can still use a key/value pair or JSON or even a REST API. I have done all - separately.

The difference is you will be parsing a string - which will add some slight overhead, but you will have more and better flexibility to run your keyboard (device).

So, if you take a look at the bridge tutorial. It will show you how to write a REST interface.

The only thing the bridge software does is pass the string to the Atmel processor. The reason it is sooo heavy is because the software does more than pass the string. It also maintains buffers, processes, a cache, and other interfaces - like mailbox.

Again the bridge software gives you 4 transactions per second. Is that good enough for a light show? If so, use the bridge - otherwise use something better.

Lastly, when you bypass the bridge software, you will be parsing a string. Make the string as simple or as fancy as you want.

Best of Luck
Jesse

jessemonroy650:
Again the bridge software gives you 4 transactions per second.

I keep seeing that number being thrown around, but nobody ever seems to have any proof to back it up. How are you getting that number? Or are you just repeating what you’ve heard without questioning it?

In my personal experience, I’ve never seen anything run that slowly using the Bridge. In addition, that statement doesn’t even say what part of the Bridge is so slow - there are many different things that the Bridge can do (key/value pairs, inter-process communications, mailboxes, network sockets, etc.) and some are more efficient for some applications than others.

That being said, storing/accessing key/value pairs on the bridge is just about the slowest thing that the Bridge does. I wouldn’t consider using it for an application like this. it’s great for storing status data, or setting infrequently changing control data. For example, almost every sketch I write stores the sketch’s name, version number, and build date to the Bridge as key/value pairs. I will sometimes store an overall health status or system state value. That way, all I need to do is fire up a web browser, point it at http://yun.local/data/get and immediately I can get a report on what is loaded on the Yun, and what it’s state may be. It is also useful for setting a control state, like a desired trigger value (think thermostat set point.) But I wouldn’t use it to convey rapidly changing data - besides speed, the Bridge key/value store has the limitation that it’s not possible for the receiving side to know when data was set, it can only see changes: if the same data is written twice in a row, the receiver will never see the second update.

For most cases of sketch/Linux communications, I use a Process object. The sketch starts a Linux process, and runs it asynchronously. The Linux process is in an infinite loop (just like the sketch) and never exits. Whatever the process prints to STDOUT, the sketch can read from the Process object, and whatever the sketch writes to the Process object, the Linux process can read from STDIN. This is much more efficient than the key/value store. It acts like a simple serial stream between the two processors. Bypassing the Bridge and talking directly over the serial port can give you a bit more speed, but it’s also more complicated. By using a Process object, you’re giving up a little bit of speed, but you can have multiple independent processes running, each with their own communications path, AND you can still use the other Bridge functions at the same time (things like the key/value store, Console class, TCP streams, mailbox, etc.)

For most applications, the Bridge and the Process class will be sufficient. In a few cases, one may want to bypass the bridge and use direct communications. However, in my mind, there are few scenarios where the key/value store is ideal.

Great! Thanks alot @ShapeShifter.
I found your example code regarding this here: http://forum.arduino.cc/index.php?topic=310623.0 and I did the same with Node.js. Cool!

One further question: What is the best method to send/read more complex data via the Process object. For example I'd like to send a midi note and its velocity combined. Is there something more elegant than reading this bit by bit?

I've not tried sending binary data through the Process object. I don't know if there are any reserved characters that would confuse the internal Bridge protocol. I've stuck with simple ASCII commands, or sending numeric values as decimal or hexadecimal ASCII string equivalents. Since a person isn't typing or reading the data directly, I try to come up with a concise encoding that takes a minimum number of characters, and is easy to parse. That often means fixed length messages with fixed character positions.

For example, suppose you need up to two digits for a note number, and one digit for velocity: Instead of sending a line like "Note=NN, Velocity=V" which is easy for a person to understand, I would instead send a packed value like NNV where the first two characters are always a note number (leading zeros if needed) and the third is the velocity. That makes it very easy to decode on the sketch side (where processing power and code space are limited) by looking for a line delimiter, reading two characters for the note, one character for the velocity, and then look for another line delimiter.

If you are doing any mapping of notes to LED output, or velocity to intensity, or anything like that, I would do all of that mapping on the Linux side. Make the sketch side as "dumb" as possible, so it does the minimum amount of work. Not only does that make things more efficient, but it minimizes the amount of data and the range of possible values. For example, if note implies output channel, and velocity implies intensity value, don't send the raw note value and velocity to the sketch, send the digested channel number and intensity values.

ShapeShifter:
I keep seeing that number being thrown around, but nobody ever seems to have any proof to back it up. How are you getting that number? Or are you just repeating what you've heard without questioning it?

In my personal experience, I've never seen anything run that slowly using the Bridge. In addition, that statement doesn't even say what part of the Bridge is so slow - there are many different things that the Bridge can do (key/value pairs, inter-process communications, mailboxes, network sockets, etc.) and some are more efficient for some applications than others.

That being said, storing/accessing key/value pairs on the bridge is just about the slowest thing that the Bridge does. I wouldn't consider using it for an application like this. it's great for storing status data, or setting infrequently changing control data. For example, almost every sketch I write stores the sketch's name, version number, and build date to the Bridge as key/value pairs. I will sometimes store an overall health status or system state value. That way, all I need to do is fire up a web browser, point it at http://yun.local/data/get and immediately I can get a report on what is loaded on the Yun, and what it's state may be. It is also useful for setting a control state, like a desired trigger value (think thermostat set point.) But I wouldn't use it to convey rapidly changing data - besides speed, the Bridge key/value store has the limitation that it's not possible for the receiving side to know when data was set, it can only see changes: if the same data is written twice in a row, the receiver will never see the second update.

For most cases of sketch/Linux communications, I use a Process object. The sketch starts a Linux process, and runs it asynchronously. The Linux process is in an infinite loop (just like the sketch) and never exits. Whatever the process prints to STDOUT, the sketch can read from the Process object, and whatever the sketch writes to the Process object, the Linux process can read from STDIN. This is much more efficient than the key/value store. It acts like a simple serial stream between the two processors. Bypassing the Bridge and talking directly over the serial port can give you a bit more speed, but it's also more complicated. By using a Process object, you're giving up a little bit of speed, but you can have multiple independent processes running, each with their own communications path, AND you can still use the other Bridge functions at the same time (things like the key/value store, Console class, TCP streams, mailbox, etc.)

For most applications, the Bridge and the Process class will be sufficient. In a few cases, one may want to bypass the bridge and use direct communications. However, in my mind, there are few scenarios where the key/value store is ideal.

sonnyyu:
Profile bridge speed:

Arduino Yun Bridge example from IDE.

ab - Apache HTTP server benchmarking tool

http://httpd.apache.org/docs/2.2/programs/ab.html

ab -n 20 -c 1 http://192.168.0.186/arduino/analog/2/123

Concurrency Level:      1
Time taken for tests:  3.425 seconds
Complete requests:      20
Failed requests:        0
Write errors:          0
Non-2xx responses:      20
Total transferred:      2100 bytes
HTML transferred:      0 bytes
Requests per second:    5.84 [#/sec] (mean)
Time per request:      171.275 [ms] (mean)
Time per request:      171.275 [ms] (mean, across all concurrent requests)
Transfer rate:          0.60 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median  max
Connect:        0    0  0.0      0      0
Processing:  164  171  7.9    169    192
Waiting:      153  159  6.2    156    171
Total:        164  171  7.9    169    192




171.275 [ms] (0.17 s) is average speed of bridge speed, and **should meet average application's requirement**.

Thanks @ShapeShifter. It works now. On the linux side I am now sending pin number and state, packaged as a string, via node.js to the process object. If there are several packages at the same time I can identify the end of a package at the Arduino side with the "." when reading the process object.

This is the node.js code

var osc = require('node-osc');

var client = new osc.Client('192.168.178.21', 9000); //Smartphone oder Laptop
var oscServer = new osc.Server(8000, '192.186.178.31'); //Arduino

oscServer.on("message", function (msg, rinfo) {

    var pin = msg[0].substr(1,msg[0].length-1);
    var state = msg[1];
    var output = String(pin + state + ".");

    process.stdout.write(output);

});

So this allows me to connect a specific midi note with a led within Ableton Live.

sonnyyu:
Profile bridge speed:

Arduino Yun Bridge example from IDE.

ab - Apache HTTP server benchmarking tool

%snip%

171.275 [ms] (0.17 s) is average speed of bridge speed, and should meet average application's requirement.

Thank you! But that shows a speed of 5.8 requests per second, which is 45% better than the 4 per second so often thrown around.

But the real issue is that this is comparing apples to oranges: it's measuring the absolute slowest way to make an external web request to the Yun (passing everything up to the sketch for processing) while the topic of discussion is how to communicate data between the Linux and sketch processors. The results of that benchmark are pretty much meaningless to this discussion (yes, I know you are not the one who introduced those results to this topic.)

The problem I see with that comparison being so widely used is that it's like saying that someone took an old worn out Yugo to the drag strip and turned in a pretty meager time. Based on that, the statement is made that cars are too slow: we should all use airplanes or rocket ships for basic transportation. Clearly a false statement.

While it may be true that that particular car is slow, it doesn't condemn all cars to that fate. A REST API implemented in the sketch is indeed slow - very easy to program, but slow. It's be of the slowest things that the Bridge does, but when ease of use is taken into account, it's a viable solution for many applications that don't need a lot of speed. One can get much better performance by implementing that API strictly on the Linux side - it's a bit more work, but not hugely so.

But fielding REST web requests is only one small facet of what the Bridge is able to do, and I think it's a disservice to condemn the whole library due to the limitations of one feature. Sure, there are faster ways to do everything, but not many that are easier to implement (especially for experienced Arduino programmers who don't want to delve into Linux) and many times it's plenty fast enough for the task at hand.

schaefer_julian:
So this allows me to connect a specific midi note with a led within Ableton Live.

Excellent! What kind of data rates are you getting, does it give the visual results you want?

I'm not familiar with node.js or the oscServer (which is why I didn't respond earlier.) That's not much code you posted, is that running on the Linux side? It looks like the note to pin mapping us being done by the node that is sending the data to the Yun, then the posted code is pretty much just a pass-through to the sketch? Looks very simple and elegant.

ShapeShifter:

Again the bridge software gives you 4 transactions per second.

I keep seeing that number being thrown around, but nobody ever seems to have any proof to back it up. How are you getting that number? Or are you just repeating what you've heard without questioning it?

::::SNIP::::

@ShapeShifter,
This is not my number. This is SonnyYu's number I believe I have linked to the article with that number.

Jesse

@schaefer_julian,
the most important part is you have a working solution you like and can work with.

All the Best
Jesse

jessemonroy650:
@ShapeShifter,
This is not my number. This is SonnyYu's number I believe I have linked to the article with that number.

Yes, and please see my response in reply #11 which explains why that number is not only wrong, but has nothing to do with this topic.

ShapeShifter:
Very interesting! Thank you for posting this alternative.

But I'm not sure where you get the 4 transactions per second? There may be things you can do with the Bridge (like synchronously run a long Process) that might be that slow, but the code you posted is essentially a replacement for the Console class, and I've never seen it be that slow. I've slightly modified your code to use the Console class (added Bridge.begin() and Console.begin() instead of Serial1.begin()) and changed all other instances of Serial1 to Console. When I run that code, I get 34 lines per second.

Yes, 34 lines per second is slower than 878 lines per second, ...

The fastest speed bridge from you sample is 34 samples per second, but compare with Linux Industrial I/O Subsystem's ~100k samples per second is deadly slow. Linux Industrial I/O Subsystem is scalable, in other word could go faster than 100k.

ShapeShifter:
Yes, and please see my response in reply #11 which explains why that number is not only wrong, but has nothing to do with this topic.

@ShapeShifter,
yes, I re-read. In retort, the obvious question when seeing these low numbers is "how do I make it faster?" Which is where the conversation needs to go.

However, I take your point. I will make add a literal exclusion clause that should make the comments clear, fairer, and achieve the same purpose - of steering the conversation.

Thanks for the feedback
Jesse