MAVLink to REST API

can i create this is javascript?

Yes, that’s totally doable in javascript

@patrickelectric hello, I have made a PR to add a readme to explain a way to modify the mavlink messages supported. If you can look at it, I think it would be usefull !

Hi, this looks excellent and perfect for my needs thanks.

I want to put some sensor data from ardupilot (attitude, depth,windspeed,gps…) into a node-red dashboard

1hz is Fast enough.

Any advice or pointers on how best to do this, or plans to make a node for node-red ?

Ps I’m competent with ardupilot. I’m learning mavlink, json, signalk, node-red and liking it.

Hi @khancyr! Sorry but I can’t find your PR over the repository, did you create under the new home (mavlink organization) ?

Hi @paul_arthur,

I would highly recommend to use the websocket to communicate, it’s pretty clear and easy.

Hum , I didn’t know it change home. Will make another there then

1 Like

Thanks Patrick, i installed it on my Pi 4b and it sprang to life and delivering :slight_smile:

My Config
zealot H7/Copter 4.3 with ESP8266 wifi dongle - mapped to my home wifi
mavlink2rest started without any parameters

Observations from this mavlink newbie

  1. dont have Mission Planner connected to the flight computer - no data back
  2. For best results
  • Connect Mission Planner (via UDP) then disconnect mission planner
  • Start mavlink2rest
    Point browser at http://192.168.1.154:8088 gives you this

    Clicking the link gives
    {
    “message_information”: {
    “counter”: 545,
    “frequency”: 4.007352828979492,
    “time”: {
    “first_message”: “2023-08-28T16:18:42.179679777+12:00”,
    “last_message”: “2023-08-28T16:20:58.670891827+12:00”
    }
    },
    “pitch”: 0.039569199085235596,
    “pitchspeed”: -0.0000885922199813649,
    “roll”: -0.009507871232926846,
    “rollspeed”: 0.00029551188345067203,
    “time_boot_ms”: 2409015,
    “type”: “ATTITUDE”,
    “yaw”: -0.2203657627105713,
    “yawspeed”: 0.0007805466884747148
    }

With a bit of node-red and a HTTP GET node results in a real time output of roll/pitch/yaw - which is what im wanting -

Question - how do i skip HTTP and retrieve the same info via websockets.
/ws/mavlink doesnt return any info - even though the console says websocket created.

ideally - how to generate output from the command line, i can figure it from there.
Thanks in advance, Paul.

Hi @kiwiPaul,

I got it working here, it was just necessary to configure the websocket block.
You can check my flow here: flows.zip (1.7 KB)

image

image

Since you are working on a Raspberry Pi 4 and with mavlink2rest, I would recommend taking a look on

Brilliant - loving this, its solving a bunch of problems for me, and thanks for the example. I built on to it - and its working brilliantly. Pi 4B is running at 4% cpu most of which is node-red and 1% is mavlink2rest - this is processing all the normal mission planner telemetry.

For those following - my flow looks like this now (Patrick, my node red payloads were all different to yours, as was the websocket - but close enough :slight_smile: )

This generates a real time guage and chart of axis, and a world map using the gps lat, long, alt and sat count.

Patrick - any hints for getting the available paths traffic up without starting stopping mission planner ? Before MP its just heartbeat and a bit more, after its whatever MP asked for i guess.

My flow to cut/paste into Node-Red is here

[{“id”:“ff69a9701e1b8d75”,“type”:“websocket in”,“z”:“2ca6ebad5d7e3813”,“name”:“ws://192.168.1.154:8088/ws/mavlink”,“server”:“397172b08ff52a59”,“client”:“”,“x”:220,“y”:100,“wires”:[[“c19f02f8883fa1a8”]]},{“id”:“56251017be9d59f1”,“type”:“inject”,“z”:“2ca6ebad5d7e3813”,“name”:“timestamp”,“props”:[{“p”:“payload”},{“p”:“topic”,“vt”:“str”}],“repeat”:“”,“crontab”:“”,“once”:false,“onceDelay”:0.1,“topic”:“”,“payload”:“”,“payloadType”:“date”,“x”:160,“y”:400,“wires”:[[“98018b377c7287ec”]]},{“id”:“98018b377c7287ec”,“type”:“http request”,“z”:“2ca6ebad5d7e3813”,“name”:“http://192.168.1.154:8088/mavlink/ATTITUDE",“method”:“GET”,“ret”:“obj”,“paytoqs”:“ignore”,“url”:“http://192.168.1.154:8088/mavlink/ATTITUDE”,“tls”:“”,“persist”:false,“proxy”:“”,“insecureHTTPParser”:false,“authType”:“”,“senderr”:false,“headers”:[],“x”:250,“y”:480,“wires”:[[“9084124dd01104fc”,“5b8e672f9fd5d422”,“1119ff04ad758e12”]]},{“id”:“9084124dd01104fc”,“type”:“debug”,“z”:“2ca6ebad5d7e3813”,“name”:“Roll”,“active”:false,“tosidebar”:true,“console”:false,“tostatus”:true,“complete”:“payload.roll”,“targetType”:“msg”,“statusVal”:“payload.message.roll”,“statusType”:“auto”,“x”:530,“y”:440,“wires”:[]},{“id”:“5b8e672f9fd5d422”,“type”:“debug”,“z”:“2ca6ebad5d7e3813”,“name”:“Pitch”,“active”:false,“tosidebar”:true,“console”:false,“tostatus”:true,“complete”:“payload.pitch”,“targetType”:“msg”,“statusVal”:“payload.message.pitch”,“statusType”:“auto”,“x”:550,“y”:500,“wires”:[]},{“id”:“1119ff04ad758e12”,“type”:“debug”,“z”:“2ca6ebad5d7e3813”,“name”:“Yaw”,“active”:false,“tosidebar”:true,“console”:false,“tostatus”:true,“complete”:“payload.yaw”,“targetType”:“msg”,“statusVal”:“payload.message.pitch”,“statusType”:“auto”,“x”:510,“y”:380,“wires”:[]},{“id”:“c19f02f8883fa1a8”,“type”:“json”,“z”:“2ca6ebad5d7e3813”,“name”:“messages”,“property”:“payload”,“action”:“obj”,“pretty”:false,“x”:330,“y”:240,“wires”:[[“9de8fbd404835d40”,“f9f65bd3f34da924”]]},{“id”:“9de8fbd404835d40”,“type”:“switch”,“z”:“2ca6ebad5d7e3813”,“name”:“Attitude”,“property”:“payload.type”,“propertyType”:“msg”,“rules”:[{“t”:“eq”,“v”:“ATTITUDE”,“vt”:“str”}],“checkall”:“true”,“repair”:false,“outputs”:1,“x”:520,“y”:100,“wires”:[[“8e4f91ac0cdd8bf1”,“a8e831944b6028d6”,“34837f96951f9577”]]},{“id”:“03a96bf5700fd912”,“type”:“ui_chart”,“z”:“2ca6ebad5d7e3813”,“name”:“Attitude”,“group”:“2444546f087153a2”,“order”:0,“width”:“6”,“height”:“6”,“label”:“chart”,“chartType”:“line”,“legend”:“true”,“xformat”:“HH:mm:ss”,“interpolate”:“linear”,“nodata”:“”,“dot”:false,“ymin”:“-180”,“ymax”:“180”,“removeOlder”:1,“removeOlderPoints”:“”,“removeOlderUnit”:“3600”,“cutout”:0,“useOneColor”:false,“useUTC”:false,“colors”:[“#1f77b4”,“#aec7e8”,“#ff7f0e”,“#2ca02c”,“#98df8a”,“#d62728”,“#ff9896”,“#9467bd”,“#c5b0d5”],“outputs”:1,“useDifferentColor”:false,“className”:“”,“x”:1000,“y”:80,“wires”:[[]]},{“id”:“7af709ccb9c37eab”,“type”:“ui_gauge”,“z”:“2ca6ebad5d7e3813”,“name”:“Yaw”,“group”:“2444546f087153a2”,“order”:1,“width”:“6”,“height”:“6”,“gtype”:“gage”,“title”:“Yaw”,“label”:“units”,“format”:"{{value}}”,“min”:“-180”,“max”:“180”,“colors”:[“#00b500”,“#e6e600”,“#ca3838”],“seg1”:“”,“seg2”:“”,“diff”:false,“className”:“”,“x”:990,“y”:120,“wires”:},{“id”:“8e4f91ac0cdd8bf1”,“type”:“function”,“z”:“2ca6ebad5d7e3813”,“name”:“Roll”,“func”:“msg.payload = msg.payload.roll * 180 / 3.1415\nmsg.topic = "Roll"\nreturn msg”,“outputs”:1,“noerr”:0,“initialize”:“”,“finalize”:“”,“libs”:,“x”:750,“y”:80,“wires”:[[“03a96bf5700fd912”]]},{“id”:“a8e831944b6028d6”,“type”:“function”,“z”:“2ca6ebad5d7e3813”,“name”:“Pitch”,“func”:“msg.payload = msg.payload.pitch * 180 / 3.1415\nmsg.topic = "Pitch"\nreturn msg”,“outputs”:1,“noerr”:0,“initialize”:“”,“finalize”:“”,“libs”:,“x”:750,“y”:140,“wires”:[[“03a96bf5700fd912”]]},{“id”:“34837f96951f9577”,“type”:“function”,“z”:“2ca6ebad5d7e3813”,“name”:“Yaw”,“func”:“msg.payload = msg.payload.yaw * 180 / 3.1415\nmsg.topic = "Yaw"\nreturn msg”,“outputs”:1,“noerr”:0,“initialize”:“”,“finalize”:“”,“libs”:,“x”:750,“y”:200,“wires”:[[“7af709ccb9c37eab”,“03a96bf5700fd912”,“99d847f567c0f7b3”]]},{“id”:“99d847f567c0f7b3”,“type”:“debug”,“z”:“2ca6ebad5d7e3813”,“name”:“Yaw”,“active”:false,“tosidebar”:true,“console”:false,“tostatus”:true,“complete”:“payload”,“targetType”:“msg”,“statusVal”:“payload”,“statusType”:“auto”,“x”:990,“y”:160,“wires”:},{“id”:“f2fa43fb2187c280”,“type”:“comment”,“z”:“2ca6ebad5d7e3813”,“name”:“WS keeps working after disconnected…”,“info”:“****“,“x”:250,“y”:180,“wires”:[]},{“id”:“f9f65bd3f34da924”,“type”:“switch”,“z”:“2ca6ebad5d7e3813”,“name”:“GPS_RAW_INT”,“property”:“payload.type”,“propertyType”:“msg”,“rules”:[{“t”:“eq”,“v”:“GPS_RAW_INT”,“vt”:“str”}],“checkall”:“true”,“repair”:false,“outputs”:1,“x”:540,“y”:240,“wires”:[[“86f5c0f0d63651f8”,“3ce0f1a7f2ddc546”,“effd61c45251e8c3”,“0dcea0f6bcf0073d”,“cb1375e14d3ac20c”]]},{“id”:“86f5c0f0d63651f8”,“type”:“function”,“z”:“2ca6ebad5d7e3813”,“name”:“lat”,“func”:“msg.payload = msg.payload.lat / 10000000\nmsg.topic = "lat"\nreturn msg”,“outputs”:1,“noerr”:0,“initialize”:”“,“finalize”:”“,“libs”:[],“x”:750,“y”:240,“wires”:[[“b206c363707f2df0”]]},{“id”:“b206c363707f2df0”,“type”:“debug”,“z”:“2ca6ebad5d7e3813”,“name”:“debug 18”,“active”:true,“tosidebar”:false,“console”:false,“tostatus”:true,“complete”:“payload”,“targetType”:“msg”,“statusVal”:“payload”,“statusType”:“auto”,“x”:1000,“y”:240,“wires”:[]},{“id”:“3ce0f1a7f2ddc546”,“type”:“function”,“z”:“2ca6ebad5d7e3813”,“name”:“lon”,“func”:“msg.payload = msg.payload.lon / 10000000\nmsg.topic = "lon"\nreturn msg”,“outputs”:1,“noerr”:0,“initialize”:”“,“finalize”:”“,“libs”:[],“x”:750,“y”:300,“wires”:[[“e84c064a920bb512”]]},{“id”:“e84c064a920bb512”,“type”:“debug”,“z”:“2ca6ebad5d7e3813”,“name”:“debug 19”,“active”:true,“tosidebar”:false,“console”:false,“tostatus”:true,“complete”:“payload”,“targetType”:“msg”,“statusVal”:“payload”,“statusType”:“auto”,“x”:1000,“y”:300,“wires”:[]},{“id”:“effd61c45251e8c3”,“type”:“function”,“z”:“2ca6ebad5d7e3813”,“name”:“alt”,“func”:“msg.payload = msg.payload.alt \nmsg.topic = "alt"\nreturn msg”,“outputs”:1,“noerr”:0,“initialize”:”“,“finalize”:”“,“libs”:[],“x”:750,“y”:360,“wires”:[[“505eec6afc313f23”]]},{“id”:“505eec6afc313f23”,“type”:“debug”,“z”:“2ca6ebad5d7e3813”,“name”:“debug 20”,“active”:true,“tosidebar”:false,“console”:false,“tostatus”:true,“complete”:“payload”,“targetType”:“msg”,“statusVal”:“payload”,“statusType”:“auto”,“x”:1000,“y”:360,“wires”:[]},{“id”:“0dcea0f6bcf0073d”,“type”:“function”,“z”:“2ca6ebad5d7e3813”,“name”:“sats”,“func”:“msg.payload = msg.payload.satellites_visible\nmsg.topic = "sats"\nreturn msg”,“outputs”:1,“noerr”:0,“initialize”:”“,“finalize”:”“,“libs”:[],“x”:750,“y”:420,“wires”:[[“e1bc6c96857f90fb”]]},{“id”:“e1bc6c96857f90fb”,“type”:“debug”,“z”:“2ca6ebad5d7e3813”,“name”:“debug 21”,“active”:true,“tosidebar”:false,“console”:false,“tostatus”:true,“complete”:“payload”,“targetType”:“msg”,“statusVal”:“payload”,“statusType”:“auto”,“x”:1000,“y”:420,“wires”:[]},{“id”:“835cdaa2c11bbc0d”,“type”:“ui_worldmap”,“z”:“2ca6ebad5d7e3813”,“group”:“eed5b235b9cee08e”,“order”:2,“width”:0,“height”:0,“name”:”“,“lat”:”-37.134",“lon”:“174.708”,“zoom”:“”,“layer”:“EsriS”,“cluster”:“”,“maxage”:“”,“usermenu”:“hide”,“layers”:“hide”,“panit”:“false”,“panlock”:“false”,“zoomlock”:“false”,“hiderightclick”:“true”,“coords”:“none”,“showgrid”:“false”,“showruler”:“false”,“allowFileDrop”:“false”,“path”:“/worldmap”,“overlist”:“DR,CO,RA,DN,HM”,“maplist”:“OSMG,OSMC,EsriC,EsriS,EsriT,EsriDG,UKOS”,“mapname”:“”,“mapurl”:“”,“mapopt”:“”,“mapwms”:false,“x”:1000,“y”:480,“wires”:[]},{“id”:“cb1375e14d3ac20c”,“type”:“function”,“z”:“2ca6ebad5d7e3813”,“name”:“Format Mav LatLong”,“func”:“msg.payload.lat = msg.payload.lat /10000000;\nmsg.payload.lon = msg.payload.lon /10000000;\nmsg.payload.label = "Zealot H7";\nmsg.payload.name = "Me";\nreturn msg;\n\n”,“outputs”:1,“noerr”:0,“initialize”:“”,“finalize”:“”,“libs”:[],“x”:800,“y”:480,“wires”:[[“835cdaa2c11bbc0d”]]},{“id”:“018ea225bd86907f”,“type”:“comment”,“z”:“2ca6ebad5d7e3813”,“name”:“start mavlink2rest after start/stop of Mission Planner”,“info”:“”,“x”:250,“y”:60,“wires”:[]},{“id”:“3aa5a82f48dab656”,“type”:“comment”,“z”:“2ca6ebad5d7e3813”,“name”:“lat lon name label”,“info”:"## ## “,“x”:820,“y”:520,“wires”:[]},{“id”:“46929e7885ea49a1”,“type”:“comment”,“z”:“2ca6ebad5d7e3813”,“name”:“This subflow demonstrates HTTP”,“info”:””,“x”:270,“y”:520,“wires”:},{“id”:“397172b08ff52a59”,“type”:“websocket-listener”,“path”:“ws://192.168.1.154:8088/ws/mavlink”,“wholemsg”:“false”},{“id”:“2444546f087153a2”,“type”:“ui_group”,“name”:“Default”,“tab”:“8e29298fdb5d2d76”,“order”:1,“disp”:true,“width”:“6”,“collapse”:false,“className”:“”},{“id”:“eed5b235b9cee08e”,“type”:“ui_group”,“name”:“PAXCounter Dashboard”,“tab”:“fc7863b4920af346”,“order”:1,“disp”:true,“width”:“6”,“collapse”:false,“className”:“”},{“id”:“8e29298fdb5d2d76”,“type”:“ui_tab”,“name”:“Home”,“icon”:“dashboard”,“disabled”:false,“hidden”:false},{“id”:“fc7863b4920af346”,“type”:“ui_tab”,“name”:“Home”,“icon”:“dashboard”,“disabled”:false,“hidden”:false}]

Just to react to a comment on your flow, depending on how you are connecting to your drone, you can connect mavlink2rest to Mission Planner (or Mavproxy) as it support to relay Mavlink communication, or using something like mavlink-router will give you as much connection you need to your drone ! Without beeing limited to only one physical layer.

Hi @kiwiPaul,

I would recommend following @khancyr suggestion, but, if you don’t want to connect a GCS to start the streaming, you could use mavp2p since it can do a streamreq by itself.

Keep in mind that cpu usage is not that low compared with mavlink-router.

Another alternative would do a streamreq or heartbeat from node-red, it should work, you just need to create the message to send.

no mavlink-r(o)u(s)ter in the pipeline ? :cry:

Hi there,
I installed all your solution and it works great ! I receive the messages I need with a websocket in nodejs and I post the commands/messages with axios : great !
But, there’s a way to send commands/messages to ardupilot (RC_CHANNELS_OVERRIDE for ex.) with WS instead Post msg ? I think that can I improve the latency and the frequency
Thanks

1 Like

I’m sorry , I solved the problem : now it works also with WS instead post msg
Nice works @patrickelectric

1 Like

Hi @khancyr,

I’m aware that are some people working on it and collaborating with rust-mavlink repository with that end.

1 Like

Cool, I would be interested to see the result ! Not that mavlink-router is bad but having a performant alternative would be good

Hi @patrickelectric,
When working with commands such as ‘MISSION_ITEM_INT,’ you’ll encounter fields named ‘command’ and ‘frame.’ In your example, these fields are populated with values like {“type”: “MAV_CMD_NAV_WAYPOINT”}. Is it possible to use an ID (such as 16 in this case) instead of the string representation?
Davide

Hi @davieli2,

It’s possible, but changes on rust-mavlink are required.