Commit 2f7689d1 authored by Léo-Paul Géneau's avatar Léo-Paul Géneau 👾

erp5_officejs_drone_simulator: add max_command_frequency

See merge request !1894

* set _game_duration as an unix epoch
* provide timestamp to onStart function
* add max_command_frequency, if direction commands (setTargetCoordinates
  and loiter) are send more often than max frenquency the drone crashes
parent 90524d25
......@@ -241,7 +241,7 @@ var EnemyDroneAPI = /** @class */ (function () {
' return Math.sqrt((a.x - b.x) ** 2 + (a.y - b.y) ** 2 + (a.z - b.z) ** 2);\n' +
'}\n' +
'\n' +
'me.onStart = function () {\n' +
'me.onStart = function (timestamp) {\n' +
' me.setDirection(0,0,0);\n' +
' return;\n' +
'\n' +
......@@ -280,6 +280,9 @@ var EnemyDroneAPI = /** @class */ (function () {
EnemyDroneAPI.prototype.getMaxAcceleration = function () {
return this._flight_parameters.drone.maxAcceleration;
};
EnemyDroneAPI.prototype.getMaxCommandFrequency = function () {
return Infinity;
};
EnemyDroneAPI.prototype.land = function (drone) {
var drone_pos = drone.getCurrentPosition();
drone.setTargetCoordinates(drone_pos.latitude, drone_pos.longitude, 0);
......
......@@ -246,7 +246,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1014.56714.1017.16076</string> </value>
<value> <string>1014.60631.26636.59528</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -266,7 +266,7 @@
</tuple>
<state>
<tuple>
<float>1709221104.19</float>
<float>1709288499.16</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -88,6 +88,10 @@ var FixedWingDroneAPI = /** @class */ (function () {
if (drone._maxClimbRate > drone._maxSpeed) {
throw new Error('max climb rate cannot be superior to max speed');
}
drone._maxCommandFrequency = this.getMaxCommandFrequency();
if (drone._maxCommandFrequency <= 0) {
throw new Error('max command frequence must be superior to 0');
}
return;
};
/*
......@@ -450,6 +454,9 @@ var FixedWingDroneAPI = /** @class */ (function () {
FixedWingDroneAPI.prototype.getMaxClimbRate = function () {
return this._flight_parameters.drone.maxClimbRate;
};
FixedWingDroneAPI.prototype.getMaxCommandFrequency = function () {
return this._flight_parameters.drone.maxCommandFrequency;
};
FixedWingDroneAPI.prototype.getYawVelocity = function (drone) {
return 360 * EARTH_GRAVITY *
Math.tan(this._toRad(this.getMaxRollAngle())) /
......
......@@ -246,7 +246,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1014.56746.48697.2713</string> </value>
<value> <string>1014.60714.57448.36454</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -266,7 +266,7 @@
</tuple>
<state>
<tuple>
<float>1709223091.4</float>
<float>1709288420.35</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -25,6 +25,8 @@ var DroneManager = /** @class */ (function () {
this._maxRollAngle = 0;
this._maxSinkRate = 0;
this._maxClimbRate = 0;
this._maxCommandFrequency = 0;
this._last_command_timestamp = 0;
this._speed = 0;
this._acceleration = 0;
this._direction = new BABYLON.Vector3(0, 0, 1); // North
......@@ -138,7 +140,7 @@ var DroneManager = /** @class */ (function () {
this._canPlay = true;
this._canCommunicate = true;
try {
return this.onStart();
return this.onStart(this._API._gameManager._game_duration);
} catch (error) {
console.warn('Drone crashed on start due to error:', error);
this._internal_crash(error);
......@@ -156,16 +158,22 @@ var DroneManager = /** @class */ (function () {
if (!this._canPlay || !this.isReadyToFly()) {
return;
}
if (this._API._gameManager._game_duration - this._last_command_timestamp
< 1000 / this._API.getMaxCommandFrequency()) {
this._internal_crash(new Error('Minimum interval between commands is ' +
1000 / this._API.getMaxCommandFrequency() + ' milliseconds'));
}
//each drone API process coordinates on its needs
//e.g. fixedwing drone converts real geo-coordinates to virtual x-y
this._targetCoordinates =
this._API.processCoordinates(latitude, longitude, altitude);
return this._API.internal_setTargetCoordinates(
this._API.internal_setTargetCoordinates(
this,
this._targetCoordinates,
speed,
radius
);
this._last_command_timestamp = this._API._gameManager._game_duration;
};
/**
* Returns the list of things a drone "sees"
......@@ -373,7 +381,7 @@ var DroneManager = /** @class */ (function () {
/**
* Function called on game start
*/
DroneManager.prototype.onStart = function () { return; };
DroneManager.prototype.onStart = function (timestamp) { return; };
/**
* Function called on game update
* @param timestamp The tic value
......@@ -1219,8 +1227,8 @@ var GameManager = /** @class */ (function () {
_this.ongoing_update_promise = null;
_this.finish_deferred = RSVP.defer();
console.log("Simulation started.");
this._game_duration = 0;
this._totalTime = GAMEPARAMETERS.gameTime;
this._game_duration = Date.now();
this._totalTime = GAMEPARAMETERS.gameTime + this._game_duration;
return new RSVP.Queue()
.push(function () {
......
......@@ -246,7 +246,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1014.56745.33504.26197</string> </value>
<value> <string>1014.60733.7318.44953</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -266,7 +266,7 @@
</tuple>
<state>
<tuple>
<float>1709223446.72</float>
<float>1709546292.39</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -153,14 +153,24 @@
<h3>Functions called by game on event</h3>
<!-- Start -->
<h4 class="item-name" id="start"><span>onStart</span><span>: void</span></h4>
<h4 class="item-name" id="start"><span>onStart</span><span>: timestamp</span></h4>
<p class="item-descr">Function called on game start.</p>
<div>
<h5 class="item-param-1">Param</h5>
<h5 class="item-param-2">Description</h5>
</div>
<div>
<p class="item-param-1">timestamp: Integer</p>
<p class="item-param-2">Timestamp in milliseconds from UNIX epoch</p>
</div>
<div>
<h5 class="item-param-1">Example</h5>
</div>
<p class="item-param-1">me.onStart = function() {<br>
<p class="item-param-1">me.onStart = function(timestamp) {<br>
&nbsp;&nbsp;//one time execution code<br>
}
</p>
......@@ -168,7 +178,7 @@
<div class="line"></div>
<!-- Update -->
<h4 class="item-name" id="update"><span>onUpdate</span><span>: void</span></h4>
<h4 class="item-name" id="update"><span>onUpdate</span><span>: timestamp</span></h4>
<p class="item-descr">Function called on game update, 60 times / second. <br></p>
<div>
......@@ -183,7 +193,7 @@
<h5 class="item-param-1">Example</h5>
<p class="item-example">me.onUpdate = function() {<br>
<p class="item-example">me.onUpdate = function(timestamp) {<br>
&nbsp;&nbsp;//code executed 60 times per second<br>
}
</p>
......
......@@ -244,7 +244,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1014.46767.47211.3123</string> </value>
<value> <string>1014.48209.18178.31351</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -264,7 +264,7 @@
</tuple>
<state>
<tuple>
<float>1708688564.0</float>
<float>1708710825.64</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -246,7 +246,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1014.46368.9372.48435</string> </value>
<value> <string>1014.48194.32365.65399</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -266,7 +266,7 @@
</tuple>
<state>
<tuple>
<float>1708616910.25</float>
<float>1708709921.07</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -52,10 +52,11 @@
' assert(coord1.altitude, coord2.altitude, "Altitude")\n' +
'}\n' +
'\n' +
'me.onStart = function () {\n' +
'me.onStart = function (timestamp) {\n' +
' assert(me.getSpeed(), ' + DEFAULT_SPEED + ', "Initial speed");\n' +
' assert(me.getYaw(), 0, "Yaw angle")\n' +
' me.initialPosition = me.getCurrentPosition();\n' +
' me.start_time = timestamp;\n' +
' me.setTargetCoordinates(\n' +
' me.initialPosition.latitude + 0.01,\n' +
' me.initialPosition.longitude,\n' +
......@@ -72,9 +73,10 @@
' me.getCurrentPosition().latitude,\n' +
' me.getCurrentPosition().longitude\n' +
' ).toFixed(8),\n' +
' time_interval = 1000 / 60,\n' +
' expectedDistance = (me.getSpeed() * time_interval / 1000).toFixed(8);\n' +
' assert(timestamp, Math.floor(time_interval), "Timestamp");\n' +
' time_interval = timestamp - me.start_time,\n' +
' expected_interval = 1000 / 60,\n' +
' expectedDistance = (me.getSpeed() * expected_interval / 1000).toFixed(8);\n' +
' assert(time_interval, Math.floor(expected_interval), "Timestamp");\n' +
' assert(realDistance, expectedDistance, "Distance");\n' +
' current_position.latitude = current_position.latitude.toFixed(7);\n' +
' compare(current_position, {\n' +
......
......@@ -246,7 +246,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1014.55287.25371.8430</string> </value>
<value> <string>1014.60680.20078.34286</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -266,7 +266,7 @@
</tuple>
<state>
<tuple>
<float>1709136147.57</float>
<float>1709286290.59</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -210,6 +210,9 @@ var DroneLogAPI = /** @class */ (function () {
DroneLogAPI.prototype.isReadyToFly = function () {
return true;
};
DroneLogAPI.prototype.getMaxCommandFrequency = function () {
return Infinity;
};
return DroneLogAPI;
}());
\ No newline at end of file
......@@ -246,7 +246,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1014.12050.13065.34372</string> </value>
<value> <string>1014.60631.26636.59528</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -266,7 +266,7 @@
</tuple>
<state>
<tuple>
<float>1706542267.28</float>
<float>1709288518.39</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -92,6 +92,10 @@ var FixedWingDroneAPI = /** @class */ (function () {
if (drone._maxClimbRate > drone._maxSpeed) {
throw new Error('max climb rate cannot be superior to max speed');
}
drone._maxCommandFrequency = this.getMaxCommandFrequency();
if (drone._maxCommandFrequency <= 0) {
throw new Error('max command frequence must be superior to 0');
}
return;
};
/*
......@@ -408,6 +412,9 @@ var FixedWingDroneAPI = /** @class */ (function () {
FixedWingDroneAPI.prototype.getMaxClimbRate = function () {
return this._flight_parameters.drone.maxClimbRate;
};
FixedWingDroneAPI.prototype.getMaxCommandFrequency = function () {
return this._flight_parameters.drone.maxCommandFrequency;
};
FixedWingDroneAPI.prototype.getYawVelocity = function (drone) {
return 360 * EARTH_GRAVITY
* Math.tan(this._toRad(this.getMaxRollAngle()))
......
......@@ -240,7 +240,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1014.12067.27492.45397</string> </value>
<value> <string>1014.60724.24572.64853</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -260,7 +260,7 @@
</tuple>
<state>
<tuple>
<float>1706542739.07</float>
<float>1709289024.77</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -25,6 +25,8 @@ var DroneManager = /** @class */ (function () {
this._maxRollAngle = 0;
this._maxSinkRate = 0;
this._maxClimbRate = 0;
this._maxCommandFrequency = 0;
this._last_command_timestamp = 0;
this._speed = 0;
this._acceleration = 0;
this._direction = new BABYLON.Vector3(0, 0, 1); // North
......@@ -124,7 +126,7 @@ var DroneManager = /** @class */ (function () {
this._canCommunicate = true;
this._targetCoordinates = initial_position;
try {
return this.onStart();
return this.onStart(this._API._gameManager._game_duration);
} catch (error) {
console.warn('Drone crashed on start due to error:', error);
this._internal_crash(error);
......@@ -142,15 +144,21 @@ var DroneManager = /** @class */ (function () {
if (!this._canPlay || !this.isReadyToFly()) {
return;
}
if (this._API._gameManager._game_duration - this._last_command_timestamp
< 1000 / this._API.getMaxCommandFrequency()) {
this._internal_crash(new Error('Minimum interval between commands is ' +
1000 / this._API.getMaxCommandFrequency() + ' milliseconds'));
}
//convert real geo-coordinates to virtual x-y coordinates
this._targetCoordinates =
this._API.processCoordinates(latitude, longitude, altitude);
return this._API.internal_setTargetCoordinates(
this._API.internal_setTargetCoordinates(
this,
this._targetCoordinates,
speed,
radius
);
this._last_command_timestamp = this._API._gameManager._game_duration;
};
DroneManager.prototype.internal_update = function (delta_time) {
var context = this;
......@@ -328,7 +336,7 @@ var DroneManager = /** @class */ (function () {
/**
* Function called on game start
*/
DroneManager.prototype.onStart = function () { return; };
DroneManager.prototype.onStart = function (timestamp) { return; };
/**
* Function called on game update
* @param timestamp The tic value
......@@ -895,8 +903,8 @@ var GameManager = /** @class */ (function () {
_this.ongoing_update_promise = null;
_this.finish_deferred = RSVP.defer();
console.log("Simulation started.");
this._game_duration = 0;
this._totalTime = GAMEPARAMETERS.gameTime;
this._game_duration = Date.now();
this._totalTime = GAMEPARAMETERS.gameTime + this._game_duration;
return new RSVP.Queue()
.push(function () {
......
......@@ -240,7 +240,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1014.12072.47950.5358</string> </value>
<value> <string>1014.60716.53618.32563</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -260,7 +260,7 @@
</tuple>
<state>
<tuple>
<float>1706542965.82</float>
<float>1709288704.17</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -22,6 +22,7 @@
MAX_PITCH = 25,
MAX_CLIMB_RATE = 8,
MAX_SINK_RATE = 3,
MAX_COMMAND_FREQUENCY = 2,
INITIAL_POSITION = {
"latitude": 45.6412,
"longitude": 14.2658,
......@@ -87,12 +88,12 @@
' return 2 * R * Math.asin(Math.sqrt(h));\n' +
'}\n' +
'\n' +
'me.onStart = function () {\n' +
'me.onStart = function (timestamp) {\n' +
' me.direction_set = false;\n' +
' me.next_checkpoint = 0;\n' +
'};\n' +
'\n' +
'me.onUpdate = function (timestamp) {' +
'me.onUpdate = function (timestamp) {\n' +
' if (!me.direction_set) {\n' +
' if (me.next_checkpoint < CHECKPOINT_LIST.length) {\n' +
' me.setTargetCoordinates(\n' +
......@@ -300,6 +301,17 @@
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_command_frequency": {
"description": "",
"title": "Drone max command frequency",
"default": MAX_COMMAND_FREQUENCY,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_command_frequency",
"hidden": 0,
"type": "FloatField"
},
"my_minimum_latitud": {
"description": "",
"title": "Minimum latitude",
......@@ -442,7 +454,8 @@
[["my_start_AMSL"], ["my_drone_min_speed"], ["my_drone_speed"],
["my_drone_max_speed"], ["my_drone_max_acceleration"],
["my_drone_max_deceleration"], ["my_drone_max_roll"], ["my_drone_min_pitch"],
["my_drone_max_pitch"], ["my_drone_max_sink_rate"], ["my_drone_max_climb_rate"]]
["my_drone_max_pitch"], ["my_drone_max_sink_rate"], ["my_drone_max_climb_rate"],
["my_drone_max_command_frequency"]]
], [
"bottom",
[["my_script"]]
......@@ -480,7 +493,8 @@
"minPitchAngle": parseFloat(options.drone_min_pitch),
"maxPitchAngle": parseFloat(options.drone_max_pitch),
"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)
},
"gameTime": parseInt(options.simulation_time, 10),
"simulation_speed": parseInt(options.simulation_speed, 10),
......
......@@ -246,7 +246,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1014.11755.64575.41864</string> </value>
<value> <string>1014.60725.60577.24917</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -266,7 +266,7 @@
</tuple>
<state>
<tuple>
<float>1706525997.75</float>
<float>1709289017.41</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -56,15 +56,16 @@
' assert(coord1.altitude, coord2.altitude, "Altitude")\n' +
'}\n' +
'\n' +
'me.onStart = function () {\n' +
'me.onStart = function (timestamp) {\n' +
' assert(me.getSpeed(), ' + DEFAULT_SPEED + ', "Initial speed");\n' +
' assert(me.getYaw(), 0, "Yaw angle")\n' +
' me.initialPosition = me.getCurrentPosition();\n' +
' me.start_time = timestamp;\n' +
' me.setTargetCoordinates(\n' +
' me.initialPosition.latitude + 0.01,\n' +
' me.initialPosition.longitude,\n' +
' me.getAltitudeAbs(),\n' +
' '+ DEFAULT_SPEED + '\n' +
' ' + DEFAULT_SPEED + '\n' +
' );\n' +
'};\n' +
'\n' +
......@@ -76,8 +77,10 @@
' me.getCurrentPosition().latitude,\n' +
' me.getCurrentPosition().longitude\n' +
' ).toFixed(8),\n' +
' expectedDistance = (me.getSpeed() * timestamp / 1000).toFixed(8);\n' +
' assert(timestamp, 1000 / 60, "Timestamp");\n' +
' time_interval = timestamp - me.start_time,\n' +
' expected_interval = 1000 / 60,\n' +
' expectedDistance = (me.getSpeed() * expected_interval / 1000).toFixed(8);\n' +
' assert(time_interval.toFixed(4), expected_interval.toFixed(4), "Timestamp");\n' +
' assert(realDistance, expectedDistance, "Distance");\n' +
' current_position.latitude = current_position.latitude.toFixed(7);\n' +
' compare(current_position, {\n' +
......
......@@ -246,7 +246,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1014.55287.25371.8430</string> </value>
<value> <string>1014.60681.20667.37171</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -266,7 +266,7 @@
</tuple>
<state>
<tuple>
<float>1709136309.62</float>
<float>1709286436.53</float>
<string>UTC</string>
</tuple>
</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