Arduino Forum

Products => Arduino Yún => Topic started by: e-existence on Sep 20, 2013, 04:00 am

Title: Using BridgeClient in Python Scripts.
Post by: e-existence on Sep 20, 2013, 04:00 am
This took me an afternoon to figure out, so I figured I would post it here hoping that others could use it. I have a project where I plan to pass values between the Arduino and the Linino environments and BridgeClient.py seemed to be the right way to go about it...


Code: [Select]

#!/usr/bin/python

import sys    
sys.path.insert(0, '/usr/lib/python2.7/bridge/')
                                               
from bridgeclient import BridgeClient as bridgeclient
                                                   
value = bridgeclient()                              
                                                   
value.put('key','value')
                         
print value.get('key')


Title: Re: Using BridgeClient in Python Scripts.
Post by: dreggy on Sep 20, 2013, 10:19 pm
Nice, this is very useful.
This seems to be the less memory eating method to access variables in every environment (Arduino, python and javascript using ajax)
Title: Re: Using BridgeClient in Python Scripts.
Post by: scrot on Sep 23, 2013, 08:19 am
Do you have the sketch that goes along with this?  I'm having a heck of a time setting up 2 way communications between a sketch and a python program.  The Process library "write" function doesn't appear to work.  Also its missing several of the variations mentioned in the documentation (i.e. ability to write strings, ...).

Thanks in advance.  The software doesn't feel quick baked yet.  I'm trying to basically make the arduino be a slave to the lineo side so that I can do all of my programming in Python.
Title: Re: Using BridgeClient in Python Scripts.
Post by: e-existence on Sep 23, 2013, 04:06 pm
The Arduino code that I am currently using is as follows (I can't make any claims to it completeness, but it is working... )

Code: [Select]

#include <Bridge.h>

char D12value[2];

void setup() {
  pinMode(12,OUTPUT);
  Bridge.begin();
}

void loop() {
  Bridge.get("D12",D12value,2);
  int D12int = atoi(D12value);
  digitalWrite(12,D12int);
  delay(50); 
}


On the Linino/Python side `value.put('D12','0')` or `value.put('D12','1')` will set the mode of Pin D12 on the Arduino...

There is an example of Bridge.put() in the "Bridge" example included with the Ardunio IDE.

For what its worth... this is all early proof of concept code... ultimately I am looking for

Android App -> HTTPS/cgi-bin/python -> bridge -> Arduino/D12 -> Power Switch Tail -> Grundfos Hot Water Loop Pump.

I am currently learning just enough Android Application Development to trigger the HTTPS calls....
Title: Re: Using BridgeClient in Python Scripts.
Post by: scrot on Sep 23, 2013, 07:27 pm
Excellent.  Thank you.  Now for a more difficult question.   :)

Can you do a Bridge.put() back up to your Python program?  I have not been successful at this.  I've read all of the source code for the Arduino Bridge, the Linio Bridge, and the Python BridgeClient, and no luck. 

Thanks again.
Title: Re: Using BridgeClient in Python Scripts.
Post by: e-existence on Sep 23, 2013, 09:24 pm
I have not written anything that uses Bridge.put() on the Arduino side. It is used in the Bridge example included with the Arduino IDE.

Code: [Select]

  if (client.read() == '/') {
    // Read value and execute command
    value = client.parseInt();
    analogWrite(pin, value);

    // Send feedback to client
    client.print(F("Pin D"));
    client.print(pin);
    client.print(F(" set to analog "));
    client.println(value);

    // Update datastore key with the current pin value
    String key = "D";
    key += pin;
    Bridge.put(key, String(value));
  }
Title: Re: Using BridgeClient in Python Scripts.
Post by: scrot on Sep 24, 2013, 08:39 pm
Just for you information.  I kind of got the Bridge.put() code to work... kind of.  It is very flakey and only works some of the time.  Also I found that it is easy to crash the Bridge process running on linino.  Just put a non-string and it will crash.  There isn't much in the way of exception handling.  I'm continuing to see if I can make it more reliable.  Its very difficult since the serial monitor behaves more erratically on Yun than on Uno.
Title: Re: Using BridgeClient in Python Scripts.
Post by: e-existence on Sep 25, 2013, 03:47 pm
Interesting, for what its worth, I am "reading" ie: bridge.get() on the Arduino side ever half second and "writing" value.put() at least twice a day and am having no trouble.

