diff --git a/Makefile b/Makefile index 1d60430fd7..583a4f434f 100644 --- a/Makefile +++ b/Makefile @@ -118,7 +118,7 @@ ac_h ac1 ac2 ac3 ac fbw ap: static conf bl: cd $(AIRBORNE)/arm7/test/bootloader; make clean; make -upload_bl: bl +upload_bl bl.upload: bl lpc21isp -control $(AIRBORNE)/arm7/test/bootloader/bl.hex /dev/ttyUSB0 38400 12000 lpc21iap: diff --git a/conf/airframes/microjet7.xml b/conf/airframes/microjet7.xml index 2d83458f48..8ab1c1699e 100644 --- a/conf/airframes/microjet7.xml +++ b/conf/airframes/microjet7.xml @@ -55,7 +55,7 @@
- + @@ -73,7 +73,7 @@ - +
@@ -126,12 +126,12 @@ - +
- + diff --git a/conf/airframes/slayer1.xml b/conf/airframes/slayer1.xml index 79d68d57fb..5f88149e35 100644 --- a/conf/airframes/slayer1.xml +++ b/conf/airframes/slayer1.xml @@ -71,9 +71,11 @@ - + - + + +
@@ -96,6 +98,7 @@ +
@@ -211,7 +214,7 @@ ap.CFLAGS += -DGPS -DUBX -DUSE_UART1 -DGPS_LINK=Uart1 -DUART1_BAUD=B19200 ap.srcs += gps_ubx.c gps.c -ap.CFLAGS += -DINFRARED -DALT_KALMAN +ap.CFLAGS += -DINFRARED -DALT_KALMAN -DIR_360 ap.srcs += infrared.c estimator.c ap.CFLAGS += -DNAV -DH_CTL_RATE_LOOP -DAGR_CLIMB -DLOITER_TRIM @@ -231,7 +234,7 @@ ap.CFLAGS += -DLIGHT_PIN_1=3 # Config for SITL simulation include $(PAPARAZZI_SRC)/conf/autopilot/sitl.makefile -sim.CFLAGS += -DCONFIG=\"tiny.h\" -DAGR_CLIMB -DH_CTL_RATE_LOOP -DLOITER_TRIM -DALT_KALMAN +sim.CFLAGS += -DCONFIG=\"tiny.h\" -DAGR_CLIMB -DH_CTL_RATE_LOOP -DLOITER_TRIM -DALT_KALMAN -DIR_360 sim.srcs += bomb.c diff --git a/conf/airframes/slayer2.xml b/conf/airframes/slayer2.xml index 054030e3f9..a7fc1dd7ba 100644 --- a/conf/airframes/slayer2.xml +++ b/conf/airframes/slayer2.xml @@ -70,7 +70,9 @@ - + + +
@@ -93,6 +95,7 @@ +
@@ -209,7 +212,7 @@ ap.CFLAGS += -DGPS -DUBX -DUSE_UART1 -DGPS_LINK=Uart1 -DUART1_BAUD=B19200 ap.srcs += gps_ubx.c gps.c -ap.CFLAGS += -DINFRARED -DALT_KALMAN +ap.CFLAGS += -DINFRARED -DALT_KALMAN -DIR_360 ap.srcs += infrared.c estimator.c ap.CFLAGS += -DNAV -DH_CTL_RATE_LOOP -DAGR_CLIMB -DLOITER_TRIM @@ -228,7 +231,7 @@ ap.srcs += bomb.c # Config for SITL simulation include $(PAPARAZZI_SRC)/conf/autopilot/sitl.makefile -sim.CFLAGS += -DCONFIG=\"tiny.h\" -DAGR_CLIMB -DH_CTL_RATE_LOOP -DLOITER_TRIM -DALT_KALMAN +sim.CFLAGS += -DCONFIG=\"tiny.h\" -DAGR_CLIMB -DH_CTL_RATE_LOOP -DLOITER_TRIM -DALT_KALMAN -DIR_360 sim.srcs += bomb.c diff --git a/conf/airframes/slayer3.xml b/conf/airframes/slayer3.xml index 76c3273f04..b7e4307d5c 100755 --- a/conf/airframes/slayer3.xml +++ b/conf/airframes/slayer3.xml @@ -71,7 +71,9 @@ - + + +
@@ -96,6 +98,7 @@ +
@@ -212,7 +215,7 @@ ap.CFLAGS += -DGPS -DUBX -DUSE_UART1 -DGPS_LINK=Uart1 -DUART1_BAUD=B19200 ap.srcs += gps_ubx.c gps.c -ap.CFLAGS += -DINFRARED -DALT_KALMAN +ap.CFLAGS += -DINFRARED -DALT_KALMAN -DIR_360 ap.srcs += infrared.c estimator.c ap.CFLAGS += -DNAV -DH_CTL_RATE_LOOP -DAGR_CLIMB -DLOITER_TRIM @@ -229,7 +232,7 @@ ap.srcs += gyro.c bomb.c # Config for SITL simulation include $(PAPARAZZI_SRC)/conf/autopilot/sitl.makefile -sim.CFLAGS += -DCONFIG=\"tiny.h\" -DAGR_CLIMB -DH_CTL_RATE_LOOP -DLOITER_TRIM -DALT_KALMAN +sim.CFLAGS += -DCONFIG=\"tiny.h\" -DAGR_CLIMB -DH_CTL_RATE_LOOP -DLOITER_TRIM -DALT_KALMAN -DIR_360 sim.srcs += bomb.c diff --git a/conf/gcs/horizontal.xml b/conf/gcs/horizontal.xml index 6dda1a58d1..67866c9256 100644 --- a/conf/gcs/horizontal.xml +++ b/conf/gcs/horizontal.xml @@ -4,7 +4,7 @@ - + diff --git a/conf/settings/tuning.xml b/conf/settings/tuning.xml index 85c827d139..e4944abe71 100644 --- a/conf/settings/tuning.xml +++ b/conf/settings/tuning.xml @@ -29,7 +29,7 @@ - + diff --git a/sw/airborne/estimator.c b/sw/airborne/estimator.c index cb3653fb71..ab43461985 100644 --- a/sw/airborne/estimator.c +++ b/sw/airborne/estimator.c @@ -125,6 +125,10 @@ bool_t alt_kalman_enabled; #ifdef ALT_KALMAN +#ifndef ALT_KALMAN_ENABLED +#define ALT_KALMAN_ENABLED FALSE +#endif + #define DT 0.25 #define SIGMA2 1. #define R 2. @@ -139,7 +143,7 @@ void alt_kalman_reset( void ) { } void alt_kalman_init( void ) { - alt_kalman_enabled = FALSE; + alt_kalman_enabled = ALT_KALMAN_ENABLED; alt_kalman_reset(); } diff --git a/sw/airborne/infrared.c b/sw/airborne/infrared.c index fbf080fc26..ddfb2dcab2 100644 --- a/sw/airborne/infrared.c +++ b/sw/airborne/infrared.c @@ -45,11 +45,11 @@ float z_contrast_mode; float ir_roll_neutral; float ir_pitch_neutral; -bool_t ir_allow_inverted; +bool_t ir_360; float ir_estimated_phi_pi_4; -#ifndef IR_ALLOW_INVERTED -#define IR_ALLOW_INVERTED FALSE +#ifndef IR_360 +#define IR_360 FALSE #endif @@ -131,7 +131,7 @@ void ir_init(void) { ir_correction_down = IR_CORRECTION_DOWN; #endif - ir_allow_inverted = IR_ALLOW_INVERTED; + ir_360 = IR_360; ir_estimated_phi_pi_4 = IR_ESTIMATED_PHI_PI_4; ir_contrast = IR_DEFAULT_CONTRAST; @@ -271,7 +271,7 @@ void estimator_update_state_infrared( void ) { estimator_rad_of_ir : ir_rad_of_ir); - if (!ir_allow_inverted) { + if (!ir_360) { ir_top = Max(ir_top, 1); float c = rad_of_ir*(1-z_contrast_mode)+z_contrast_mode*((float)IR_RAD_OF_IR_CONTRAST/fabs(ir_top)); @@ -299,8 +299,12 @@ void estimator_update_state_infrared( void ) { Bound(estimator_phi, -M_PI_2, M_PI_2); Bound(estimator_theta, -M_PI_2, M_PI_2); - } else { /* allow_inverted */ + } else { /* 360° estimation */ /* 250 us for the whole block */ + ir_roll *= IR_360_LATERAL_CORRECTION; + ir_pitch *= IR_360_LONGITUDINAL_CORRECTION; + ir_top *= IR_360_VERTICAL_CORRECTION; + estimator_phi = atan2(ir_roll, ir_top) - ir_roll_neutral; estimator_phi = correct_angle(estimator_phi, ir_estimated_phi_pi_4); diff --git a/sw/airborne/infrared.h b/sw/airborne/infrared.h index caee86284c..306c2f63a7 100644 --- a/sw/airborne/infrared.h +++ b/sw/airborne/infrared.h @@ -48,7 +48,7 @@ extern int16_t ir_top; /* averaged vertical ir adc */ extern float ir_rad_of_ir; extern int16_t ir_contrast; extern float z_contrast_mode; -extern bool_t ir_allow_inverted; +extern bool_t ir_360; extern float ir_estimated_phi_pi_4; #if defined IR_CORRECTION_LEFT && defined IR_CORRECTION_RIGHT diff --git a/sw/ground_segment/cockpit/gcs.ml b/sw/ground_segment/cockpit/gcs.ml index a3144ff875..42c299cb4c 100644 --- a/sw/ground_segment/cockpit/gcs.ml +++ b/sw/ground_segment/cockpit/gcs.ml @@ -611,7 +611,7 @@ let _main = geomap#center (Latlong.of_string !center) end; - Speech.say "Welcome to papa radsi"; + Speech.say "Welcome to papa ratsi"; (** Threaded main loop (map tiles loaded concurently) *) GtkThread.main () diff --git a/sw/ground_segment/cockpit/live.ml b/sw/ground_segment/cockpit/live.ml index b5b5abf876..2704ccae18 100644 --- a/sw/ground_segment/cockpit/live.ml +++ b/sw/ground_segment/cockpit/live.ml @@ -73,7 +73,9 @@ type aircraft = { mutable first_pos : bool; mutable last_block_name : string; mutable in_kill_mode : bool; - mutable speed : float + mutable speed : float; + mutable alt : float; + mutable flight_time : int } let live_aircrafts = Hashtbl.create 3 @@ -394,14 +396,14 @@ let create_ac = fun (geomap:G.widget) (acs_notebook:GPack.notebook) (ac_id:strin fp = fp_xml; ac_name = name; blocks = blocks; last_ap_mode= ""; last_stage = (-1,-1); - ir_page = ir_page; + ir_page = ir_page; flight_time = 0; gps_page = gps_page; pfd_page = pfd_page; misc_page = misc_page; dl_settings_page = dl_settings_page; rc_settings_page = rc_settings_page; strip = strip; first_pos = true; - last_block_name = ""; + last_block_name = ""; alt = 0.; in_kill_mode = false; speed = 0. } @@ -548,7 +550,13 @@ let listen_flight_params = fun geomap auto_center_new_ac alert -> in set_label "alt" alt; set_label "speed" speed; - set_label "climb" climb + set_label "climb" climb; + let agl = (a "agl") in + ac.alt <- alt; + Strip.set_agl ac.strip agl; + if (ac.flight_time > 10 && agl < 20.) then + log_and_say alert (sprintf "%s, %s" ac.ac_name "Ground Proximity Warning") + in safe_bind "FLIGHT_PARAM" get_fp; @@ -564,6 +572,9 @@ let listen_flight_params = fun geomap auto_center_new_ac alert -> Strip.set_label ac.strip l (sprintf "%.1f" (Pprz.float_assoc f vs)) in set_label "->" "target_alt"; set_label "/" "target_climb"; + let target_alt = Pprz.float_assoc "target_alt" vs in + Strip.set_label ac.strip "diff_target_alt" (sprintf "%+.0f" (ac.alt -. target_alt)); + let b = List.assoc cur_block ac.blocks in if b <> ac.last_block_name then begin log_and_say alert (sprintf "%s, %s" ac.ac_name b); @@ -627,6 +638,7 @@ let listen_flight_params = fun geomap auto_center_new_ac alert -> let ac = get_ac vs in let flight_time = Int32.to_int (Pprz.int32_assoc "flight_time" vs) in ac.track#update_ap_status (float_of_int flight_time); + ac.flight_time <- flight_time; let ap_mode = Pprz.string_assoc "ap_mode" vs in if ap_mode <> ac.last_ap_mode then begin log_and_say alert (sprintf "%s, %s" ac.ac_name ap_mode); diff --git a/sw/ground_segment/cockpit/strip.ml b/sw/ground_segment/cockpit/strip.ml index 006e23f64a..6e514ba27d 100644 --- a/sw/ground_segment/cockpit/strip.ml +++ b/sw/ground_segment/cockpit/strip.ml @@ -2,13 +2,15 @@ let bat_max = 12.5 let bat_min = 9. +let agl_max = 150. (** window for the strip panel *) -let scrolled = GBin.scrolled_window ~width:300 ~hpolicy: `AUTOMATIC ~vpolicy: `AUTOMATIC () +let scrolled = GBin.scrolled_window ~hpolicy: `AUTOMATIC ~vpolicy: `AUTOMATIC () let table = GPack.table ~rows: 1 ~columns: 1 ~row_spacings: 5 ~packing: (scrolled#add_with_viewport) () type t = { + agl: GMisc.drawing_area; gauge: GMisc.drawing_area; labels: (string * (GBin.event_box * GMisc.label)) list; buttons_box : GPack.box @@ -24,7 +26,7 @@ let labels_print = [| let gen_int = let i = ref (-1) in fun () -> incr i; !i let rows = 1 + Array.length labels_name + 1 -let columns = 1 + 2 * Array.length labels_name.(0) +let columns = 1 + 2 * Array.length labels_name.(0) + 1 (** add a strip to the panel *) @@ -79,6 +81,18 @@ let add config color select center_ac commit_moves mark = let gauge = GMisc.drawing_area ~height:60 ~show:true ~packing:(strip#attach ~top:1 ~bottom:(rows-1) ~left:0) () in gauge#misc#realize (); + (* AGL gauge *) + let agl_box = GBin.event_box ~packing:(strip#attach ~top:1 ~bottom:(rows-1) ~left:(columns-1)) () in + let agl = GMisc.drawing_area ~width:30 ~height:60 ~show:true ~packing:agl_box#add () in + agl#misc#realize (); + tooltips#set_tip agl_box#coerce ~text:"AGL (m)"; + + (* Diff to target altitude *) + let dta_box = GBin.event_box ~packing:(strip#attach ~top:(rows-1) ~left:(columns-1)) () in + let diff_target_alt = GMisc.label ~text: "+0" ~packing:dta_box#add () in + add_label "diff_target_alt_value" (plane_color, diff_target_alt); + tooltips#set_tip dta_box#coerce ~text:"Height to target (m)"; + (* Telemetry *) let eb = GBin.event_box ~packing:(strip#attach ~top:(rows-1) ~left:0) () in let ts = GMisc.label ~text:"N/A" ~packing:eb#add () in @@ -102,18 +116,17 @@ let add config color select center_ac commit_moves mark = let top = rows - 1 in let b = GButton.button ~label:"Center A/C" ~packing:(strip#attach ~top ~left:1 ~right:3) () in ignore(b#connect#clicked ~callback:center_ac); - let b = GButton.button ~label:"Send WPs" ~packing:(strip#attach ~top ~left:3 ~right:5) () in - ignore (b#connect#clicked ~callback:commit_moves); let b = GButton.button ~label:"Mark" ~packing:(strip#attach ~top ~left:5 ~right:7) () in ignore (b#connect#clicked ~callback:mark); (* User buttons *) let hbox = GPack.hbox ~packing:framevb#add () in - {gauge=gauge ; labels= !strip_labels; buttons_box = hbox} + { agl=agl; gauge=gauge ; labels= !strip_labels; buttons_box = hbox} - (** set a label *) + +(** set a label *) let set_label strip name value = try let _eb, l = List.assoc (name^"_value") strip.labels in @@ -123,20 +136,19 @@ let set_label strip name value = Not_found -> Printf.fprintf stderr "Strip.set_label: '%s' unknown\n%!" name - (** set a label *) +(** set a color *) let set_color strip name color = let eb, _l = List.assoc (name^"_value") strip.labels in eb#coerce#misc#modify_bg [`NORMAL, `NAME color] - (** set the battery *) -let set_bat ?(color="green") strip value = - let gauge = strip.gauge in + +let set_gauge = fun ?(color="green") gauge v_min v_max value string -> let {Gtk.width=width; height=height} = gauge#misc#allocation in let dr = GDraw.pixmap ~width ~height ~window:gauge () in dr#set_foreground (`NAME "orange"); dr#rectangle ~x:0 ~y:0 ~width ~height ~filled:true (); - let f = (value -. bat_min) /. (bat_max -. bat_min) in + let f = (value -. v_min) /. (v_max -. v_min) in let f = max 0. (min 1. f) in let h = truncate (float height *. f) in dr#set_foreground (`NAME color); @@ -144,12 +156,23 @@ let set_bat ?(color="green") strip value = let context = gauge#misc#create_pango_context in let layout = context#create_layout in - Pango.Layout.set_text layout (string_of_float value); + Pango.Layout.set_text layout string; let (w,h) = Pango.Layout.get_pixel_size layout in dr#put_layout ~x:((width-w)/2) ~y:((height-h)/2) ~fore:`BLACK layout; (new GDraw.drawable gauge#misc#window)#put_pixmap ~x:0 ~y:0 dr#pixmap + +(** set the battery *) +let set_bat ?color strip value = + set_gauge ?color strip.gauge bat_min bat_max value (string_of_float value) + + +(** set the AGL *) +let set_agl ?color strip value = + set_gauge ?color strip.agl 0. agl_max value (Printf.sprintf "%3.0f" value) + + let add_widget = fun strip widget -> strip.buttons_box#add widget diff --git a/sw/ground_segment/cockpit/strip.mli b/sw/ground_segment/cockpit/strip.mli index 6383932af9..f5ace9dccb 100644 --- a/sw/ground_segment/cockpit/strip.mli +++ b/sw/ground_segment/cockpit/strip.mli @@ -6,5 +6,6 @@ val add : val set_label : t -> string -> string -> unit val set_color : t -> string -> string -> unit val set_bat : ?color:string -> t -> float -> unit +val set_agl : ?color:string -> t -> float -> unit val scrolled : GBin.scrolled_window val add_widget : t -> GObj.widget -> unit diff --git a/sw/ground_segment/tmtc/link.ml b/sw/ground_segment/tmtc/link.ml index e7b66f2e77..5571b1ed32 100644 --- a/sw/ground_segment/tmtc/link.ml +++ b/sw/ground_segment/tmtc/link.ml @@ -292,7 +292,6 @@ module XB = struct (** XBee module *) fprintf o "%s%!" (Xbee.at_set_baud_rate device.baud_rate); fprintf o "%s%!" Xbee.at_api_enable; fprintf o "%s%!" Xbee.at_exit; - fprintf o "ATRR14\r%!"; Debug.trace 'x' "end init xbee" let init = fun device -> diff --git a/sw/lib/ocaml/mapCanvas.ml b/sw/lib/ocaml/mapCanvas.ml index a09e1e58ff..d0d40b7bdb 100644 --- a/sw/lib/ocaml/mapCanvas.ml +++ b/sw/lib/ocaml/mapCanvas.ml @@ -25,6 +25,7 @@ *) module LL = Latlong +open LL module G2D = Geometry_2d open Printf @@ -176,9 +177,7 @@ class basic_widget = fun ?(height=800) ?width ?(projection = Mercator) ?georef ( ~value:1. ~lower:0.05 ~upper:10. ~step_incr:0.25 ~page_incr:1.0 ~page_size:1.0 () - val info = info - - + method info = info (** other attributes *) @@ -431,7 +430,7 @@ class basic_widget = fun ?(height=800) ?width ?(projection = Mercator) ?georef ( let xc = GdkEvent.Motion.x ev and yc = GdkEvent.Motion.y ev in let (xw, yw) = self#window_to_world xc yc in - self#display_geo (self#geo_string (self#of_world (xw,yw))); + self#display_geo (self#of_world (xw,yw)); self#display_alt (self#of_world (xw,yw)); let (x, y) = canvas#get_scroll_offsets in last_mouse_x <- truncate xc - x; @@ -574,20 +573,22 @@ class basic_widget = fun ?(height=800) ?width ?(projection = Mercator) ?georef ( class widget = fun ?(height=800) ?width ?projection ?georef () -> let srtm = GMenu.check_menu_item ~label:"SRTM" ~active:false () in + let lbl_xy = GMisc.label () + and lbl_geo = GMisc.label () + and lbl_alt = GMisc.label () + and lbl_group = GMisc.label () in + object(self) inherit (basic_widget ~height ?width ?projection ?georef ()) - val mutable lbl_xy = GMisc.label () - val mutable lbl_geo = GMisc.label () - val mutable lbl_alt = GMisc.label () - val mutable lbl_group = GMisc.label () val mutable utm_grid_group = None + val mutable info_georef = None method pack_labels = - info#pack lbl_xy#coerce; - info#pack lbl_geo#coerce; - info#pack lbl_alt#coerce; - info#pack lbl_group#coerce; + self#info#pack lbl_xy#coerce; + self#info#pack lbl_geo#coerce; + self#info#pack lbl_alt#coerce; + self#info#pack lbl_group#coerce; initializer ( self#pack_labels; @@ -641,10 +642,20 @@ class widget = fun ?(height=800) ?width ?projection ?georef () -> GToolbox.message_box "SRTM" (sprintf "SRTM tile %s not found: %s ?" x (Srtm.error x)); 0 + method set_info_georef = fun ?(name="") geo -> + info_georef <- Some (name, geo) + (** display methods *) - method display_xy = fun s -> lbl_xy#set_text s - method display_geo = fun s -> lbl_geo#set_text s + method display_geo = fun geo -> + match info_georef with + None -> lbl_geo#set_text (self#geo_string geo) + | Some (name, (georef:< pos : LL.geographic>)) -> + let (dx, dy) = Latlong.utm_sub (LL.utm_of LL.WGS84 geo) (LL.utm_of LL.WGS84 georef#pos) in + let d = sqrt (dx*.dx+.dy*.dy) in + lbl_geo#set_text (sprintf "%.0f %.0fm/%s" ((Rad>>Deg)(atan2 dx dy)) d name) + + method display_alt = fun wgs84 -> if srtm#active then lbl_alt#set_text (sprintf "\t%dm"(self#altitude wgs84)) diff --git a/sw/lib/ocaml/mapFP.ml b/sw/lib/ocaml/mapFP.ml index 8c22142f15..a5e3ba6df0 100644 --- a/sw/lib/ocaml/mapFP.ml +++ b/sw/lib/ocaml/mapFP.ml @@ -161,7 +161,8 @@ class flight_plan = fun ?editable ~show_moved geomap color fp_dtd xml -> update (); w#connect update; XmlEdit.connect wp update; - XmlEdit.connect xml_root update + XmlEdit.connect xml_root update; + geomap#set_info_georef ~name:"HOME" (w :> < pos : geographic>) end) (XmlEdit.children xml_wpts) in diff --git a/sw/lib/ocaml/mapTrack.ml b/sw/lib/ocaml/mapTrack.ml index 54303710c6..3339c0860b 100644 --- a/sw/lib/ocaml/mapTrack.ml +++ b/sw/lib/ocaml/mapTrack.ml @@ -65,7 +65,8 @@ class track = fun ?(name="Noname") ?(size = 500) ?(color="red") (geomap:MapCanva ignore (GnoCanvas.line ~fill_color:color ~props:[`WIDTH_PIXELS 4;`CAP_STYLE `ROUND] ~points:[|-4.;10.;4.;10.|] aircraft) in let ac_label = GnoCanvas.text group ~props:[`TEXT name; `X 25.; `Y 25.; `ANCHOR `SW; `FILL_COLOR color] in - let carrot = GnoCanvas.group group in + let vertical_indicator = GnoCanvas.line ~fill_color:color ~props:[`WIDTH_PIXELS 2] ~points:[|0.;0.;0.;100.|] group in + let carrot = GnoCanvas.group group in let _ac_carrot = ignore (GnoCanvas.polygon ~points:[|0.;0.;-5.;-10.;5.;-10.|] ~props:[`WIDTH_UNITS 1.;`FILL_COLOR "orange"; `OUTLINE_COLOR "orange"; `FILL_STIPPLE (Gdk.Bitmap.create_from_data ~width:2 ~height:2 "\002\001")] carrot) in @@ -185,6 +186,8 @@ class track = fun ?(name="Noname") ?(size = 500) ?(color="red") (geomap:MapCanva end; ac_label#affine_absolute (affine_pos_and_angle geomap#zoom_adj#value xw yw 0.); + vertical_indicator#affine_absolute (affine_pos_and_angle geomap#zoom_adj#value xw yw 0.); + vertical_indicator#set [`POINTS [|0.; 0.;0.; (self#height ())|]]; self#add_point wgs84; method move_carrot = fun wgs84 ->