Not able to run Python script from Arduino program

I have a python script "evdev.py" for keyboard accessing in the root directory.

If I give command "/root/evdev.py /dev/input/event1" in Putty, it is working well.

If I try to run the same using arduino program (code mentioned below), it is not responding.


Process p;
p.begin("python");
p.addParameter("/root/evdev.py");
p.addParameter("/dev/input/event1");
p.run();
if (p.available() > 0)
{
char keyboard_code[BUFF_LEN];
int code_len;

code_len = Bridge.get("to_arduino", keyboard_code, BUFF_LEN);

if(code_len!=0)
{
Serial.println(keyboard_code);
}
}


Am I did anything wrong in my coding? Suggestions please.

Try using p.runAsynchronously() instead of p.run().

Your python script remains in a running state, so your sketch hangs at p.run because it waits the end of the process. If you use the asynchronous method the script will run in background and your sketch moves on.

You have an interesting construct starting on the line after p.run(): you check to see if there are any characters returned from the process, and if not, you do nothing. Keep in mind that if you change run() to runAsynchronously(), odds are that there won't be any output available instantly. If your script generates any output, you will have to keep polling for it until it's available.

However, if there is a character available, you never read it. Instead, you call Bridge.get() to read the value of the "to_arduino" key. Presumably, the value is set by your Python script using a corresponding put() call. Will that value have been set by the time the script writes out it's first character? If not, you will either not get any data (if this is the first time through this path) or will get the data from the last execution if this is a subsequent time through this code. Keep in mind that once you "put" something to the bridge database, it stays there until the Linux side is reset. So if you are expecting to not get anything sometimes (I guess this because of your check for a non-zero result from get()) that check will only work until the first time it is put(). Any time after that, you'll read the last put() value, even if the script didn't set anything during the current invocation.

Synchronizing execution between two processors can be tricky. Make sure you've thought it all through carefully - it seems that might not be the case here. It is an an usual case for the output of a process (any output, or the lack thereof) to trigger reading from the bridge. Normally, one would pass values back from the script by writing to STDOUT and using p.available() and p.read() to read it, or one would use Bridge.put()/get() calls, not a mixture of both.

Thanks Mr.Shapeshifter. I understand my mistake I did. But, I wish to clear this issue.

Actually I wish to get the "to_arduino" key value using Bridge.get() method. That value was put by the evdev.py python program. I place this in the /root/ folder. I have attached the python program I used for Keyboard interfacing (I got this program from this forum).

Kindly suggest the way to run the python program from the arduino and get the key value.

Thanks.

evdev.pdf (23.7 KB)

Before worrying about how to do one particular construct, it's always best to start with the requirements: a clear concise statement of just what you are trying to accomplish. Then, when you clearly know WHAT you want to do, you can start to figure out HOW to best do it.

From the Python code, it looks like you are trying to capture events from some sort of keyboard/throttle/joystick flight simulator interface. As such, I'm pretty sure you want to keep receiving events from the Python code and not stop after just one. Once you have the event into the Arduino code, then you will do something useful with it, but for now you will just print it out to the serial port so that you can verify that you are getting the codes - a wise first step.

Does that sound about right? If so, you will need to organize the code a little differently. Besides my initial comments, the other issue with the code is that you start the process, wait for one character back, read one data item (which will probably not be set yet) then exit. As is, you won't get multiple events, if any. And if what you have is inside loop() then you will be starting the Python script through every iteration, which is not what you want since the Python has it's own infinite loop to keep processing multiple events. And, as previously mentioned Bridge.put/get is not a good communications method for this task, since you don't know when a new value is set, only that it changed (you won't be able to detect the same event twice(or more) in a row.)

So it's clear to me that you want to start the script in setup() and keep looking for events in loop(). This means that your Process object p needs to be declared at a global level, outside of and before setup() and loop() so that both functions can access the same object. Then, in setup() you need to do the initial begin, parameter, and runAsynchronously calls. (Angelo9999 has it exactly right - because the Python has an infinite loop, it will never terminate, so p.run() will never return. You MUST call it a synchronously.)

With the process started in setup(), then in loop() you will want to check for available characters. When a character is ready, read it and add it to a character array buffer. When a complete event string is received, then decode the event and act on it.