Just checked uptime, 7 days now.. no issues...

If you can provide code examples, I wouldn't mind looking it over/testing.

Title: Re: Using BridgeClient in Python Scripts.
Post by: scrot on Sep 26, 2013, 06:55 am
Ok.  I've now gotten it to work reliably.  However it is very, very slow.  I'm only seeing about 4 get/puts per second, or a little over 1 transaction per second between my python program and my sketch.  Is there a faster way other than writing my own bridge?

I'm asking because I want to do all of my programming using the arduino as a slave to my python program.  I want to do my programming in Python on the Linino side.  To do this I need at least 10 transactions per second, I'd like 100 if I could.

When I looked at the BridgeClient.py I found that in the end it was setting up a new socket to the local port for every get or put.  Very inefficient.  Indeed it isn't much faster than using the Bridge REST interface from a remote computer.

I'm looking for performance similar to what I was seeing in my old Raspberry Pi <-> Uno combination using Firmata.

Any ideas?  (Just so you know I'm having a blast regardless of how it sounds.)
Title: Re: Using BridgeClient in Python Scripts.
Post by: wpunkts on Oct 15, 2013, 01:52 pm
I might have an idea....

I've spent the last couple of days on the same problem. The goal is to have a Python script that listens to OSC messages from an application on my phone, and to pass on values retrieved from some of the messages to control PWM pins. Getting the Python script to run properly was surprisingly straightforward, given my (lack of) Linux and Python skills. So far, the script reads floats between -127 and +127 from two faders and sends the values back to the phone, where they're displayed in two text boxes as feedback.

All this works very fast and smooth. Excellent.

Then I tried to pass on the values to the Arduino sketch. I had been hoping that runShellCommandAsynchronously() would do the job, but apparently that's not possible. At least I couldn't get it to work.

After many, many hours of trying all kinds of things I found this thread. I managed to get it working, but, as mentioned above, the speed is simply unacceptable. However, using code from bridgeclient.py I was able to speed it up significantly. Adding
Code: [Select]
from bridgeclient import BridgeClient as bridgeclient
json = TCPJSONClient('127.0.0.1', 5700)
to the script, and replacing
Code: [Select]
value.put('D13','%i' % (fader1Feedback)) with
Code: [Select]
json.send({'command':'put', 'key':'D13', 'value':'%i' % (fader1Feedback)}) did the trick. Avoiding opening and closing a socket for every put is the key.

This will need a lot more testing and refining, but so far it looks promising.

Here's the relevant part of the script. Hope it's helpful.

Code: [Select]
#!/usr/bin/python

import OSC
import time, threading
import sys   
sys.path.insert(0, '/usr/lib/python2.7/bridge/')
                                               
from bridgeclient import BridgeClient as bridgeclient
from tcp import TCPJSONClient
                                                     
value = bridgeclient()
json = TCPJSONClient('127.0.0.1', 5700)

receive_address = ('192.168.1.144', 12345)

s = OSC.OSCServer(receive_address)

client = OSC.OSCClient()

s.addDefaultHandlers()

fader1Feedback = 0

# define a message-handler function for the server to call.
def printing_handler(addr, tags, stuff, source):
    global fader1Feedback
    global fader2Feedback
    if addr=="/1/fader1":
    fader1Feedback = int(stuff[0])
    msg = OSC.OSCMessage("/1/label2")
    msg.append('0')
    msg.insert(0, fader1Feedback)
    client.sendto(msg, ('192.168.1.109', 1234))
    print "%i" % fader1Feedback
    #value.put('D13','%i' % (fader1Feedback))
    json.send({'command':'put', 'key':'D13', 'value':'%i' % (fader1Feedback)})

       
Title: Re: Using BridgeClient in Python Scripts.
Post by: federicofissore on Oct 15, 2013, 03:40 pm
I've just opened an issue on bridge github https://github.com/arduino/YunBridge/issues/4
Anyone willing to code something similar and provide a pull request?
Title: Re: Using BridgeClient in Python Scripts.
Post by: mrk_b on Nov 02, 2013, 09:28 pm
Hi everyone.
I'm working on a project and i would like to implement all the control law and filters in the faster AR9331 microprocessor on a python script rather than in the mcu, but I'm fighting with the issue of the laggy "bridge method" to excange data between the mcu and the linino side.
It would be really a pity if I could not use the powerful microprocessor to do computation just because of the latency in the comunication between the linino side and the atmega.
I tried the advice posted by wpunkts, it enhances the performance respect the built-in "BridgeClient" method, but not enough.
Did someone figure out how to speed up the bridge?
Anyone have some other hints?
Thank you!
Title: Re: Using BridgeClient in Python Scripts.
Post by: federicofissore on Nov 03, 2013, 09:19 pm
Is the delay you're experiencing happening on the mcu or cpu side? If it's the mcu, take a look at this http://forum.arduino.cc//index.php?topic=192823.msg1448287#msg1448287
Title: Re: Using BridgeClient in Python Scripts.
Post by: mrk_b on Nov 04, 2013, 08:21 am
Thank you Federico for answered me.
Yes, i think the delay that i'm experiencing is on the mcu side.
I'm looking at your suggestion, isn't it related to the REST call?
Does it works even if I wanna use directily the bridge acces trough a Python script?
Sorry I'm a little bit confused about REST call (via browser?) and the lets say "normal use" of the bridge (bridge.get, bridge.put).
Thank you!
Title: Re: Using BridgeClient in Python Scripts.
Post by: federicofissore on Nov 04, 2013, 03:42 pm
My suggestion is related to the use of YunClient and YunServer. Bridge.get and put are not affected
Title: Re: Using BridgeClient in Python Scripts.
Post by: mediamad on Nov 08, 2013, 12:15 am
I don't understand (probably because of the noob factor).  There's a serial connection between the two sides.  Why is it not possible to just pass data on it monitoring in python on one side and in the sketch on the other?
Title: Re: Using BridgeClient in Python Scripts.
Post by: mamu on Nov 08, 2013, 06:48 am

I don't understand (probably because of the noob factor).  There's a serial connection between the two sides.  Why is it not possible to just pass data on it monitoring in python on one side and in the sketch on the other?

I came up with the same thoughts and asked the same question in another thread.
Why all this bridge class heck? Why not simply using the well know Serial in the sketch and having access on the Linino site with JSON and WebSockets like node.js offers?
Title: Re: Using BridgeClient in Python Scripts.
Post by: federicofissore on Nov 08, 2013, 10:17 am
What kind of performance are you expecting? Maybe you'll find this discussion (http://forum.arduino.cc/index.php?topic=191820.0) interesting
Title: Re: Using BridgeClient in Python Scripts.
Post by: mediamad on Nov 08, 2013, 02:48 pm
Very interesting indeed.  Kind of surprised this wasn't already taken care of via library upon release.  Seems a no brainer if using the Arduino as a dumb I/O.  Throughput in most cases would be a non issue.
Title: Re: Using BridgeClient in Python Scripts.
Post by: federicofissore on Nov 08, 2013, 05:36 pm
If you're suggesting we should change some library and have working code to share, I'm eager to test it
Title: Re: Using BridgeClient in Python Scripts.
Post by: OPtoss on Jan 11, 2016, 03:41 am
This post helped me track down the issue. Thanks to wpunkts the true reason for the lag is brought to light:

Quote
Avoiding opening and closing a socket for every put is the key.
Now as of how to resolve it, I found that the bridgeclient.py already has an answer, but it's not obvious or well documented.

Code: [Select]

// Init a bridge client
client = bridgeclient()
// Flag it to not open and close the socket every function call
client.begin()


A quick peek at the source reveals that's what begin does. And indeed it appears to have the same performance as your json client, but for some reason my values weren't saved with that approach, and I'd like to trust the lib where I can.

Hope this helps some one else with this problem!
Title: Re: Using BridgeClient in Python Scripts.
Post by: jfourie on Jan 11, 2016, 04:41 am
Is there a way o do the same on the Python side? I find it also slower to do gets.  Also I found that if you read the bridge to fast you get wrong values back. Is there a way to read it fast and not break it from the Linux side using Python.
Title: Re: Using BridgeClient in Python Scripts.
Post by: steinvb12 on Jan 26, 2017, 03:54 am
The "put" command you post is working great for me in the python script.

Code: [Select]
json.send({'command':'put', 'key':'testjson', 'value':'jsonvalue'})



However, the "get" command returns a null (None) value. What am I missing?

Code: [Select]
jsonData = json.send({'command':'get', 'key': 'testjson'})