Emitting dronekit.io vehicle's attribute changes using flask-socket.io

221 Views Asked by At

I'm trying to send data from my dronekit.io vehicle using flask-socket.io. Unfortunately, I got this log:

Starting copter simulator (SITL)
SITL already Downloaded and Extracted.
Ready to boot.
Connecting to vehicle on: tcp:127.0.0.1:5760
>>> APM:Copter V3.3 (d6053245)
>>> Frame: QUAD
>>> Calibrating barometer
>>> Initialising APM...
>>> barometer calibration complete
>>> GROUND START
* Restarting with stat
latitude  -35.363261

>>> Exception in attribute handler for location.global_relative_frame
>>> Working outside of request context.    

This typically means that you attempted to use functionality that needed
an active HTTP request.  Consult the documentation on testing for
information about how to avoid this problem.
longitude  149.1652299

>>> Exception in attribute handler for location.global_relative_frame
>>> Working outside of request context.

This typically means that you attempted to use functionality that needed
an active HTTP request.  Consult the documentation on testing for
information about how to avoid this problem.

Here is my code:

sample.py

from dronekit import connect, VehicleMode
from flask import Flask
from flask_socketio import SocketIO, emit
import dronekit_sitl
import time

sitl = dronekit_sitl.start_default()
connection_string = sitl.connection_string()
print("Connecting to vehicle on: %s" % (connection_string,))
vehicle = connect(connection_string, wait_ready=True)

def arm_and_takeoff(aTargetAltitude):

    print "Basic pre-arm checks"
    while not vehicle.is_armable:
        print " Waiting for vehicle to initialise..."
        time.sleep(1)

    print "Arming motors"
    vehicle.mode    = VehicleMode("GUIDED")
    vehicle.armed   = True

    while not vehicle.armed:
        print " Waiting for arming..."
        time.sleep(1)

    print "Taking off!"
    vehicle.simple_takeoff(aTargetAltitude)

    while True:
        if vehicle.location.global_relative_frame.alt>=aTargetAltitude*0.95:
            print "Reached target altitude"
            break
        time.sleep(1)

last_latitude = 0.0
last_longitude = 0.0
last_altitude = 0.0

@vehicle.on_attribute('location.global_relative_frame')
def location_callback(self, attr_name, value):
    global last_latitude
    global last_longitude
    global last_altitude
    if round(value.lat, 6) != round(last_latitude, 6):
        last_latitude = value.lat
        print "latitude ", value.lat, "\n"
        emit("latitude", value.lat)
    if round(value.lon, 6) != round(last_longitude, 6):
        last_longitude = value.lon
        print "longitude ", value.lon, "\n"
        emit("longitude", value.lon)
    if round(value.alt) != round(last_altitude):
        last_altitude = value.alt
        print "altitude ", value.alt, "\n"
        emit("altitude", value.alt)

app = Flask(__name__)
socketio = SocketIO(app)

if __name__ == '__main__':
    socketio.run(app, host='0.0.0.0', port=5000, debug=True)
    arm_and_takeoff(20)

I know because of the logs that I should not do any HTTP request inside "vehicle.on_attribute" decorator method and I should search for information on how to solve this problem but I didn't found any info about the error.

Hope you could help me.

Thank you very much,

Raniel

1

There are 1 best solutions below

2
On

The emit() function by default returns an event back to the active client. If you call this function outside of a request context there is no concept of active client, so you get this error.

You have a couple of options:

  1. indicate the recipient of the event and the namespace that you are using, so that there is no need to look them up in the context. You can do this by adding room and namespace arguments. Use '/' for the namespace if you are using the default namespace.

  2. emit to all clients by adding broadcast=True as an argument, plus the namespace as indicated in #1.