I would start with baby steps:

  • Start with the original Python code, without the Bridge calls
  • Manually run the script from the command line and make sure it gives good data. Don't bother doing ANYTHING with the Arduino side until this part works - nothing you do in the Arduino code will fix the Python script if it doesn't work. It would be helpful for future steps if you post the output of the Python script while you are creating some of the events you want to process, this will make it easier to figure out how to parse the data and identify the beginning/end of an event string. This step lets you know the Python is working, and shows you the data you need to process.
  • Once it's working at the command line, move to the Arduino code. Start the process in setup() and in loop() just check for a character available and if so read it and simply write it the serial port. Run it and generate more events. The goal is that the serial output should look identical to the output from when you ran the script on the command line. This step shows that you can properly transfer the data to the Arduino code.
  • Now that you know that you can get the data into the Arduino code, and what it looks like, add the code to buffer the incoming characters and detect the end of the event string. When you get a complete string, print it to the serial port. Run it and generate events, making sure they are printed properly. This step shows you can properly buffer and recognize complete events.
  • With all of that working, you can finally add the code to recognize and act on the desired events.

There are a lot of things that all have to interact together to make this work. If you try to do it all at once, there will likely be a problem somewhere, and it'll be hard to tell just where. By doing it one step at a time, and only adding one feature at a time, you break it up into a set of small steps. If something goes wrong at one of the steps, it's much easier to figure out what it is.

Good luck, and let us know what the output from Python looks like, and we can probably give some tips on how to parse it.

Dear Mr.ShapeShifter,

I have attached my programs and results with this.

I'm facing one issue. When trying to get result in Arduino Serial Monitor, If I press the keyboard keys 10 times, then it is showing accumulated results.

But in PuTTY terminal, for each and every key, python is responding instantly.

Why & How this is happened? How to solve this?

arduinoWithPython.pdf (243 KB)

evdev.pdf (60.6 KB)

sridevi:
When trying to get result in Arduino Serial Monitor, If I press the keyboard keys 10 times, then it is showing accumulated results.

I don't know what you mean by "accumulated results." The output looks good, but I can't see the timing or how it correlates with what you are actually doing.

But in PuTTY terminal, for each and every key, python is responding instantly.

Is that PuTTY doing the SSH connection, or when you try it connected to COM14 in lieu of the serial monitor. If you are seeing strange things in the serial monitor, the first thing I would try is close that and use PuTTY to connect to the serial port - the serial monitor is not the best terminal emulator.

Hai Mr.ShapeShifter,

What I mean is,

If I press the letter 'A' in my keyboard, immediately I get the result in Putty. But in Arduino program, I am not getting any result for this.

But if I enter 'APPLEAPPLE', this word contains 10 letter totally, at the end of entering tenth letter, I get result for each and every ten characters (First for A, next for P, next for another P, next for L, etc.)

The Python program may store the results and send to Arduino at the end of getting 10th character.

Is it due to the buffer in Python program?

If so, how can I change this. I wish to get the immediate response for every character in Arduino program.

Kindly share your suggestions.

Putty works as a direct bridge between the Linino terminal and your computer so every time your python script writes to stdout the same will appear inside putty instantly.

If you use the Bridge get and put you are using the Bridge library to share data so the mechanism is different. Can you give us the program you use to read data from Arduino and the sketch?

Mr.Angel,

You can find my arduino program in this attachment.

arduinoWithPython.doc (134 KB)

The file you attached is empty, can you post it again?

I have attached the pdf version of the same.

arduinoWithPython.pdf (245 KB)

Try to put the Serial.flush inside the while loop, if the data comes too fast you will wait a bit before exiting from the loop.

I tried that. There is no effect.

Very interesting...

I've sometimes seen the Arduino serial monitor act strangely... Try closing the serial monitor, and use PuTTY to open COM14 and see if that makes a difference. It probably won't, but it's worth a try to make sure it's not caused by the serial monitor.

Do you have a spare LED and resistor? Hook it up between pin 0 (Rx) and 5V, and it will blink whenever the Arduino side receives data from the Linux side. (It needs to go from 5V so that it lights only when the line goes low -- if you connect the LED to ground it will always be on and only go off when data is being sent, and that's hard to see.) See the attached for a Fritzing diagram.

When you run your sketch, what does the LED do? Does it flash with each event? Or does it only flash when you've sent the 10 events? This may help narrow down where the buffering is happening.

Solved the issue. Finally I run the python script from my arduino and got the value using bridge.get command. Now there is no delay. Responding immediately.

Thanks for all of your support.

Please tell so what you did to fix it, and what was causing your delay. Besides my curiosity, it may help the next person who has a similar problem.