diff --git a/conf/messages.xml b/conf/messages.xml
index 2a0a31f1ba..95d2bf18f2 100644
--- a/conf/messages.xml
+++ b/conf/messages.xml
@@ -367,6 +367,14 @@
+
+
+
+
+
+
+
+
diff --git a/sw/simulator/Makefile b/sw/simulator/Makefile
index 4d7e66b031..1c8a3c587b 100644
--- a/sw/simulator/Makefile
+++ b/sw/simulator/Makefile
@@ -54,7 +54,7 @@ SIMDIR=$(shell echo `pwd`)
#all : simhitl.out sitl.cma $(GEN_DOWNLINK)
-all : sitl.cma $(GEN_DOWNLINK)
+all : gaia sitl.cma $(GEN_DOWNLINK)
sim_sitl : $(OBJDIR)/simsitl
@@ -77,6 +77,12 @@ $(OBJDIR)/simsitl : $(OBJDIR)/$(SIMSA) $(OBJDIR)/simsitl.ml
echo 'lablgtk2 -I $$PAPARAZZI_SRC/sw/lib/ocaml -I $(OBJDIR) glibivy-ocaml.cma xml-light.cma lib-pprz.cma $(SIMSA) $$PAPARAZZI_SRC/sw/simulator/sitl.cma -I $$PAPARAZZI_SRC/sw/simulator $(OBJDIR)/simsitl.ml $$*' >> $@
chmod a+x $@
+gaia : gaia.ml
+ $(OCAMLC) $(INCLUDES) -o $@ glibivy-ocaml.cma xml-light.cma unix.cma lib-pprz.cma lablgtk.cma gtkInit.cmo gaia.ml # To check
+ cat ../../pprz_src_test.sh > $@
+ echo 'lablgtk2 -I $$PAPARAZZI_SRC/sw/lib/ocaml glibivy-ocaml.cma xml-light.cma unix.cma lib-pprz.cma lablgtk.cma gtkInit.cmo $$PAPARAZZI_SRC/sw/simulator/gaia.ml $$*' >> $@
+ chmod a+x $@
+
$(OBJDIR)/simsitl.opt : $(SIMSO) $(OBJDIR)/simsitl.cmx
$(OCAMLOPT) $(INCLUDES) -o $@ str.cmxa glibivy-ocaml.cmxa xml-light.cmxa unix.cmxa lib.cmxa lablgtk.cmxa gtkInit.cmx $(SIMSO) sitl.cmxa $(OBJDIR)/simsitl.cmx
diff --git a/sw/simulator/flightModel.ml b/sw/simulator/flightModel.ml
index 6db418dd36..f7373cbbfb 100644
--- a/sw/simulator/flightModel.ml
+++ b/sw/simulator/flightModel.ml
@@ -1,3 +1,29 @@
+(*
+ * $Id$
+ *
+ * Basic flight model for simulation
+ *
+ * Copyright (C) 2004 Pascal Brisset, Antoine Drouin
+ *
+ * This file is part of paparazzi.
+ *
+ * paparazzi is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * paparazzi is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with paparazzi; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ *)
+
open Stdlib
type meter = float
@@ -84,9 +110,8 @@ let yaw_response_factor = float_value simu_section "YAW_RESPONSE_FACTOR"
let weight = float_value simu_section "WEIGHT"
- let state_update = fun state (wx, wy) ->
- let now = Unix.gettimeofday () -. state.start in
- let dt = now -. state.t in
+ let state_update = fun state (wx, wy) dt ->
+ let now = state.t +. dt in
if state.air_speed > 0. then begin
let phi_dot_dot = roll_response_factor *. state.delta_a +. c_lp *. state.phi_dot /. state.air_speed in
state.phi_dot <- state.phi_dot +. phi_dot_dot *. dt;
diff --git a/sw/simulator/flightModel.mli b/sw/simulator/flightModel.mli
index ef32dc9e6b..1f71597edd 100644
--- a/sw/simulator/flightModel.mli
+++ b/sw/simulator/flightModel.mli
@@ -18,5 +18,5 @@ module Make :
val do_servos : state -> Stdlib.us array -> unit
val nb_servos : int
val nominal_airspeed : float (* m/s *)
- val state_update : state -> float * float -> unit
+ val state_update : state -> float * float -> float -> unit
end
diff --git a/sw/simulator/gaia.ml b/sw/simulator/gaia.ml
new file mode 100644
index 0000000000..116d2e86ff
--- /dev/null
+++ b/sw/simulator/gaia.ml
@@ -0,0 +1,101 @@
+(*
+ * $Id$
+ *
+ * World environment (time, wind, ...) for multi-AC simulation
+ *
+ * Copyright (C) 2004 Pascal Brisset, Antoine Drouin
+ *
+ * This file is part of paparazzi.
+ *
+ * paparazzi is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * paparazzi is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with paparazzi; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ *)
+
+open Printf
+open Latlong
+
+let my_id = "gaia"
+
+module Ground_Pprz = Pprz.Protocol(struct let name = "ground" end)
+
+let ivy_bus = ref "127.255.255.255:2010"
+
+let parse_args = fun () ->
+ let options =
+ [ "-b", Arg.String (fun x -> ivy_bus := x), (sprintf "Bus\tDefault is %s" !ivy_bus)] in
+ Arg.parse (options)
+ (fun x -> Printf.fprintf stderr "Warning: Don't do anythig with %s\n" x)
+ "Usage: "
+
+let _ =
+ parse_args ();
+ let window = GWindow.window ~title:"Gaia" () in
+ let quit = fun () -> GMain.Main.quit (); exit 0 in
+ ignore (window#connect#destroy ~callback:quit);
+
+ let time_scale = GData.adjustment ~value:1. ~lower:(0.) ~upper:10. ~step_incr:1. () in
+ let wind_dir_adj = GData.adjustment ~value:0. ~lower:(0.) ~upper:370. ~step_incr:1.0 () in
+ let wind_speed_adj = GData.adjustment ~value:0. ~lower:(0.) ~upper:20. ~step_incr:0.1 () in
+ let gust_norm_max_adj = GData.adjustment ~value:0. ~lower:(0.) ~upper:20. ~step_incr:0.1 () in
+ let infrared_contrast_adj = GData.adjustment ~value:500. ~lower:(0.) ~upper:1010. ~step_incr:10. () in
+
+ let world_values = fun () ->
+ let wind_dir_rad = Latlong.pi /. 2. -. (Deg>>Rad) wind_dir_adj#value in
+ let wind_east = wind_speed_adj#value *. cos wind_dir_rad
+ and wind_north = wind_speed_adj#value *. sin wind_dir_rad in
+ [ "wind_east", Pprz.Float wind_east;
+ "wind_north", Pprz.Float wind_north;
+ "ir_contrast", Pprz.Float infrared_contrast_adj#value;
+ "time_scale", Pprz.Float time_scale#value ] in
+ let world_send = fun () ->
+ Ground_Pprz.message_send my_id "WORLD_ENV" (world_values ()) in
+
+ List.iter
+ (fun (a:GData.adjustment) -> ignore (a#connect#value_changed world_send))
+ [time_scale; wind_dir_adj; wind_speed_adj; gust_norm_max_adj;
+ infrared_contrast_adj];
+
+
+ let vbox = GPack.vbox ~packing:window#add () in
+
+ let hbox = GPack.hbox ~packing:vbox#pack () in
+ let _ = GMisc.label ~text:"time scale:" ~packing:hbox#pack () in
+ let ts = GEdit.spin_button ~adjustment:time_scale ~packing:hbox#add () in
+
+ let hbox = GPack.hbox ~packing:vbox#pack () in
+ ignore (GMisc.label ~text:"wind dir:" ~packing:hbox#pack ());
+ ignore (GRange.scale `HORIZONTAL ~adjustment:wind_dir_adj ~packing:hbox#add ());
+
+ let hbox = GPack.hbox ~packing:vbox#pack () in
+ ignore (GMisc.label ~text:"wind speed:" ~packing:hbox#pack ());
+ ignore (GRange.scale `HORIZONTAL ~adjustment:wind_speed_adj ~packing:hbox#add ());
+
+ let hbox = GPack.hbox ~packing:vbox#pack () in
+ ignore (GMisc.label ~text:"gust max speed:" ~packing:hbox#pack ());
+ ignore (GRange.scale `HORIZONTAL ~adjustment:gust_norm_max_adj ~packing:hbox#add ());
+
+
+ let hbox = GPack.hbox ~packing:vbox#pack () in
+ ignore (GMisc.label ~text:"infrared:" ~packing:hbox#pack ());
+ ignore (GRange.scale `HORIZONTAL ~adjustment:infrared_contrast_adj ~packing:hbox#add ());
+
+ Ivy.init "Paparazzi gaia" "READY" (fun _ _ -> ());
+ Ivy.start !ivy_bus;
+
+ ignore (Ground_Pprz.message_answerer my_id "WORLD_ENV" (fun _ _ -> world_values ()));
+
+ window#show ();
+ Unix.handle_unix_error GMain.Main.main ()
diff --git a/sw/simulator/sim.ml b/sw/simulator/sim.ml
index 7e8b5462bd..9c1ae3e153 100644
--- a/sw/simulator/sim.ml
+++ b/sw/simulator/sim.ml
@@ -24,23 +24,24 @@
*
*)
+open Printf
open Stdlib
-open Geometry_2d
+
+module Ground_Pprz = Pprz.Protocol(struct let name = "ground" end)
let float_attrib xml a = float_of_string (ExtXml.attrib xml a)
-let wind = (0., 0.) (* m/s in local ref *)
-
-(* Frequencies for perdiodic tasks are expressed in periods of 100Hz *)
-let timebase = 10 (* ms *)
-let ir_period = 5
-let fm_period = 4
+(* Frequencies for perdiodic tasks are expressed in s *)
+let ir_period = 1./.20.
+let fm_period = 1./.25.
module type AIRCRAFT =
sig
val init : int -> GPack.box -> unit
- val boot : unit -> unit
+ val boot : Stdlib.value -> unit
+ (** [boot time_acceleration] *)
+
val servos : us array -> unit
(** Called once at init *)
@@ -57,8 +58,9 @@ module type AIRCRAFT_ITL = functor (A : Data.MISSION) -> AIRCRAFT
let ac_name = ref ""
+let ivy_bus = ref "127.255.255.255:2010"
-let common_options = []
+let common_options = [ "-b", Arg.String (fun x -> ivy_bus := x), "Bus\tDefault is 127.255.255.25:2010"]
module Make(AircraftItl : AIRCRAFT_ITL) = struct
@@ -76,29 +78,17 @@ module Make(AircraftItl : AIRCRAFT_ITL) = struct
let lon0 = rad_of_deg (float_attrib flight_plan "lon0")
let qfu = (float_attrib flight_plan "qfu")
let alt0 = (float_attrib flight_plan "ground_alt")
-(*
- let gust_dir = 0 and
- let gust_speed = 0
- let wind = fun ->
- let wind_dir = wind_dir_adj#value in
- let wind_speed = wind_speed_adj#value in
- let gust_max = gust_max_adj#value in
- let gust_dir_fact = gust_dir_fact_adj#value in
- let gust_speed_fact = gust_dir_fact_adj#value in
- gust_speed = trim 0, gust_max (gust_speed + Random.float gust_dir_fact)
- gust_dir = gust_dirspeed + Random.float gu)
-
-*)
let main () =
- let window = GWindow.dialog ~title:("Aircraft "^ !ac_name) () in
+ let window = GWindow.window ~title:("Aircraft "^ !ac_name) () in
let quit = fun () -> GMain.Main.quit (); exit 0 in
ignore (window#connect#destroy ~callback:quit);
+ let vbox = GPack.vbox ~packing:window#add () in
Srtm.add_path (Env.paparazzi_home ^ "/data/srtm");
- Aircraft.init A.ac.Data.id window#vbox;
+ Aircraft.init A.ac.Data.id vbox;
- let gps_period = 25 in
+ let gps_period = 0.25 in
let compute_gps_state = Gps.state lat0 lon0 (alt0) in
@@ -117,79 +107,70 @@ module Make(AircraftItl : AIRCRAFT_ITL) = struct
let north_label = GMisc.label ~text:"000" ()
and east_label = GMisc.label ~text:"000" ()
and alt_label = GMisc.label ~text:"000" () in
- let wind_dir_adj = GData.adjustment ~value:0. ~lower:(0.) ~upper:370. ~step_incr:1.0 () in
- let wind_speed_adj = GData.adjustment ~value:0. ~lower:(0.) ~upper:20. ~step_incr:0.1 () in
- let gust_norm_max_adj = GData.adjustment ~value:0. ~lower:(0.) ~upper:20. ~step_incr:0.1 () in
- let gust_norm_ch_fact_adj = GData.adjustment ~value:0. ~lower:(0.) ~upper:20. ~step_incr:0.1 () in
- let gust_dir_ch_fact_adj = GData.adjustment ~value:0. ~lower:(0.) ~upper:20. ~step_incr:0.1 () in
- let infrared_contrast_adj = GData.adjustment ~value:500. ~lower:(0.) ~upper:1010. ~step_incr:10. () in
-
-
let half_aperture = (Latlong.pi /. 4.) in
let last_gps_state = ref None in
let run = ref false in
let ir_srtm = ref false in
- let scheduler =
- let t = ref 0 in
- let f =
- fun () ->
- incr t;
- if !t mod fm_period = 0 then begin
- FM.do_servos !state servos;
- let wind_dir_rad = deg2rad wind_dir_adj#value in
- let wind_angle_rad = heading_of_to_angle_rad wind_dir_rad in
- let wind_speed_polar = {r2D = wind_speed_adj#value; theta2D = oposite_heading_rad wind_angle_rad} in
- let wind_speed_cart = polar2cart wind_speed_polar in
- FM.state_update !state ( wind_speed_cart.x2D, wind_speed_cart.y2D)
- end;
+ let wind_x = ref 0.
+ and wind_y = ref 0. in
+ let infrared_contrast = ref 500.
+ and time_scale = object val mutable v = 1. method value = v method set_value x = v <- x end in
- if !t mod ir_period = 0 then begin
- let phi = FlightModel.get_phi !state in
- let horizon_distance = 1000. in
- try
- match !last_gps_state with
- None -> ()
- | Some gps_state ->
- let delta_ir =
- if !ir_srtm then
- let altitude = (int_of_float gps_state.Gps.alt) in
- let horizon_right = Srtm.horizon_slope gps_state.Gps.wgs84 altitude (gps_state.Gps.course +. Latlong.pi /. 2.) half_aperture horizon_distance in
- let horizon_left = Srtm.horizon_slope gps_state.Gps.wgs84 altitude (gps_state.Gps.course -. Latlong.pi /. 2.) half_aperture horizon_distance in
- (***) Printf.printf "IR: %f-%f\n%!" horizon_right horizon_left;
- (***) Printf.printf "alt: %d\n%!" altitude;
- horizon_right -. horizon_left
- else
- 0. in
- let ir_left = ( (phi +. delta_ir ) *. infrared_contrast_adj#value )
- and ir_front = 0. in
- Aircraft.infrared ir_left ir_front
- with
- x -> Printf.printf "%s\n%!" (Printexc.to_string x)
-
- end;
-
- if !t mod gps_period = 0 then begin
- let (x,y,z) = FlightModel.get_xyz !state in
- east_label#set_text (Printf.sprintf "%.0f" x);
- north_label#set_text (Printf.sprintf "%.0f" y);
- alt_label#set_text (Printf.sprintf "%.0f" z);
- let s = compute_gps_state (x,y,z) (FlightModel.get_time !state) in
- last_gps_state := Some s;
- Aircraft.gps s
- end;
- true in
- fun () -> ignore (GMain.Timeout.add 10 f) in
+ let world_update = fun _ vs ->
+ wind_x := Pprz.float_assoc "wind_east" vs;
+ wind_y := Pprz.float_assoc "wind_north" vs;
+ infrared_contrast := Pprz.float_assoc "ir_contrast" vs;
+ time_scale#set_value (Pprz.float_assoc "time_scale" vs)
+ in
+ ignore (Ground_Pprz.message_bind "WORLD_ENV" world_update);
+
+
+ let fm_task = fun () ->
+ FM.do_servos !state servos;
+ FM.state_update !state (!wind_x, !wind_y) fm_period
+
+ and ir_task = fun () ->
+ let phi = FlightModel.get_phi !state in
+ let horizon_distance = 1000. in
+ try
+ match !last_gps_state with
+ None -> ()
+ | Some gps_state ->
+ let delta_ir =
+ if !ir_srtm then
+ let altitude = (int_of_float gps_state.Gps.alt) in
+ let horizon_right = Srtm.horizon_slope gps_state.Gps.wgs84 altitude (gps_state.Gps.course +. Latlong.pi /. 2.) half_aperture horizon_distance in
+ let horizon_left = Srtm.horizon_slope gps_state.Gps.wgs84 altitude (gps_state.Gps.course -. Latlong.pi /. 2.) half_aperture horizon_distance in
+ horizon_right -. horizon_left
+ else
+ 0. in
+ let ir_left = ( (phi +. delta_ir ) *. !infrared_contrast)
+ and ir_front = 0. in
+ Aircraft.infrared ir_left ir_front
+ with
+ x -> Printf.printf "%s\n%!" (Printexc.to_string x)
+
+ and gps_task = fun () ->
+ let (x,y,z) = FlightModel.get_xyz !state in
+ east_label#set_text (Printf.sprintf "%.0f" x);
+ north_label#set_text (Printf.sprintf "%.0f" y);
+ alt_label#set_text (Printf.sprintf "%.0f" z);
+ let s = compute_gps_state (x,y,z) (FlightModel.get_time !state) in
+ last_gps_state := Some s;
+ Aircraft.gps s in
let boot = fun () ->
- Aircraft.boot ();
- scheduler () in
+ Aircraft.boot (time_scale:>value);
+ Stdlib.timer ~scale:time_scale fm_period fm_task;
+ Stdlib.timer ~scale:time_scale ir_period ir_task;
+ Stdlib.timer ~scale:time_scale gps_period gps_task in
let take_off = fun () -> prerr_endline "takeoff"; FlightModel.set_air_speed !state FM.nominal_airspeed in
- let hbox = GPack.hbox ~packing:window#vbox#pack () in
+ let hbox = GPack.hbox ~packing:vbox#pack () in
let s = GButton.button ~label:"Boot" ~packing:(hbox#pack ~padding:5) () in
ignore (s#connect#clicked ~callback:boot);
let t = GButton.button ~label:"Launch" ~packing:hbox#pack () in
@@ -197,29 +178,14 @@ module Make(AircraftItl : AIRCRAFT_ITL) = struct
let ir_srtm_button = GButton.toggle_button ~label:"IR/srtm" ~packing:hbox#pack () in
ignore (ir_srtm_button#connect#toggled (fun () -> ir_srtm := not !ir_srtm));
- let hbox = GPack.hbox ~packing:window#vbox#pack () in
+ let hbox = GPack.hbox ~packing:vbox#pack () in
let l = fun s -> ignore(GMisc.label ~text:s ~packing:hbox#pack ()) in
l "East:"; hbox#pack east_label#coerce;
l " North:"; hbox#pack north_label#coerce;
l " Height:"; hbox#pack alt_label#coerce;
- let hbox = GPack.hbox ~packing:window#vbox#pack () in
- ignore (GMisc.label ~text:"wind dir:" ~packing:hbox#pack ());
- ignore (GRange.scale `HORIZONTAL ~adjustment:wind_dir_adj ~packing:hbox#add ());
-
- let hbox = GPack.hbox ~packing:window#vbox#pack () in
- ignore (GMisc.label ~text:"wind speed:" ~packing:hbox#pack ());
- ignore (GRange.scale `HORIZONTAL ~adjustment:wind_speed_adj ~packing:hbox#add ());
-
- let hbox = GPack.hbox ~packing:window#vbox#pack () in
- ignore (GMisc.label ~text:"gust max speed:" ~packing:hbox#pack ());
- ignore (GRange.scale `HORIZONTAL ~adjustment:gust_norm_max_adj ~packing:hbox#add ());
-
-
- let hbox = GPack.hbox ~packing:window#vbox#pack () in
- ignore (GMisc.label ~text:"infrared:" ~packing:hbox#pack ());
- ignore (GRange.scale `HORIZONTAL ~adjustment:infrared_contrast_adj ~packing:hbox#add ());
-
+ Ivy.init (sprintf "Paparazzi sim %d" A.ac.Data.id) "READY" (fun _ _ -> ());
+ Ivy.start !ivy_bus;
window#show ();
Unix.handle_unix_error GMain.Main.main ()
diff --git a/sw/simulator/sim.mli b/sw/simulator/sim.mli
index 8d323cdec5..824a4c4e96 100644
--- a/sw/simulator/sim.mli
+++ b/sw/simulator/sim.mli
@@ -7,7 +7,7 @@ val ac_name : string ref
module type AIRCRAFT =
sig
val init : int -> GPack.box -> unit
- val boot : unit -> unit
+ val boot : Stdlib.value -> unit
val servos : Stdlib.us array -> unit
val infrared : float -> float -> unit
val gps : Gps.state -> unit
diff --git a/sw/simulator/sitl.ml b/sw/simulator/sitl.ml
index d6a874b3d5..d4ef6d3a6d 100644
--- a/sw/simulator/sitl.ml
+++ b/sw/simulator/sitl.ml
@@ -29,14 +29,12 @@ open Printf
let ios = int_of_string
let fos = float_of_string
-let ivy_bus = ref "127.255.255.255:2010"
-
module Make(A:Data.MISSION) = struct
- let servos_period = 25 (* ms *)
- let periodic_period = 16 (* ms *)
- let rc_period = 25 (* ms *)
-
+ let servos_period = 1./.40. (* s *)
+ let periodic_period = 1./.61. (* s *)
+ let rc_period = 1./.40. (* s *)
+
let periodic = fun p f ->
f ();
ignore (GMain.Timeout.add p (fun () -> f (); true))
@@ -67,7 +65,7 @@ module Make(A:Data.MISSION) = struct
let gaz = set_servos !rservos in
(* 100% = 1W *)
if bat_button#active then
- let energy = float (gaz-1000) /. 1000. *. float servos_period /. 1000. in
+ let energy = float (gaz-1000) /. 1000. *. servos_period in
accu := !accu +. energy *. 0.00259259259259259252; (* To be improved !!! *)
printf "\b\b\b\b\b%.3f%!" !accu;
if !accu >= 0.1 then begin
@@ -123,8 +121,6 @@ module Make(A:Data.MISSION) = struct
let bat_button = GButton.toggle_button ~label:"Bat" ()
let init = fun id vbox ->
- Ivy.init (sprintf "Paparazzi sim %d" id) "READY" (fun _ _ -> ());
- Ivy.start !ivy_bus;
rc ();
sim_init id;
@@ -138,10 +134,10 @@ module Make(A:Data.MISSION) = struct
update ()
- let boot = fun () ->
- periodic servos_period (update_servos bat_button);
- periodic periodic_period periodic_task;
- periodic rc_period rc_task
+ let boot = fun time_scale ->
+ Stdlib.timer ~scale:time_scale servos_period (update_servos bat_button);
+ Stdlib.timer ~scale:time_scale periodic_period periodic_task;
+ Stdlib.timer ~scale:time_scale rc_period rc_task
(* Functions called by the simulator *)
let servos = fun s -> rservos := s
@@ -158,6 +154,4 @@ module Make(A:Data.MISSION) = struct
use_gps_pos (cm utm.utm_x) (cm utm.utm_y) utm.utm_zone gps.Gps.course gps.Gps.alt gps.Gps.gspeed gps.Gps.climb gps.Gps.time
end
-let options =
- [ "-b", Arg.String (fun x -> ivy_bus := x), "Bus\tDefault is 127.255.255.25:2010"]
-
+let options = []
diff --git a/sw/simulator/stdlib.ml b/sw/simulator/stdlib.ml
index dd4ee954ee..93975987a4 100644
--- a/sw/simulator/stdlib.ml
+++ b/sw/simulator/stdlib.ml
@@ -40,3 +40,26 @@ let set_float = fun option var name ->
(option, Arg.Set_float var, Printf.sprintf "%s (%f)" name !var)
let set_string = fun option var name ->
(option, Arg.Set_string var, Printf.sprintf "%s (%s)" name !var)
+
+let ms x = max 0 (truncate (1000.*.x))
+(* Non derivating timer *)
+class type value = object method value : float end
+
+let timer ?scale p f =
+ let scale =
+ match scale with
+ None -> object method value = 1. end
+ | Some s -> (s :> value) in
+ let rec loop = fun expected ->
+ let next = expected +. p /. scale#value in
+ let dt = ms (next -. Unix.gettimeofday()) in
+ if dt < 1 then begin (* No timer needed, simply loop *)
+ f (); loop next
+ end else
+ GMain.Timeout.add
+ dt
+ (fun () ->
+ loop next;
+ f ();
+ false) in
+ ignore (loop (Unix.gettimeofday()))
diff --git a/sw/simulator/stdlib.mli b/sw/simulator/stdlib.mli
index 361bc31104..7a5bd997d4 100644
--- a/sw/simulator/stdlib.mli
+++ b/sw/simulator/stdlib.mli
@@ -31,3 +31,8 @@ val deg_of_rad : float -> float
val rad_of_deg : float -> float
val set_float : string -> float ref -> string -> string * Arg.spec * string
val set_string : string -> string ref -> string -> string * Arg.spec * string
+
+class type value = object method value : float end
+
+val timer : ?scale:#value -> float -> (unit -> 'a) -> unit
+(** [timer ?time_accel period_s callback] Non derivating periodic timer *)