Commit 25dbbe77 authored by Léo-Paul Géneau's avatar Léo-Paul Géneau 👾

erp5_officejs_drone_simulator: add loop interval parameter

Loop interval is the time in milliseconds between 2 executions of the
onUpdate function of the user script as well as the periodicity to send
messages to the swarm (which means updating telemetry values).
As this is something we can set in SlapOS mostly to handle bandwith
usage, this must not be linked to the time delta used to update drone
position in the simulation.
parent 8f4cf329
...@@ -56,7 +56,7 @@ var EnemyDroneAPI = /** @class */ (function () { ...@@ -56,7 +56,7 @@ var EnemyDroneAPI = /** @class */ (function () {
/* /*
** Function called on every drone update, right before onUpdate AI script ** Function called on every drone update, right before onUpdate AI script
*/ */
EnemyDroneAPI.prototype.internal_update = function (context, delta_time) { EnemyDroneAPI.prototype.internal_position_update = function (context, delta_time) {
context._speed += context._acceleration * delta_time / 1000; context._speed += context._acceleration * delta_time / 1000;
if (context._speed > context._maxSpeed) { if (context._speed > context._maxSpeed) {
context._speed = context._maxSpeed; context._speed = context._maxSpeed;
...@@ -81,7 +81,7 @@ var EnemyDroneAPI = /** @class */ (function () { ...@@ -81,7 +81,7 @@ var EnemyDroneAPI = /** @class */ (function () {
/* /*
** Function called on every drone update, right after onUpdate AI script ** Function called on every drone update, right after onUpdate AI script
*/ */
EnemyDroneAPI.prototype.internal_post_update = function (drone) { EnemyDroneAPI.prototype.internal_info_update = function (drone) {
var _this = this, drone_position = drone.getCurrentPosition(), drone_info; var _this = this, drone_position = drone.getCurrentPosition(), drone_info;
if (drone_position) { if (drone_position) {
drone_info = { drone_info = {
...@@ -307,6 +307,9 @@ var EnemyDroneAPI = /** @class */ (function () { ...@@ -307,6 +307,9 @@ var EnemyDroneAPI = /** @class */ (function () {
EnemyDroneAPI.prototype.getMaxHeight = function () { EnemyDroneAPI.prototype.getMaxHeight = function () {
return 800; return 800;
}; };
EnemyDroneAPI.prototype.getOnUpdateInterval = function () {
return 0;
};
EnemyDroneAPI.prototype.getFlightParameters = function () { EnemyDroneAPI.prototype.getFlightParameters = function () {
return this._flight_parameters; return this._flight_parameters;
}; };
......
...@@ -246,7 +246,7 @@ ...@@ -246,7 +246,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1014.60631.26636.59528</string> </value> <value> <string>1015.63148.58654.57634</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -266,7 +266,7 @@ ...@@ -266,7 +266,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1709288499.16</float> <float>1713426942.44</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -98,7 +98,7 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -98,7 +98,7 @@ var FixedWingDroneAPI = /** @class */ (function () {
/* /*
** Function called on every drone update, right before onUpdate AI script ** Function called on every drone update, right before onUpdate AI script
*/ */
FixedWingDroneAPI.prototype.internal_update = function (context, delta_time) { FixedWingDroneAPI.prototype.internal_position_update = function (context, delta_time) {
if (context.position.z > 0) { if (context.position.z > 0) {
this._updateSpeed(context, delta_time); this._updateSpeed(context, delta_time);
this._updatePosition(context, delta_time); this._updatePosition(context, delta_time);
...@@ -112,7 +112,7 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -112,7 +112,7 @@ var FixedWingDroneAPI = /** @class */ (function () {
/* /*
** Function called on every drone update, right after onUpdate AI script ** Function called on every drone update, right after onUpdate AI script
*/ */
FixedWingDroneAPI.prototype.internal_post_update = function (drone) { FixedWingDroneAPI.prototype.internal_info_update = function (drone) {
var _this = this, drone_position = drone.getCurrentPosition(), drone_info; var _this = this, drone_position = drone.getCurrentPosition(), drone_info;
/*if (_this._start_altitude > 0) { //TODO move start_altitude here /*if (_this._start_altitude > 0) { //TODO move start_altitude here
_this.reachAltitude(drone); _this.reachAltitude(drone);
...@@ -548,6 +548,9 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -548,6 +548,9 @@ var FixedWingDroneAPI = /** @class */ (function () {
FixedWingDroneAPI.prototype.getMaxHeight = function () { FixedWingDroneAPI.prototype.getMaxHeight = function () {
return 800; return 800;
}; };
FixedWingDroneAPI.prototype.getOnUpdateInterval = function () {
return this._flight_parameters.drone.onUpdateInterval;
};
FixedWingDroneAPI.prototype.getFlightParameters = function () { FixedWingDroneAPI.prototype.getFlightParameters = function () {
return this._flight_parameters; return this._flight_parameters;
}; };
......
...@@ -246,7 +246,7 @@ ...@@ -246,7 +246,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1015.19974.55909.31829</string> </value> <value> <string>1015.63135.31786.47957</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -266,7 +266,7 @@ ...@@ -266,7 +266,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1710776360.59</float> <float>1713426004.3</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -27,6 +27,7 @@ var DroneManager = /** @class */ (function () { ...@@ -27,6 +27,7 @@ var DroneManager = /** @class */ (function () {
this._maxClimbRate = 0; this._maxClimbRate = 0;
this._maxCommandFrequency = 0; this._maxCommandFrequency = 0;
this._last_command_timestamp = 0; this._last_command_timestamp = 0;
this._last_onUpdate_timestamp = 0;
this._speed = 0; this._speed = 0;
this._acceleration = 0; this._acceleration = 0;
this._direction = new BABYLON.Vector3(0, 0, 1); // North this._direction = new BABYLON.Vector3(0, 0, 1); // North
...@@ -135,7 +136,7 @@ var DroneManager = /** @class */ (function () { ...@@ -135,7 +136,7 @@ var DroneManager = /** @class */ (function () {
this._canPlay = true; this._canPlay = true;
this._canCommunicate = true; this._canCommunicate = true;
try { try {
return this.onStart(this._API._gameManager._game_duration); return this.onStart(this._API._gameManager._start_time);
} catch (error) { } catch (error) {
console.warn('Drone crashed on start due to error:', error); console.warn('Drone crashed on start due to error:', error);
this._internal_crash(error); this._internal_crash(error);
...@@ -143,17 +144,18 @@ var DroneManager = /** @class */ (function () { ...@@ -143,17 +144,18 @@ var DroneManager = /** @class */ (function () {
}; };
DroneManager.prototype._callSetTargetCommand = DroneManager.prototype._callSetTargetCommand =
function (latitude, longitude, altitude, speed, radius) { function (latitude, longitude, altitude, speed, radius) {
var current_time = this._API._gameManager.getCurrentTime();
if (!this.isReadyToFly()) { if (!this.isReadyToFly()) {
return; return;
} }
if (this._API._gameManager._game_duration - this._last_command_timestamp if (current_time - this._last_command_timestamp
< 1000 / this._API.getMaxCommandFrequency()) { < 1000 / this._API.getMaxCommandFrequency()) {
this._internal_crash(new Error('Minimum interval between commands is ' + this._internal_crash(new Error('Minimum interval between commands is ' +
1000 / this._API.getMaxCommandFrequency() + ' milliseconds')); 1000 / this._API.getMaxCommandFrequency() + ' milliseconds'));
} }
this._internal_setTargetCoordinates(latitude, longitude, altitude, speed, this._internal_setTargetCoordinates(latitude, longitude, altitude, speed,
radius); radius);
this._last_command_timestamp = this._API._gameManager._game_duration; this._last_command_timestamp = current_time;
}; };
/** /**
* Set a target point to move * Set a target point to move
...@@ -192,15 +194,29 @@ var DroneManager = /** @class */ (function () { ...@@ -192,15 +194,29 @@ var DroneManager = /** @class */ (function () {
return; return;
}; };
DroneManager.prototype.internal_update = function (delta_time) { DroneManager.prototype.internal_update = function (delta_time) {
var context = this, milliseconds; var context = this,
current_time = this._API._gameManager.getCurrentTime(),
onUpdate_interval = this._API.getOnUpdateInterval(),
onUpdate_start;
if (this._controlMesh) { if (this._controlMesh) {
context._API.internal_update(context, delta_time); context._API.internal_position_update(context, delta_time);
if (context._canUpdate) { if (context._canUpdate &&
current_time - this._last_onUpdate_timestamp >= onUpdate_interval) {
context._canUpdate = false; context._canUpdate = false;
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
milliseconds = Math.floor(context._API._gameManager._game_duration); onUpdate_start = Date.now();
return context.onUpdate(milliseconds); context._last_onUpdate_timestamp = current_time;
context.onUpdate(current_time);
if (onUpdate_interval > 0 &&
Date.now() - onUpdate_start > onUpdate_interval) {
throw new Error('onUpdate execution took ' +
(Date.now() - onUpdate_start) +
' milliseconds but loop interval is only ' +
onUpdate_interval +
' milliseconds');
}
return;
}) })
.push(function () { .push(function () {
context._canUpdate = true; context._canUpdate = true;
...@@ -209,7 +225,7 @@ var DroneManager = /** @class */ (function () { ...@@ -209,7 +225,7 @@ var DroneManager = /** @class */ (function () {
context._internal_crash(error); context._internal_crash(error);
}) })
.push(function () { .push(function () {
context._API.internal_post_update(context); context._API.internal_info_update(context);
}) })
.push(undefined, function (error) { .push(undefined, function (error) {
console.warn('Drone crashed on update due to error:', error); console.warn('Drone crashed on update due to error:', error);
...@@ -313,7 +329,7 @@ var DroneManager = /** @class */ (function () { ...@@ -313,7 +329,7 @@ var DroneManager = /** @class */ (function () {
this._controlMesh.position.z, this._controlMesh.position.z,
this._controlMesh.position.y this._controlMesh.position.y
); );
position.timestamp = this._API._gameManager._game_duration; position.timestamp = this._API._gameManager.getCurrentTime();
//Backward compatibility sanitation //Backward compatibility sanitation
position.x = position.latitude; position.x = position.latitude;
position.y = position.longitude; position.y = position.longitude;
...@@ -923,7 +939,6 @@ var GameManager = /** @class */ (function () { ...@@ -923,7 +939,6 @@ var GameManager = /** @class */ (function () {
this._droneList.forEach(function (drone) { this._droneList.forEach(function (drone) {
queue.push(function () { queue.push(function () {
drone._tick += 1;
if (drone.can_play) { if (drone.can_play) {
if (drone.getCurrentPosition().altitude <= 0) { if (drone.getCurrentPosition().altitude <= 0) {
if (!drone.isLanding()) { if (!drone.isLanding()) {
...@@ -983,7 +998,8 @@ var GameManager = /** @class */ (function () { ...@@ -983,7 +998,8 @@ var GameManager = /** @class */ (function () {
this._game_duration += delta_time; this._game_duration += delta_time;
var color, drone_position, game_manager = this, geo_coordinates, var color, drone_position, game_manager = this, geo_coordinates,
log_count, map_info, map_manager, material, position_obj, log_count, map_info, map_manager, material, position_obj,
seconds = Math.floor(this._game_duration / 1000), trace_objects; current_time = this.getCurrentTime(),
seconds = Math.floor(current_time / 1000), trace_objects;
if (GAMEPARAMETERS.log_drone_flight || GAMEPARAMETERS.draw_flight_path) { if (GAMEPARAMETERS.log_drone_flight || GAMEPARAMETERS.draw_flight_path) {
this._droneList_user.forEach(function (drone, index) { this._droneList_user.forEach(function (drone, index) {
...@@ -1002,7 +1018,7 @@ var GameManager = /** @class */ (function () { ...@@ -1002,7 +1018,7 @@ var GameManager = /** @class */ (function () {
drone_position.z drone_position.z
); );
game_manager._flight_log[index].push([ game_manager._flight_log[index].push([
game_manager._game_duration, geo_coordinates.latitude, current_time, geo_coordinates.latitude,
geo_coordinates.longitude, geo_coordinates.longitude,
map_info.start_AMSL + drone_position.z, map_info.start_AMSL + drone_position.z,
drone_position.z, drone.getYaw(), drone.getSpeed(), drone_position.z, drone.getYaw(), drone.getSpeed(),
...@@ -1232,20 +1248,19 @@ var GameManager = /** @class */ (function () { ...@@ -1232,20 +1248,19 @@ var GameManager = /** @class */ (function () {
_this.ongoing_update_promise = null; _this.ongoing_update_promise = null;
_this.finish_deferred = RSVP.defer(); _this.finish_deferred = RSVP.defer();
console.log("Simulation started."); console.log("Simulation started.");
this._game_duration = Date.now(); this._start_time = Date.now();
this._totalTime = GAMEPARAMETERS.gameTime * 1000 + this._game_duration; this._game_duration = 0;
this._totalTime = GAMEPARAMETERS.gameTime * 1000;
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
promise_list = []; promise_list = [];
_this._droneList_user.forEach(function (drone) { _this._droneList_user.forEach(function (drone) {
drone._tick = 0;
promise_list.push(drone.internal_start()); promise_list.push(drone.internal_start());
}); });
start_msg = GAMEPARAMETERS.operator_init_msg; start_msg = GAMEPARAMETERS.operator_init_msg;
promise_list.push(_this._droneList_user[0].sendMsg(start_msg)); promise_list.push(_this._droneList_user[0].sendMsg(start_msg));
_this._droneList_enemy.forEach(function (drone) { _this._droneList_enemy.forEach(function (drone) {
drone._tick = 0;
promise_list.push(drone.internal_start()); promise_list.push(drone.internal_start());
}); });
return RSVP.all(promise_list); return RSVP.all(promise_list);
...@@ -1331,9 +1346,8 @@ var GameManager = /** @class */ (function () { ...@@ -1331,9 +1346,8 @@ var GameManager = /** @class */ (function () {
"let droneMe = function(NativeDate, me, Math, window, DroneManager," + "let droneMe = function(NativeDate, me, Math, window, DroneManager," +
" GameManager, FixedWingDroneAPI, EnemyDroneAPI, BABYLON, " + " GameManager, FixedWingDroneAPI, EnemyDroneAPI, BABYLON, " +
"GAMEPARAMETERS) {" + "GAMEPARAMETERS) {" +
"var start_time = (new Date(2070, 0, 0, 0, 0, 0, 0)).getTime();" +
"Date.now = function () {" + "Date.now = function () {" +
"return start_time + drone._tick * 1000/60;}; " + "return me._API._gameManager.getCurrentTime();}; " +
"function Date() {if (!(this instanceof Date)) " + "function Date() {if (!(this instanceof Date)) " +
"{throw new Error('Missing new operator');} " + "{throw new Error('Missing new operator');} " +
"if (arguments.length === 0) {return new NativeDate(Date.now());} " + "if (arguments.length === 0) {return new NativeDate(Date.now());} " +
...@@ -1395,6 +1409,10 @@ var GameManager = /** @class */ (function () { ...@@ -1395,6 +1409,10 @@ var GameManager = /** @class */ (function () {
} }
}; };
GameManager.prototype.getCurrentTime = function () {
return this._start_time + this._game_duration;
};
return GameManager; return GameManager;
}()); }());
......
...@@ -246,7 +246,7 @@ ...@@ -246,7 +246,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1015.21434.33254.25036</string> </value> <value> <string>1016.21924.8943.57122</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -266,7 +266,7 @@ ...@@ -266,7 +266,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1710867421.17</float> <float>1714738813.84</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -185,6 +185,7 @@ var OperatorAPI = /** @class */ (function () { ...@@ -185,6 +185,7 @@ var OperatorAPI = /** @class */ (function () {
DRAW = true, DRAW = true,
LOG = true, LOG = true,
LOG_TIME = 1662.7915426540285, LOG_TIME = 1662.7915426540285,
ONUPDATE_INTERVAL = 100,
LOGIC_FILE_LIST = [ LOGIC_FILE_LIST = [
'gadget_erp5_page_drone_capture_flag_logic.js', 'gadget_erp5_page_drone_capture_flag_logic.js',
'gadget_erp5_page_drone_capture_map_utils.js', 'gadget_erp5_page_drone_capture_map_utils.js',
...@@ -566,6 +567,17 @@ var OperatorAPI = /** @class */ (function () { ...@@ -566,6 +567,17 @@ var OperatorAPI = /** @class */ (function () {
"hidden": 0, "hidden": 0,
"type": "IntegerField" "type": "IntegerField"
}, },
"my_onupdate_interval": {
"description": "Minimum interval (in milliseconds) between 2 executions of onUpdate function as well as periodicity to send telemetry to the swarm",
"title": "OnUpdate interval",
"default": gadget.state.onupdate_interval,
"css_class": "",
"required": 1,
"editable": 1,
"key": "onupdate_interval",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_min_speed": { "my_drone_min_speed": {
"description": "", "description": "",
"title": "Drone min speed", "title": "Drone min speed",
...@@ -708,7 +720,7 @@ var OperatorAPI = /** @class */ (function () { ...@@ -708,7 +720,7 @@ var OperatorAPI = /** @class */ (function () {
form_definition: { form_definition: {
group_list: [[ group_list: [[
"left", "left",
[["my_simulation_speed"], ["my_simulation_time"], [["my_simulation_speed"], ["my_simulation_time"], ["my_onupdate_interval"],
["my_number_of_drones"], ["my_map_seed"]] ["my_number_of_drones"], ["my_map_seed"]]
], [ ], [
"right", "right",
...@@ -845,6 +857,7 @@ var OperatorAPI = /** @class */ (function () { ...@@ -845,6 +857,7 @@ var OperatorAPI = /** @class */ (function () {
"maxSinkRate": parseFloat(gadget.state.drone_max_sink_rate), "maxSinkRate": parseFloat(gadget.state.drone_max_sink_rate),
"maxClimbRate": parseFloat(gadget.state.drone_max_climb_rate), "maxClimbRate": parseFloat(gadget.state.drone_max_climb_rate),
"maxCommandFrequency": parseFloat(gadget.state.drone_max_command_frequency), "maxCommandFrequency": parseFloat(gadget.state.drone_max_command_frequency),
"onUpdateInterval": parseInt(gadget.state.onupdate_interval, 10),
"list": drone_list "list": drone_list
}, },
"gameTime": parseInt(gadget.state.simulation_time, 10), "gameTime": parseInt(gadget.state.simulation_time, 10),
...@@ -970,6 +983,7 @@ var OperatorAPI = /** @class */ (function () { ...@@ -970,6 +983,7 @@ var OperatorAPI = /** @class */ (function () {
drone_max_speed: MAX_SPEED, drone_max_speed: MAX_SPEED,
drone_speed: DEFAULT_SPEED, drone_speed: DEFAULT_SPEED,
drone_min_speed: MIN_SPEED, drone_min_speed: MIN_SPEED,
onupdate_interval: ONUPDATE_INTERVAL,
simulation_time: SIMULATION_TIME, simulation_time: SIMULATION_TIME,
simulation_speed: SIMULATION_SPEED, simulation_speed: SIMULATION_SPEED,
operator_init_msg: {}, operator_init_msg: {},
......
...@@ -246,7 +246,7 @@ ...@@ -246,7 +246,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1014.48194.32365.65399</string> </value> <value> <string>1016.21921.52144.47906</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -266,7 +266,7 @@ ...@@ -266,7 +266,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1708709921.07</float> <float>1714738877.83</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
var SIMULATION_SPEED = 1, var SIMULATION_SPEED = 1,
LOOP_INTERVAL = 1000 / 60, LOOP_INTERVAL = 1000 / 60,
ON_UPDATE_INTERVAL = LOOP_INTERVAL,
SIMULATION_TIME = LOOP_INTERVAL / 1000, SIMULATION_TIME = LOOP_INTERVAL / 1000,
MIN_LAT = 45.6364, MIN_LAT = 45.6364,
MAX_LAT = 45.65, MAX_LAT = 45.65,
...@@ -77,7 +78,8 @@ ...@@ -77,7 +78,8 @@
' time_interval = timestamp - me.start_time,\n' + ' time_interval = timestamp - me.start_time,\n' +
' expected_interval = ' + LOOP_INTERVAL + ',\n' + ' expected_interval = ' + LOOP_INTERVAL + ',\n' +
' expectedDistance = (me.getSpeed() * expected_interval / 1000).toFixed(8);\n' + ' expectedDistance = (me.getSpeed() * expected_interval / 1000).toFixed(8);\n' +
' assert(time_interval, Math.floor(expected_interval), "Timestamp");\n' + ' assert(time_interval.toFixed(4), expected_interval.toFixed(4), "Timestamp");\n' +
' assert(Date.now(), timestamp, "Date");\n' +
' assert(realDistance, expectedDistance, "Distance");\n' + ' assert(realDistance, expectedDistance, "Distance");\n' +
' current_position.latitude = current_position.latitude.toFixed(7);\n' + ' current_position.latitude = current_position.latitude.toFixed(7);\n' +
' compare(current_position, {\n' + ' compare(current_position, {\n' +
...@@ -152,6 +154,7 @@ ...@@ -152,6 +154,7 @@
"maxPitchAngle": MAX_PITCH, "maxPitchAngle": MAX_PITCH,
"maxSinkRate": MAX_SINK_RATE, "maxSinkRate": MAX_SINK_RATE,
"maxClimbRate": MAX_CLIMB_RATE, "maxClimbRate": MAX_CLIMB_RATE,
"onUpdateInterval": ON_UPDATE_INTERVAL,
"list": DRONE_LIST "list": DRONE_LIST
}, },
"gameTime": SIMULATION_TIME, "gameTime": SIMULATION_TIME,
......
...@@ -246,7 +246,7 @@ ...@@ -246,7 +246,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1015.15807.32412.36915</string> </value> <value> <string>1015.64187.34381.50346</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -266,7 +266,7 @@ ...@@ -266,7 +266,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1710526066.91</float> <float>1713428877.4</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -80,7 +80,7 @@ var DroneLogAPI = /** @class */ (function () { ...@@ -80,7 +80,7 @@ var DroneLogAPI = /** @class */ (function () {
/* /*
** Function called on every drone update, right before onUpdate AI script ** Function called on every drone update, right before onUpdate AI script
*/ */
DroneLogAPI.prototype.internal_update = function (context, delta_time) { DroneLogAPI.prototype.internal_position_update = function (context, delta_time) {
var updateSpeed; var updateSpeed;
context._speed += context._acceleration * delta_time / 1000; context._speed += context._acceleration * delta_time / 1000;
if (context._speed > context._maxSpeed) { if (context._speed > context._maxSpeed) {
...@@ -104,7 +104,7 @@ var DroneLogAPI = /** @class */ (function () { ...@@ -104,7 +104,7 @@ var DroneLogAPI = /** @class */ (function () {
/* /*
** Function called on every drone update, right after onUpdate AI script ** Function called on every drone update, right after onUpdate AI script
*/ */
DroneLogAPI.prototype.internal_post_update = function (drone) { DroneLogAPI.prototype.internal_info_update = function (drone) {
return; return;
}; };
DroneLogAPI.prototype.internal_setTargetCoordinates = DroneLogAPI.prototype.internal_setTargetCoordinates =
...@@ -213,6 +213,9 @@ var DroneLogAPI = /** @class */ (function () { ...@@ -213,6 +213,9 @@ var DroneLogAPI = /** @class */ (function () {
DroneLogAPI.prototype.getMaxCommandFrequency = function () { DroneLogAPI.prototype.getMaxCommandFrequency = function () {
return Infinity; return Infinity;
}; };
DroneLogAPI.prototype.getOnUpdateInterval = function () {
return 0;
};
return DroneLogAPI; return DroneLogAPI;
}()); }());
\ No newline at end of file
...@@ -246,7 +246,7 @@ ...@@ -246,7 +246,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1014.60631.26636.59528</string> </value> <value> <string>1015.64101.28159.26163</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -266,7 +266,7 @@ ...@@ -266,7 +266,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1709288518.39</float> <float>1713425784.77</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -102,7 +102,7 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -102,7 +102,7 @@ var FixedWingDroneAPI = /** @class */ (function () {
/* /*
** Function called on every drone update, right before onUpdate AI script ** Function called on every drone update, right before onUpdate AI script
*/ */
FixedWingDroneAPI.prototype.internal_update = function (context, delta_time) { FixedWingDroneAPI.prototype.internal_position_update = function (context, delta_time) {
this._updateSpeed(context, delta_time); this._updateSpeed(context, delta_time);
this._updatePosition(context, delta_time); this._updatePosition(context, delta_time);
...@@ -112,7 +112,7 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -112,7 +112,7 @@ var FixedWingDroneAPI = /** @class */ (function () {
/* /*
** Function called on every drone update, right after onUpdate AI script ** Function called on every drone update, right after onUpdate AI script
*/ */
FixedWingDroneAPI.prototype.internal_post_update = function (drone) { FixedWingDroneAPI.prototype.internal_info_update = function (drone) {
var _this = this, drone_position = drone.getCurrentPosition(), drone_info; var _this = this, drone_position = drone.getCurrentPosition(), drone_info;
/*if (_this._start_altitude > 0) { //TODO move start_altitude here /*if (_this._start_altitude > 0) { //TODO move start_altitude here
_this.reachAltitude(drone); _this.reachAltitude(drone);
...@@ -501,6 +501,9 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -501,6 +501,9 @@ var FixedWingDroneAPI = /** @class */ (function () {
FixedWingDroneAPI.prototype.getMaxHeight = function () { FixedWingDroneAPI.prototype.getMaxHeight = function () {
return 800; return 800;
}; };
FixedWingDroneAPI.prototype.getOnUpdateInterval = function () {
return this._flight_parameters.drone.onUpdateInterval;
};
FixedWingDroneAPI.prototype.getFlightParameters = function () { FixedWingDroneAPI.prototype.getFlightParameters = function () {
return this._flight_parameters; return this._flight_parameters;
}; };
......
...@@ -240,7 +240,7 @@ ...@@ -240,7 +240,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1015.19909.43325.57463</string> </value> <value> <string>1015.64135.23574.22357</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -260,7 +260,7 @@ ...@@ -260,7 +260,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1710776370.92</float> <float>1713425740.22</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -27,6 +27,7 @@ var DroneManager = /** @class */ (function () { ...@@ -27,6 +27,7 @@ var DroneManager = /** @class */ (function () {
this._maxClimbRate = 0; this._maxClimbRate = 0;
this._maxCommandFrequency = 0; this._maxCommandFrequency = 0;
this._last_command_timestamp = 0; this._last_command_timestamp = 0;
this._last_onUpdate_timestamp = 0;
this._speed = 0; this._speed = 0;
this._acceleration = 0; this._acceleration = 0;
this._direction = new BABYLON.Vector3(0, 0, 1); // North this._direction = new BABYLON.Vector3(0, 0, 1); // North
...@@ -124,7 +125,7 @@ var DroneManager = /** @class */ (function () { ...@@ -124,7 +125,7 @@ var DroneManager = /** @class */ (function () {
this._canCommunicate = true; this._canCommunicate = true;
this._targetCoordinates = initial_position; this._targetCoordinates = initial_position;
try { try {
return this.onStart(this._API._gameManager._game_duration); return this.onStart(this._API._gameManager._start_time);
} catch (error) { } catch (error) {
console.warn('Drone crashed on start due to error:', error); console.warn('Drone crashed on start due to error:', error);
this._internal_crash(error); this._internal_crash(error);
...@@ -132,17 +133,18 @@ var DroneManager = /** @class */ (function () { ...@@ -132,17 +133,18 @@ var DroneManager = /** @class */ (function () {
}; };
DroneManager.prototype._callSetTargetCommand = DroneManager.prototype._callSetTargetCommand =
function (latitude, longitude, altitude, speed, radius) { function (latitude, longitude, altitude, speed, radius) {
var current_time = this._API._gameManager.getCurrentTime();
if (!this.isReadyToFly()) { if (!this.isReadyToFly()) {
return; return;
} }
if (this._API._gameManager._game_duration - this._last_command_timestamp if (current_time - this._last_command_timestamp
< 1000 / this._API.getMaxCommandFrequency()) { < 1000 / this._API.getMaxCommandFrequency()) {
this._internal_crash(new Error('Minimum interval between commands is ' + this._internal_crash(new Error('Minimum interval between commands is ' +
1000 / this._API.getMaxCommandFrequency() + ' milliseconds')); 1000 / this._API.getMaxCommandFrequency() + ' milliseconds'));
} }
this._internal_setTargetCoordinates(latitude, longitude, altitude, speed, this._internal_setTargetCoordinates(latitude, longitude, altitude, speed,
radius); radius);
this._last_command_timestamp = this._API._gameManager._game_duration; this._last_command_timestamp = current_time;
}; };
/** /**
* Set a target point to move * Set a target point to move
...@@ -167,14 +169,28 @@ var DroneManager = /** @class */ (function () { ...@@ -167,14 +169,28 @@ var DroneManager = /** @class */ (function () {
); );
}; };
DroneManager.prototype.internal_update = function (delta_time) { DroneManager.prototype.internal_update = function (delta_time) {
var context = this; var context = this,
current_time = this._API._gameManager.getCurrentTime(),
onUpdate_interval = this._API.getOnUpdateInterval(),
onUpdate_start;
if (this._controlMesh) { if (this._controlMesh) {
context._API.internal_update(context, delta_time); context._API.internal_position_update(context, delta_time);
if (context._canUpdate) { if (context._canUpdate &&
current_time - this._last_onUpdate_timestamp >= onUpdate_interval) {
context._canUpdate = false; context._canUpdate = false;
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
return context.onUpdate(context._API._gameManager._game_duration); onUpdate_start = Date.now();
context._last_onUpdate_timestamp = current_time;
context.onUpdate(current_time);
if (onUpdate_interval > 0 &&
Date.now() - onUpdate_start > onUpdate_interval) {
throw new Error('onUpdate execution took ' +
(Date.now() - onUpdate_start) +
' milliseconds but loop interval is only ' +
onUpdate_interval +
' milliseconds');
}
}) })
.push(function () { .push(function () {
context._canUpdate = true; context._canUpdate = true;
...@@ -183,7 +199,7 @@ var DroneManager = /** @class */ (function () { ...@@ -183,7 +199,7 @@ var DroneManager = /** @class */ (function () {
context._internal_crash(error); context._internal_crash(error);
}) })
.push(function () { .push(function () {
context._API.internal_post_update(context); context._API.internal_info_update(context);
}) })
.push(undefined, function (error) { .push(undefined, function (error) {
console.warn('Drone crashed on update due to error:', error); console.warn('Drone crashed on update due to error:', error);
...@@ -282,7 +298,7 @@ var DroneManager = /** @class */ (function () { ...@@ -282,7 +298,7 @@ var DroneManager = /** @class */ (function () {
this._controlMesh.position.z, this._controlMesh.position.z,
this._controlMesh.position.y this._controlMesh.position.y
); );
position.timestamp = this._API._gameManager._game_duration; position.timestamp = this._API._gameManager.getCurrentTime();
return position; return position;
} }
return null; return null;
...@@ -666,7 +682,6 @@ var GameManager = /** @class */ (function () { ...@@ -666,7 +682,6 @@ var GameManager = /** @class */ (function () {
this._droneList.forEach(function (drone) { this._droneList.forEach(function (drone) {
queue.push(function () { queue.push(function () {
drone._tick += 1;
if (drone._API.isCollidable && drone.can_play) { if (drone._API.isCollidable && drone.can_play) {
if (drone.getCurrentPosition().altitude <= 0) { if (drone.getCurrentPosition().altitude <= 0) {
if (!drone.isLanding()) { if (!drone.isLanding()) {
...@@ -705,7 +720,8 @@ var GameManager = /** @class */ (function () { ...@@ -705,7 +720,8 @@ var GameManager = /** @class */ (function () {
this._game_duration += delta_time; this._game_duration += delta_time;
var color, drone_position, game_manager = this, geo_coordinates, var color, drone_position, game_manager = this, geo_coordinates,
log_count, map_info, map_manager, material, position_obj, log_count, map_info, map_manager, material, position_obj,
seconds = Math.floor(this._game_duration / 1000), trace_objects; current_time = this.getCurrentTime(),
seconds = Math.floor(current_time / 1000), trace_objects;
if (GAMEPARAMETERS.log_drone_flight || GAMEPARAMETERS.draw_flight_path) { if (GAMEPARAMETERS.log_drone_flight || GAMEPARAMETERS.draw_flight_path) {
this._droneList.forEach(function (drone, index) { this._droneList.forEach(function (drone, index) {
...@@ -724,7 +740,7 @@ var GameManager = /** @class */ (function () { ...@@ -724,7 +740,7 @@ var GameManager = /** @class */ (function () {
drone_position.z drone_position.z
); );
game_manager._flight_log[index].push([ game_manager._flight_log[index].push([
game_manager._game_duration, geo_coordinates.latitude, current_time, geo_coordinates.latitude,
geo_coordinates.longitude, geo_coordinates.longitude,
map_info.start_AMSL + drone_position.z, map_info.start_AMSL + drone_position.z,
drone_position.z, drone.getYaw(), drone.getSpeed(), drone_position.z, drone.getYaw(), drone.getSpeed(),
...@@ -909,14 +925,14 @@ var GameManager = /** @class */ (function () { ...@@ -909,14 +925,14 @@ var GameManager = /** @class */ (function () {
_this.ongoing_update_promise = null; _this.ongoing_update_promise = null;
_this.finish_deferred = RSVP.defer(); _this.finish_deferred = RSVP.defer();
console.log("Simulation started."); console.log("Simulation started.");
this._game_duration = Date.now(); this._start_time = Date.now();
this._totalTime = GAMEPARAMETERS.gameTime * 1000 + this._game_duration; this._game_duration = 0;
this._totalTime = GAMEPARAMETERS.gameTime * 1000;
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
promise_list = []; promise_list = [];
_this._droneList.forEach(function (drone) { _this._droneList.forEach(function (drone) {
drone._tick = 0;
promise_list.push(drone.internal_start( promise_list.push(drone.internal_start(
_this._mapManager.getMapInfo().initial_position _this._mapManager.getMapInfo().initial_position
)); ));
...@@ -998,9 +1014,8 @@ var GameManager = /** @class */ (function () { ...@@ -998,9 +1014,8 @@ var GameManager = /** @class */ (function () {
"let droneMe = function(NativeDate, me, Math, window, DroneManager," + "let droneMe = function(NativeDate, me, Math, window, DroneManager," +
" GameManager, DroneLogAPI, FixedWingDroneAPI, BABYLON, " + " GameManager, DroneLogAPI, FixedWingDroneAPI, BABYLON, " +
"GAMEPARAMETERS) {" + "GAMEPARAMETERS) {" +
"var start_time = (new Date(2070, 0, 0, 0, 0, 0, 0)).getTime();" +
"Date.now = function () {" + "Date.now = function () {" +
"return start_time + drone._tick * 1000/60;}; " + "return me._API._gameManager.getCurrentTime();}; " +
"function Date() {if (!(this instanceof Date)) " + "function Date() {if (!(this instanceof Date)) " +
"{throw new Error('Missing new operator');} " + "{throw new Error('Missing new operator');} " +
"if (arguments.length === 0) {return new NativeDate(Date.now());} " + "if (arguments.length === 0) {return new NativeDate(Date.now());} " +
...@@ -1056,6 +1071,10 @@ var GameManager = /** @class */ (function () { ...@@ -1056,6 +1071,10 @@ var GameManager = /** @class */ (function () {
} }
}; };
GameManager.prototype.getCurrentTime = function () {
return this._start_time + this._game_duration;
};
return GameManager; return GameManager;
}()); }());
......
...@@ -240,7 +240,7 @@ ...@@ -240,7 +240,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1015.21426.50931.23620</string> </value> <value> <string>1016.21930.60269.31744</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -260,7 +260,7 @@ ...@@ -260,7 +260,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1710926073.14</float> <float>1714739216.07</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -128,6 +128,7 @@ ...@@ -128,6 +128,7 @@
DRAW = true, DRAW = true,
LOG = true, LOG = true,
LOG_TIME = 1662.7915426540285, LOG_TIME = 1662.7915426540285,
ONUPDATE_INTERVAL = 100,
DRONE_LIST = [], DRONE_LIST = [],
WIDTH = 680, WIDTH = 680,
HEIGHT = 340, HEIGHT = 340,
...@@ -192,6 +193,17 @@ ...@@ -192,6 +193,17 @@
"hidden": 0, "hidden": 0,
"type": "IntegerField" "type": "IntegerField"
}, },
"my_onupdate_interval": {
"description": "Minimum interval (in milliseconds) between 2 executions of onUpdate function as well as periodicity to send telemetry to the swarm",
"title": "OnUpdate interval",
"default": ONUPDATE_INTERVAL,
"css_class": "",
"required": 1,
"editable": 1,
"key": "onupdate_interval",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_min_speed": { "my_drone_min_speed": {
"description": "", "description": "",
"title": "Drone min speed", "title": "Drone min speed",
...@@ -445,8 +457,8 @@ ...@@ -445,8 +457,8 @@
form_definition: { form_definition: {
group_list: [[ group_list: [[
"left", "left",
[["my_simulation_speed"], ["my_simulation_time"], ["my_number_of_drones"], [["my_simulation_speed"], ["my_simulation_time"], ["my_onupdate_interval"],
["my_minimum_latitud"], ["my_maximum_latitud"], ["my_number_of_drones"], ["my_minimum_latitud"], ["my_maximum_latitud"],
["my_minimum_longitud"], ["my_maximum_longitud"], ["my_minimum_longitud"], ["my_maximum_longitud"],
["my_init_pos_lat"], ["my_init_pos_lon"], ["my_init_pos_alt"], ["my_init_pos_lat"], ["my_init_pos_lon"], ["my_init_pos_alt"],
["my_map_height"]] ["my_map_height"]]
...@@ -495,7 +507,8 @@ ...@@ -495,7 +507,8 @@
"maxPitchAngle": parseFloat(options.drone_max_pitch), "maxPitchAngle": parseFloat(options.drone_max_pitch),
"maxSinkRate": parseFloat(options.drone_max_sink_rate), "maxSinkRate": parseFloat(options.drone_max_sink_rate),
"maxClimbRate": parseFloat(options.drone_max_climb_rate), "maxClimbRate": parseFloat(options.drone_max_climb_rate),
"maxCommandFrequency": parseFloat(options.drone_max_command_frequency) "maxCommandFrequency": parseFloat(options.drone_max_command_frequency),
"onUpdateInterval": parseInt(options.onupdate_interval, 10)
}, },
"gameTime": parseInt(options.simulation_time, 10), "gameTime": parseInt(options.simulation_time, 10),
"simulation_speed": parseInt(options.simulation_speed, 10), "simulation_speed": parseInt(options.simulation_speed, 10),
......
...@@ -246,7 +246,7 @@ ...@@ -246,7 +246,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1015.15836.20157.60791</string> </value> <value> <string>1015.64120.46679.6946</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -266,7 +266,7 @@ ...@@ -266,7 +266,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1710527785.95</float> <float>1713425712.2</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
var SIMULATION_SPEED = 1, var SIMULATION_SPEED = 1,
LOOP_INTERVAL = 1000 / 60, LOOP_INTERVAL = 1000 / 60,
ON_UPDATE_INTERVAL = LOOP_INTERVAL,
SIMULATION_TIME = LOOP_INTERVAL / 1000, SIMULATION_TIME = LOOP_INTERVAL / 1000,
DEFAULT_SPEED = 16, DEFAULT_SPEED = 16,
MAX_ACCELERATION = 6, MAX_ACCELERATION = 6,
...@@ -78,6 +79,7 @@ ...@@ -78,6 +79,7 @@
' expected_interval = ' + LOOP_INTERVAL + ',\n' + ' expected_interval = ' + LOOP_INTERVAL + ',\n' +
' expectedDistance = (me.getSpeed() * expected_interval / 1000).toFixed(8);\n' + ' expectedDistance = (me.getSpeed() * expected_interval / 1000).toFixed(8);\n' +
' assert(time_interval.toFixed(4), expected_interval.toFixed(4), "Timestamp");\n' + ' assert(time_interval.toFixed(4), expected_interval.toFixed(4), "Timestamp");\n' +
' assert(Date.now(), timestamp, "Date");\n' +
' assert(realDistance, expectedDistance, "Distance");\n' + ' assert(realDistance, expectedDistance, "Distance");\n' +
' current_position.latitude = current_position.latitude.toFixed(7);\n' + ' current_position.latitude = current_position.latitude.toFixed(7);\n' +
' compare(current_position, {\n' + ' compare(current_position, {\n' +
...@@ -180,7 +182,8 @@ ...@@ -180,7 +182,8 @@
"minPitchAngle": MIN_PITCH, "minPitchAngle": MIN_PITCH,
"maxPitchAngle": MAX_PITCH, "maxPitchAngle": MAX_PITCH,
"maxSinkRate": MAX_SINK_RATE, "maxSinkRate": MAX_SINK_RATE,
"maxClimbRate": MAX_CLIMB_RATE "maxClimbRate": MAX_CLIMB_RATE,
"onUpdateInterval": ON_UPDATE_INTERVAL
}, },
"gameTime": SIMULATION_TIME, "gameTime": SIMULATION_TIME,
"simulation_speed": SIMULATION_SPEED, "simulation_speed": SIMULATION_SPEED,
......
...@@ -246,7 +246,7 @@ ...@@ -246,7 +246,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1015.15809.60561.48213</string> </value> <value> <string>1015.64176.45813.63488</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -266,7 +266,7 @@ ...@@ -266,7 +266,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1710526207.55</float> <float>1713428376.53</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment