Hello,
I have been working on a project where I am designing a flight control system to control UAV. So far, I have been able to initialize Lat/Lon values from user and update the icon in the Map and move the icon with buttons to N,S,E,W directions. My main concern is how can I update/move the icon to next location using a slider which gradually makes the icon move to next location?
The formulas for calculation the next position are already implemented in the function node but I have been stuck in this project for about a month. If anyone can help me out, it would be great.
Here is my current flow:
[
{
"id": "594f4d4bfd9f7699",
"type": "tab",
"label": "Flight_Control_SIMULU",
"disabled": false,
"info": "",
"env": []
},
{
"id": "319ff3a15befbaa7",
"type": "ui_worldmap",
"z": "594f4d4bfd9f7699",
"group": "b4ebae93d455bbc5",
"order": 1,
"width": 9,
"height": 10,
"name": "",
"lat": "48.80",
"lon": "13.50",
"zoom": "",
"layer": "OSMC",
"cluster": "0",
"maxage": "",
"usermenu": "hide",
"layers": "hide",
"panit": "true",
"panlock": "false",
"zoomlock": "false",
"hiderightclick": "true",
"coords": "deg",
"showgrid": "false",
"showruler": "false",
"allowFileDrop": "false",
"path": "/worldmap",
"overlist": "DR,CO,RA,DN,AC,HM",
"maplist": "OSMG,OSMC,EsriC,EsriS,EsriT,EsriDG,UKOS",
"mapname": "",
"mapurl": "",
"mapopt": "",
"mapwms": false,
"x": 1100,
"y": 40,
"wires": []
},
{
"id": "01732bfeeaa6afce",
"type": "ui_text_input",
"z": "594f4d4bfd9f7699",
"name": "",
"label": "Initial Lat Position",
"tooltip": "",
"group": "b4ebae93d455bbc5",
"order": 2,
"width": 6,
"height": 1,
"passthru": true,
"mode": "number",
"delay": "100",
"topic": "lat",
"sendOnBlur": true,
"className": "",
"topicType": "str",
"x": 150,
"y": 160,
"wires": [
[
"fa8d16f8a3e226de"
]
]
},
{
"id": "2aeed1b10c6c1515",
"type": "ui_button",
"z": "594f4d4bfd9f7699",
"name": "",
"group": "b4ebae93d455bbc5",
"order": 3,
"width": 2,
"height": 1,
"passthru": false,
"label": "Set",
"tooltip": "",
"color": "",
"bgcolor": "",
"className": "",
"icon": "",
"payload": "",
"payloadType": "str",
"topic": "set",
"topicType": "str",
"x": 330,
"y": 40,
"wires": [
[
"fa8d16f8a3e226de"
]
]
},
{
"id": "2cb3acd121995f56",
"type": "worldmap-tracks",
"z": "594f4d4bfd9f7699",
"name": "",
"depth": 20,
"layer": "single",
"smooth": false,
"x": 710,
"y": 140,
"wires": [
[
"14927396080798d3"
]
]
},
{
"id": "14927396080798d3",
"type": "worldmap",
"z": "594f4d4bfd9f7699",
"name": "",
"lat": "48.80",
"lon": "13.50",
"zoom": "",
"layer": "OSMC",
"cluster": "",
"maxage": "20",
"usermenu": "show",
"layers": "show",
"panit": "true",
"panlock": "false",
"zoomlock": "false",
"hiderightclick": "false",
"coords": "deg",
"showgrid": "false",
"showruler": "false",
"allowFileDrop": "false",
"path": "/worldmap",
"overlist": "DR,CO,RA,DN,AC,HM",
"maplist": "OSMG,OSMC,EsriC,EsriS,EsriT,EsriDG,UKOS",
"mapname": "",
"mapurl": "",
"mapopt": "",
"mapwms": false,
"x": 940,
"y": 200,
"wires": []
},
{
"id": "3f1eed7c26c68aa2",
"type": "ui_text_input",
"z": "594f4d4bfd9f7699",
"name": "",
"label": "Initial Lon Position",
"tooltip": "",
"group": "b4ebae93d455bbc5",
"order": 4,
"width": 6,
"height": 1,
"passthru": true,
"mode": "number",
"delay": "100",
"topic": "lon",
"sendOnBlur": true,
"className": "",
"topicType": "str",
"x": 150,
"y": 200,
"wires": [
[
"fa8d16f8a3e226de"
]
]
},
{
"id": "bd958146f73af5c1",
"type": "ui_button",
"z": "594f4d4bfd9f7699",
"name": "",
"group": "b4ebae93d455bbc5",
"order": 12,
"width": 6,
"height": 1,
"passthru": false,
"label": "up",
"tooltip": "",
"color": "",
"bgcolor": "",
"className": "",
"icon": "",
"payload": "",
"payloadType": "str",
"topic": "up",
"topicType": "str",
"x": 130,
"y": 60,
"wires": [
[
"fa8d16f8a3e226de"
]
]
},
{
"id": "83cee2bda843d0d2",
"type": "ui_button",
"z": "594f4d4bfd9f7699",
"name": "",
"group": "b4ebae93d455bbc5",
"order": 14,
"width": 6,
"height": 1,
"passthru": false,
"label": "down",
"tooltip": "",
"color": "",
"bgcolor": "",
"className": "",
"icon": "",
"payload": "",
"payloadType": "str",
"topic": "down",
"topicType": "str",
"x": 110,
"y": 260,
"wires": [
[
"fa8d16f8a3e226de"
]
]
},
{
"id": "03aa2f6ba41795a5",
"type": "ui_button",
"z": "594f4d4bfd9f7699",
"name": "",
"group": "b4ebae93d455bbc5",
"order": 16,
"width": 6,
"height": 1,
"passthru": false,
"label": "left",
"tooltip": "",
"color": "",
"bgcolor": "",
"className": "",
"icon": "",
"payload": "",
"payloadType": "str",
"topic": "left",
"topicType": "str",
"x": 110,
"y": 300,
"wires": [
[
"fa8d16f8a3e226de"
]
]
},
{
"id": "7347a00f5de4aab0",
"type": "ui_button",
"z": "594f4d4bfd9f7699",
"name": "",
"group": "b4ebae93d455bbc5",
"order": 18,
"width": 6,
"height": 1,
"passthru": false,
"label": "right",
"tooltip": "",
"color": "",
"bgcolor": "",
"className": "",
"icon": "",
"payload": "",
"payloadType": "str",
"topic": "right",
"topicType": "str",
"x": 130,
"y": 120,
"wires": [
[
"fa8d16f8a3e226de"
]
]
},
{
"id": "fa8d16f8a3e226de",
"type": "function",
"z": "594f4d4bfd9f7699",
"name": "function 3",
"func": "var R = 6378.1; // Radius of Earth\nvar dist = 100; // Distance in meters\nvar theta = (dist / R) * 2 * Math.PI; // Angular distance in radians\nvar speed = 0;\n\nvar lat1 = 0.0;\nvar lon1 = 0.0;\n\nvar lat2 = flow.get(\"lat2\") || 0; //Set Initial Latitude Position\nvar lon2 = flow.get(\"lon2\") || 0; //Set Initial Longitude Position\n\nif(msg.topic == \"lat\"){\n lat2 = msg.payload; \n flow.set(\"lat2\", lat2);\n \n}\n\nif(msg.topic == \"lon\"){\n lon2 = msg.payload ;\n flow.set(\"lon2\", lon2);\n \n}\n\n//Calculate Bearing for Direction\nvar y = Math.sin(lon2 - lon1) * Math.cos(lat2);\nvar x = Math.cos(lat1)*Math.sin(lat2) - Math.sin(lat1)*Math.cos(lat2)*Math.cos(lon2-lon1);\nvar angle = Math.atan2(y, x);\nvar brng = (angle*180/Math.PI + 360) % 360; // in degrees\n\n//Set Position using Set Button\nif(msg.topic == \"set\"){\n var set_it = {\n name:\"SIMULU\",\n lat: lat2,\n lon: lon2,\n icon: \"plane\",\n iconColor: \"black\",\n layer: \"gps\",\n bearing: brng,\n speed: speed + \"kn\",\n popped: true\n }\n msg.payload = set_it;\n}\n\n//Calculation for next point\nvar lat3 = Math.asin(Math.sin(lat1) * Math.cos(theta) +\n Math.cos(lat1) * Math.sin(theta) * Math.cos(brng));\n\nvar lon3 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(theta)* Math.cos(lat1),\n Math.cos(theta) - Math.sin(lat1) * Math.sin(lat3))\n\nvar lat3_deg = lat3 * 180 / Math.PI;\nvar lon3_deg = lon3 * 180 / Math.PI;\n\n//Calculation of bearing for next point\nvar y_1 = Math.sin(lon3 - lon2) * Math.cos(lat3);\nvar x_1 = Math.cos(lat2) * Math.sin(lat3) - Math.sin(lat2) * Math.cos(lat3) * Math.cos(lon3 - lon2);\nvar angle = Math.atan2(y_1, x_1);\nvar brng_1 = (angle * 180 / Math.PI + 360) % 360; // in degrees\n\n//Speed slider for next point\nif(msg.topic == \"speed\"){\n var nxt_pnt = {\n name: \"SIMULU\",\n lat: lat3_deg,\n lon: lon3_deg,\n bearing: brng_1,\n layer: \"gps\",\n popped: true\n }\n msg.payload = nxt_pnt;\n}\n\n//Control Buttons for directions\nlet move = flow.get(\"location\") || set_it;\nlet bearing = move.bearing;\nlet lat = move.lat;\nlet lon = move.lon;\n\nif(msg.topic == \"up\"){\n if(bearing = 0){\n bearing = 0;\n }\n move.lat = move.lat + 0.01;\n move.lon = move.lon + 0; \n var up = {\n name:\"SIMULU\",\n lat: move.lat,\n lon: move.lon,\n bearing:bearing,\n layer:\"gps\",\n popped:true\n }\n node.warn(\"Up-bearing=\" +bearing);\n msg.payload = up;\n}\n\nif(msg.topic==\"right\"){\n if(bearing >= 0 || bearing < 90){\n bearing = 90;\n }\n move.lat = move.lat + 0;\n move.lon = move.lon + 0.01;\n var right = {\n name:\"SIMULU\",\n lat: move.lat,\n lon: move.lon,\n bearing:bearing,\n layer:\"gps\",\n popped:true\n }\n node.warn(\"Right-bearing=\" +bearing)\n msg.payload = right;\n}\n\nif(msg.topic == \"down\"){\n if(bearing > 90 || bearing < 270){\n bearing = 180;\n }\n move.lat = move.lat - 0.01;\n move.lon = move.lon - 0;\n var down = {\n name: \"SIMULU\",\n lat: move.lat,\n lon: move.lon,\n bearing:bearing,\n layer:\"gps\",\n popped:true\n }\n node.warn(\"Down-bearing=\" +bearing)\n msg.payload = down;\n}\n\nif(msg.topic==\"left\"){\n if(bearing > 180 || bearing < 360 ){\n bearing = 270;\n }\n move.lat = move.lat - 0;\n move.lon = move.lon - 0.01;\n var left = {\n name:\"SIMULU\",\n lat: move.lat,\n lon: move.lon,\n bearing:bearing,\n layer:\"gps\",\n popped:true\n }\n node.warn(\"Left-bearing=\" +bearing)\n msg.payload = left;\n}\n\nmove.bearing = bearing;\nflow.set(\"location\", move);\n//msg.payload = move;\n\n/*let new_location = flow.get(\"new_location\") || move;\nlet new_lat = new_location.lat;\nlet new_lon = new_location.lon;\n\n\nif(msg.topic == \"set\"){\n flow.set(\"new_location\", new_location);\n node.warn(\"new_location:\" +new_location);\n msg.payload = new_location;\n}\n*/\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 500,
"y": 160,
"wires": [
[
"9336120dc02d8212",
"2cb3acd121995f56",
"14927396080798d3"
]
]
},
{
"id": "9336120dc02d8212",
"type": "debug",
"z": "594f4d4bfd9f7699",
"name": "debug 4",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 800,
"y": 320,
"wires": []
},
{
"id": "4293d65595438ef9",
"type": "ui_slider",
"z": "594f4d4bfd9f7699",
"name": "",
"label": "Speed",
"tooltip": "",
"group": "b4ebae93d455bbc5",
"order": 10,
"width": 6,
"height": 1,
"passthru": true,
"outs": "end",
"topic": "speed",
"topicType": "str",
"min": 0,
"max": "100",
"step": "0.1",
"className": "",
"x": 110,
"y": 360,
"wires": [
[]
]
},
{
"id": "b4ebae93d455bbc5",
"type": "ui_group",
"name": "UAV Flight Control",
"tab": "37a720198b072daf",
"order": 1,
"disp": true,
"width": "17",
"collapse": false,
"className": ""
},
{
"id": "37a720198b072daf",
"type": "ui_tab",
"name": "Flight_Control",
"icon": "dashboard",
"order": 2,
"disabled": false,
"hidden": false
}
]