Go Down

Topic: Call arduino function FROM Python (Read 3051 times) previous topic - next topic

Ale_bo

Hi,

on Arduino sketch I've a simple function like:

void test() {
  pinMode(12,OUTPUT); 
}

It's possible to call this function FROM python script?


Thank you

ShapeShifter

In a word, no.

Python and your sketch are running on two different processors, so there is no way for Python to directly call a function in your sketch.

That being said, there is a serial port connection between the two processors, and there are a variety of ways to send commands from one processor to another. Sending a command from the sketch to run a command on the Linux side (where Python runs) is fairly trivial. Going the other direction from Python to the sketch is more involved.

If you give us an idea of what you are actually trying to accomplish, we can give more detailed suggestions on an approach.

Ale_bo

Ok, I try to explain as best I can.
I'm testing on OSC communication APP.
The scenario is:
On OSC APP on my phone I've a button. When this button is pressed a python script running on the linino has to call a function on .ino that read the status of all digital pin and send back a string with all pin values to OSC APP.

I try to do this with REST API calls from python but first of all I don't know if it works and if it's the best way to do that.


Before the OSC implementation on python I'm trying in this way:
------------------------------------------------
PYTHON SCRIPT: Note the import of urllib2
------------------------------------------------

#!/usr/bin/python
import urllib2
url = 'http://arduino.local/arduino/stato/99'
response = urllib2.urlopen(url).read()
print "%s" % response



-----------------------
ARDUINO SKETCH
-----------------------
#include <Bridge.h>
#include <YunServer.h>
#include <YunClient.h>

int DigitalPin[] = {2, 4, 7, 8, 9, 10, 11, 12, 13};

YunServer server;

void setup() {
  Bridge.begin();
  server.listenOnLocalhost();
  server.begin();
}

void loop() {
 
  YunClient client = server.accept();
  if (client) {
    process(client);
    client.stop();
  }
  delay(50);
}

void process(YunClient client) {
  String command = client.readStringUntil('/');
  if (command == "stato") {
    check(client);
  }
}

void check(YunClient client) {
  int pin, value;
    client.print(F("check"));
    for (int thisPin = 0; thisPin < 9; thisPin++) {
        pin = DigitalPin[thisPin];
        value = digitalRead(pin);
        client.print(F("#"));
        client.print(pin);
        client.print(F("="));
        client.print(value);
        }     
    client.println("");
}   

ShapeShifter

What calls the Python script? Can that make the REST call directly?

Your comment says "before OSC implementation", what will change after implementation?

Will the sketch be doing anything else besides looking for incoming REST calls? If not, how about having the sketch constantly read the status and call Bridge.put()? The Python can then get() the status from the bridge whenever it is needed without having to send something to the sketch and waiting for a response.

Ale_bo

Hi,

the python script is in background, executed when the system boot. It wait for OSC command.
I think that Bridge.put solution could be a good idea.

Do you think something like this? I'll try this. I think that it works, but I'm also curious to try calling an arduino function from python. It could be useful in many cases.

-----------------------------
ARDUINO SKETCH
-----------------------------

#include <Bridge.h>


void setup() {
  Bridge.begin();
 
}

void loop() {
  check();
  delay(10); 
}

void check() {
  int value;
  value = digitalRead(7);
  Bridge.put("D7", String(value));
}


-----------------------
PYTHON OSC CODE:
-----------------------

# -*- coding: utf-8 -*-
from OSC import OSCServer,OSCClient, OSCMessage
import sys
from time import sleep
import types
sys.path.insert(0, '/usr/lib/python2.7/bridge/')

from bridgeclient import BridgeClient as bridgeclient
                      
server = OSCServer( ("192.168.240.1", 8000) )
client = OSCClient()
client.connect( ("192.168.240.206", 9000) )
value = bridgeclient()

def handle_timeout(self):
   print ("Waiting for OSC Message")

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

def Pin7Readbutton(path, tags, args, source):
    global Pin7Readbutton_Feedback
    if path=="/1/button2":
        Pin7Readbutton_Feedback = value.get("D7")
        msg = OSCMessage("/1/label3")
        msg.insert(0, Pin7Readbutton_Feedback)
        print "%i" % Pin7Readbutton_Feedback
        client.send(msg)

server.addMsgHandler( "/1/button2", Pin7Readbutton)

while True:
   server.handle_request()

server.close()




ShapeShifter

It would be very helpful if you posted your code in code tags: above the post editor is a row of buttons, where the one that looks like a scroll with blue angle brackets will insert the tags, ready for you paste your code between them.

Something along those lines should work for the put/get operations. You may want to put some test on the Python side in case it doesn't get() a proper value.

I'm not familiar with OSC, is there a way for the request to go directly to the sketch rather than going through Python first?

I'm also curious to try calling an arduino function from python. It could be useful in many cases.
This is the opposite way from which the Bridge normally acts: it tends to put the sketch in control, and the Linux side acts as a server, bending to the will of the sketch.

One way to accomplish putting the LInux side in control would be to not use the Bridge library. Instead, use raw serial communications between the two processors. To "call" a function, the Python script would send a serial string to the sketch, the sketch would decode the command and perform the operation, and send a response string back. The Python code would have to wait for the response, or otherwise be set up to handle asynchronous responses. To do something like this, don't use the Bridge library, instead open Serial1 in the sketch, and ttyATH0 on the Linux side.

Go Up