Go Down

Topic: how to get response from python script running on Yun (Read 1 time) previous topic - next topic

katesfb

Hi,
I have a sketch running on the Yun that runs a couple of python scripts on the linux side. The first python script doesn't do much - its really setup as a test to get a response i can see in the serial monitor, and this works fine. The second python script runs a loop that continually creates random tags, logs them to the SD card and prints out the tag. The script itself works and and when i run the sketch it logs correctly however i am not able to see teh tag in the serial monitor. I am using the runshellcommandAsynchronously() method so that i can get the responses without having to wait for the process to end.

Any help is much appreciated.

The code example is bellow.

Cheers. 

Code: [Select]

#include <Bridge.h>
#include <Process.h>

Process p;

// Path
String path = "/mnt/sda1/";

void setup() {
  // Initialize the Bridge and the Serial
  Bridge.begin();
  Serial.begin(9600);
  SerialUSB.begin(9600);  // Initialize the Serial

  while (!SerialUSB); // wait for Serial port to connect.
  SerialUSB.println("Yun Logging Test 2\n");

  SerialUSB.println("Setup test");
  p.runShellCommand("python " + path + "loggingSetup.py");
  while(p.running());
 
  // read the output of the command
  while (p.available() > 0) {
    char c = p.read();
    //if (c != '\n') result += c;
    SerialUSB.print(c);
  }

  SerialUSB.println("Start logging");
  p.runShellCommandAsynchronously("python " + path + "logging.py");

  if (p.running()) {SerialUSB.println("python script is running");}
 
}

void loop() {
    // read and display the output
    while (p.available() > 0) {
      char c = p.read();
      //if (c != '\n') result += c;
      SerialUSB.print(c);
    }
}

ShapeShifter

Instead of this:

Code: [Select]

  p.runShellCommandAsynchronously("python " + path + "logging.py");


Try this:

Code: [Select]

  p.runAsynchronously("/usr/bin/python -U " + path + "logging.py");


There are two changes here. The first one is the important one: adding the "-U" option to the python command line tells Python to run in unbuffered mode. Normally, Python buffers its output until it fills up a rather large buffer, or the process terminates. Your first Python call worked because the process terminated and released its output. The second process is working, but if the output is sporadic it can take a long time to fill the buffer. During that time you will see nothing. Once the buffer is full you will see a sudden surge of output, and then nothing again until the buffer fills once more.

The second change is not needed to make it work, but it is more efficient. The runShellCommandAsynchronously() call is starting a process to run a command interpreter shell, which then parses your command line, searches the path for the Python executable, and then launches Python. On the other hand, runAsynchronously() takes the command line you give it and runs it directly, without starting another command shell. The outcome is the same, but it's more efficient.

katesfb

Hi Shapeshifter,
You were exactly right - where i thought nothing was happening was actually the buffer filling up so when i left it for long enough it eventually displayed the output.

I will make the suggested changes and let you know how i get on.

Your reply is much appreciated.

Cheers.

ShapeShifter

I spoke from personal experience - much the same thing happened to me: I thought it wasn't working and couldn't figure out why. I got interrupted by something else for a while, and didn't unplug the unit or close the serial monitor. When I came back, there was a screen-full of text once the buffer had filled. That made me think that it was buffering, so I searched for a way to have unbuffered output. Fortunately, the ultimate fix was easy.

Now, as a matter of course, I explicitly enable unbuffered mode any time I use the Process class to start a Python script. Never had a problem since.

Knelf

Oh no.... if I am right... I've just figured out something fundamentally important about the Bridge class (as a result of reading this) that I hadn't realised and have been consequently been all over the shop trying to find a solution for...  

Well... if I'm right, I'm not sure even a triple face palm is going to cut the mustard.  

On the positive side, I guess I potentially learnt something on my travels to "The land of totally unnecessary and overcomplicated"!

I'll be back...

Knelf

Urggh.... so I was right... I real face palm moment.

Still, on the upside I did learn a reasonable bit about how the bridge library operates behind the scenes so it isn't this "magic box" of a piece of code that it initially appeared as.

I now have 2 way binary exchange between my python program on the Atheros, and what runs on the Atmel.

Good times! I can finally progress. I guess I should update my dev env too... ^_^ the version I've got doesn't take parameters for runAsynchronously ;)

Cheers for making this thread. While not related to my specific issue, it did allow me to work out where I was going wrong!

Much appreciated

Knelf

Go Up