0

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

Holt
  • 36,600
  • 7
  • 92
  • 139
MaryG
  • 3
  • 4

1 Answers1

0

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.

DavidW
  • 29,336
  • 6
  • 55
  • 86
  • ok, i'm understanding. i've tried with eval but i wasn't able to recover the python Object. i think that the result of my python script is not a String(it should be an array), so i tried loading a function : `altitude= the_connection.messages['ATTITUDE']). s = "attitude: "+str(attitude.time_boot_ms) ). print(s, flush=True)). return s` , but i'm not sure of the correct function to run this code. maybe should i use another function? – MaryG Jan 13 '23 at 08:55
  • That isn't a function because it isn't defined with `def xxx()` – DavidW Jan 13 '23 at 09:10
  • but can i use the PyRun_String function to load this function? or i should use pyObject_CallObject? i've tried this function loading a .py file with the definition of function, but i had some problems with the argument of the function itself. do you have an example of directly invoking a function without loading a py file? thank you very much – MaryG Jan 13 '23 at 09:26
  • my function is defined in a .py file as `def altitude_data(the_connection): altitude= the_connection.recv_match(type='GLOBAL_POSITION_INT') s2="altitude: "+round(altitude.relative_alt/304.8) return(s2)` and i'm invoking it with `PyObject* pFunc = PyObject_GetAttrString(pModule, "altitude_data"); PyObject* args = PyTuple_Pack(1,PyUnicode_FromString("the_connection")); PyObject* pval = PyObject_CallObject(pFunc, args);` is it correct? I've got an error ** AttributeError: 'str' object has no attribute 'recv_match'** – MaryG Jan 13 '23 at 10:06
  • If you're getting attribute errors then you're into a completely different question - that's just that your Python code isn't working. I don't think I can help you – DavidW Jan 13 '23 at 18:37