Getting result of PyRun_String when python code returns an object

223 views Asked by At

i have a problem with my code. i have a python file for the capturing of mavlink messages(i'm using pymavlink library) and i need to create a library for interfacing python results with c/c++ code. this is my python code from .py file

from pymavlink import mavutil

the_connection = mavutil.mavlink_connection('udpin:localhost:14550')

the_connection.wait_heartbeat()
print("Heartbeat from system (system %u component %u)" % (the_connection.target_system, the_connection.target_component))

while 1:
    
    attitude=the_connection.messages['ATTITUDE']
    print("attitude: ",attitude)

i need to recover the attitude object as PyObject, the result of the last print is:

attitude:  ATTITUDE {time_boot_ms : 1351674, roll : -0.006938610225915909, pitch : -0.009435104206204414, yaw : 1.8100472688674927, rollspeed : 0.0005244240164756775, pitchspeed : -0.0023000920191407204, yawspeed : 0.0002169199287891388}

i have a streaming of messages, so i need to call the connection and the to evaluate the result in a loop. so i tried to call the simple python commands as string, to open the connection and then access to the data. My C code is:

Py_Initialize();
                
PyRun_SimpleString("from pymavlink import mavutil\n"
                "the_connection = mavutil.mavlink_connection('udpin:localhost:14550')\n"
                "the_connection.wait_heartbeat()\n"
                "print(\"Heartbeat from system (system %u component %u)\" % (the_connection.target_system, the_connection.target_component), flush=True)" );
    
PyObject* main_module=PyImport_AddModule("__main__");
PyObject* pdict = PyModule_GetDict(main_module);
PyObject* pdict_new = PyDict_New();

    
while (1) {
        
    PyObject* pval = PyRun_String("the_connection.messages['ATTITUDE']", Py_single_input, pdict, pdict_new);
    PyObject* repr = PyObject_Str(pval);

    PyObject* str = PyUnicode_AsEncodedString(repr, "utf-8", "~E~");
    const char* bytes = PyBytes_AS_STRING(str);

    PyObject_Print(pval, stdout, 0);
    printf(" end\n");

    Py_XDECREF(repr);
}
    
Py_Finalize();

the result of this code is:

<pymavlink.dialects.v20.ardupilotmega.MAVLink_attitude_message object at 0x7fba218220>
None end
<pymavlink.dialects.v20.ardupilotmega.MAVLink_attitude_message object at 0x7fba218220>
None end
<pymavlink.dialects.v20.ardupilotmega.MAVLink_attitude_message object at 0x7fba218220>
None end
<pymavlink.dialects.v20.ardupilotmega.MAVLink_attitude_message object at 0x7fba218220>
None end

i've tried using a return of the object, but it didn't work

PyObject* pval = PyRun_String("return(the_connection.messages['ATTITUDE'])", Py_single_input, pdict, pdict_new);

i'm not expert of C/C++, is there a way to obtain the result in the right way?i'm not interested in a string format, i only need a way to use the result as c object

i'm using python 3.9, on a raspberry pi, gcc version is 10.2.1. thank you

1

There are 1 answers

5
DavidW On

You want

PyRun_String("the_connection.messages['ATTITUDE']", Py_eval_input, pdict, pdict_new);

Py_eval_input treats it like the Python builtin eval (so what you're running must be an expression rather than a statement, which it is...).

In contrast, Py_single_input evaluates a single statement, but just returns None because a statement doesn't necessary returns anything. (In Python all expressions are statements, but not all statements are expressions). It's more akin to exec (but only deals with a single line).

Using "return(the_connection.messages['ATTITUDE'])" doesn't work because return is specifically designed to appear in a Python function.