diff --git a/sw/airborne/cam_roll.c b/sw/airborne/cam_roll.c new file mode 100644 index 0000000000..ff57341140 --- /dev/null +++ b/sw/airborne/cam_roll.c @@ -0,0 +1,79 @@ +/* + * $Id$ + * + * Copyright (C) 2003 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. + * + */ +/** \file cam.c + * \brief Pan/Tilt camera library + * + */ + +#include +#include "cam.h" +#include "nav.h" +#include "autopilot.h" +#include "flight_plan.h" +#include "estimator.h" +#include "inter_mcu.h" +#include "nav.h" + +#define MIN_PPRZ_CAM ((int16_t)(MAX_PPRZ * 0.05)) +#define DELTA_ALPHA 0.2 + +#define MAX_CAM_ROLL M_PI/2 + +float cam_roll_phi; /* radian */ +float phi_c; /* radian */ +float theta_c; /* have to be defined for telemetry message */ + +float target_x, target_y, target_alt; + +#ifdef MOBILE_CAM + +#define MODE_MANUAL 0 +#define MODE_STABILIZED 1 + +uint8_t cam_roll_mode; +bool_t cam_roll_switch; + +void cam_init( void ) { + cam_roll_switch = 0; +#ifdef VIDEO_SWITCH_PIN + IO0DIR |= _BV(VIDEO_SWITCH_PIN); + IO0CLR = _BV(VIDEO_SWITCH_PIN); +#endif +} + +void cam_periodic( void ) { + switch (cam_roll_mode) { + case MODE_STABILIZED: + phi_c = cam_roll_phi + estimator_phi; + break; + case MODE_MANUAL: + phi_c = cam_roll_phi; + break; + default: + phi_c = 0; + } + ap_state->commands[COMMAND_CAM_ROLL] = TRIM_PPRZ(phi_c * MAX_PPRZ / RadOfDeg(CAM_PHI_MAX_DEG)); +} + +#endif // MOBILE_CAM diff --git a/sw/airborne/cam_roll.h b/sw/airborne/cam_roll.h new file mode 100644 index 0000000000..fa3ec7f3d4 --- /dev/null +++ b/sw/airborne/cam_roll.h @@ -0,0 +1,13 @@ +#ifndef CAM_ROLL_H +#define CAM_ROLL_H + +extern uint8_t cam_roll_mode; +extern float cam_roll_phi; +extern bool_t cam_roll_switch; + +#define cam_roll_SetPhiDeg(_deg) { cam_roll_phi = RadOfDeg(_deg); } + +#define cam_roll_Switch(_x) { cam_roll_switch = _x; if (_x) IO0SET = _BV(VIDEO_SWITCH_PIN); else IO0CLR = _BV(VIDEO_SWITCH_PIN); } + + +#endif /* CAM_ROLL_H */ diff --git a/sw/logalizer/Makefile b/sw/logalizer/Makefile index c6d7d410ce..26829adf5a 100644 --- a/sw/logalizer/Makefile +++ b/sw/logalizer/Makefile @@ -32,6 +32,9 @@ play : play.ml plotter : plotter.ml $(OCAMLC) $(INCLUDES) -custom -o $@ unix.cma str.cma xml-light.cma glibivy-ocaml.cma -I +lablgtk2 -I ../lib/ocaml lablgtk.cma lib-pprz.cma gtkInit.cmo $^ +plot : plot.ml + $(OCAMLC) $(INCLUDES) -custom -o $@ unix.cma str.cma xml-light.cma glibivy-ocaml.cma -I +lablgtk2 -I ../lib/ocaml lablgtk.cma lib-pprz.cma gtkInit.cmo $^ + pt : ahrsview imuview ahrs2fg @@ -105,4 +108,4 @@ ahrs2fg: ahrs2fg.c network.c flight_gear.c utils.c ivy_example: ivy_example.c - gcc -g -O2 -Wall `pkg-config glib-2.0 --cflags` -o $@ $^ `pkg-config glib-2.0 --libs` `pcre-config --libs` -lglibivy \ No newline at end of file + gcc -g -O2 -Wall `pkg-config glib-2.0 --cflags` -o $@ $^ `pkg-config glib-2.0 --libs` `pcre-config --libs` -lglibivy diff --git a/sw/logalizer/plot.ml b/sw/logalizer/plot.ml new file mode 100644 index 0000000000..f415222a4b --- /dev/null +++ b/sw/logalizer/plot.ml @@ -0,0 +1,278 @@ +(* + * $Id$ + * + * Real time plotter + * + * Copyright (C) 2007- ENAC, 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 + + +module P = Pprz.Messages (struct let name = "telemetry" end) + + +let double__ = + let underscore = Str.regexp "_" in + fun s -> Str.global_replace underscore "__" s + + +let (//) = Filename.concat + +let colors = [|"red"; "blue"; "green"; "orange"; "purple"; "magenta"|] + +let labelled_entry = fun ?width_chars text value (h:GPack.box) -> + let label = GMisc.label ~text ~packing:h#pack () in + label, GEdit.entry ?width_chars ~text:value ~packing:h#pack () + +class plot = fun ~width ~height ~packing () -> + let da = GMisc.drawing_area ~width ~height ~show:true ~packing () in + let curves = Hashtbl.create 3 in + object (self) + val mutable min_x = max_float + val mutable max_x = min_float + val mutable min = max_float + val mutable max = min_float + val mutable color_index = 0 + val mutable csts = ([] : float list) + val mutable auto_scale = true + + method auto_scale = auto_scale + method set_auto_scale = fun x -> auto_scale <- x + method min = min + method set_min = fun x -> min <- x + method max = max + method set_max = fun x -> max <- x + + method destroy = fun () -> () + + method drawing_area = da + + method add_cst = fun v -> + csts <- v :: csts + + method delete_cst = fun v -> + csts <- List.filter (fun x -> x <> v) csts + + method add_curve = fun (name:string) (values:(float*float) array) -> + Hashtbl.add curves name values + + method delete_curve = fun (name:string) -> + Hashtbl.remove curves name + + method update_curves = fun () -> + let {Gtk.width=width; height=height} = da#misc#allocation in + let dr = GDraw.pixmap ~width ~height ~window:da () in + dr#set_foreground (`NAME "white"); + dr#rectangle ~x:0 ~y:0 ~width ~height ~filled:true (); + + (* Time Graduations *) + let context = da#misc#create_pango_context in + context#set_font_by_name "sans 10 "; + let layout = context#create_layout in + + let f = fun x y s -> + Pango.Layout.set_text layout s; + let (w, h) = Pango.Layout.get_pixel_size layout in + dr#put_layout ~x ~y:(y-h) ~fore:`BLACK layout in + () + end + + +(* Indexed by log *) +let logs = Hashtbl.create 3 + +let pprz_float = function + Pprz.Int i -> float i + | Pprz.Float f -> f + | Pprz.Int32 i -> Int32.to_float i + | Pprz.String s -> float_of_string s + | Pprz.Array _ -> failwith "pprz_float" + + +let load_log = fun (plot:plot) (menubar:GMenu.menu_shell GMenu.factory) xml_file -> + let xml = Xml.parse_file xml_file in + let data_file = ExtXml.attrib xml "data_file" in + + let f = Ocaml_tools.find_file [Filename.dirname xml_file] data_file in + let f = Ocaml_tools.open_compress f in + let acs = Hashtbl.create 3 in (* indexed by A/C *) + Hashtbl.add logs data_file acs; + try + while true do + let l = input_line f in + try + Scanf.sscanf l "%f %s %[^\n]" + (fun t ac m -> + if not (Hashtbl.mem acs ac) then + Hashtbl.add acs ac (Hashtbl.create 97); + let msgs = Hashtbl.find acs ac in + + let msg_id, vs = P.values_of_string m in + if not (Hashtbl.mem msgs msg_id) then + Hashtbl.add msgs msg_id (Hashtbl.create 97); + let fields = Hashtbl.find msgs msg_id in + + List.iter (fun (f, v) -> Hashtbl.add fields f (t, v)) vs + ) + with + exc -> prerr_endline (Printexc.to_string exc) + done + with + End_of_file -> + close_in f; + (* Build the A/C menus *) + Hashtbl.iter + (fun ac msgs -> + let menu_name = sprintf "%s:%s" (String.sub data_file 0 18) ac in + let menu = menubar#add_submenu menu_name in + let menu_fact = new GMenu.factory menu in + let l = ref [] in + Hashtbl.iter (fun msg fields -> l := (P.message_of_id msg, fields):: !l) msgs; + let l = List.sort (fun (a,_) (b,_) -> compare a b) !l in + + (* Build the msg menus *) + List.iter + (fun (msg, fields) -> + let menu = menu_fact#add_submenu (double__ msg.Pprz.name) in + let menu_fact = new GMenu.factory menu in + let l = ref [] in + Hashtbl.iter + (fun f v -> if not (List.mem f !l) then l := f :: !l) + fields; + let l = List.sort compare !l in + (* Build the field menus *) + List.iter + (fun f -> + let values = Hashtbl.find_all fields f in + let values = List.map (fun (t, v) -> (t, pprz_float v)) values in + let values = Array.of_list values in + Array.sort compare values; + let name = sprintf "%s:%s:%s:%s" menu_name ac msg.Pprz.name f in + let callback = fun _ -> plot#add_curve name values; plot#update_curves () in + ignore (menu_fact#add_item ~callback (double__ f))) + l + ) + l + ) + acs + + + +let file_dialog ~title ~callback () = + let sel = GWindow.file_selection ~title ~filename:"var/logs/*.log" ~modal:true () in + ignore (sel#cancel_button#connect#clicked ~callback:sel#destroy); + ignore + (sel#ok_button#connect#clicked + ~callback:(fun () -> + let name = sel#filename in + sel#destroy (); + callback name)); + sel#show () + + +let open_log = fun plot menubar () -> + ignore (file_dialog ~title:"Open Log" ~callback:(fun name -> load_log plot menubar name) ()) + + +let rec plot_window = fun init -> + let plotter = GWindow.window ~allow_shrink:true ~title:"Log Plotter" () in + let vbox = GPack.vbox ~packing:plotter#add () in + let quit = fun () -> GMain.Main.quit (); exit 0 in + + let tooltips = GData.tooltips () in + + let menubar = GMenu.menu_bar ~packing:vbox#pack () in + let factory = new GMenu.factory menubar in + let accel_group = factory#accel_group in + let file_menu = factory#add_submenu "File" in + let file_menu_fact = new GMenu.factory file_menu ~accel_group in + + let width = 900 and height = 200 in + let plot = new plot ~width ~height ~packing:(vbox#pack ~expand:true) () in + + ignore (file_menu_fact#add_item "Open Log" ~key:GdkKeysyms._O ~callback:(open_log plot factory)); + + ignore (file_menu_fact#add_item "New" ~key:GdkKeysyms._N ~callback:(fun () -> plot_window [])); +(* + let close = fun () -> plotter#destroy () in + ignore (file_menu_fact#add_item "Close" ~key:GdkKeysyms._W ~callback:close); *) + + ignore (file_menu_fact#add_item "Quit" ~key:GdkKeysyms._Q ~callback:quit); + let curves_menu = factory#add_submenu "Curves" in + let curves_menu_fact = new GMenu.factory curves_menu in + + let h = GPack.hbox ~packing:vbox#pack () in + + tooltips#set_tip plot#drawing_area#coerce ~text:"Drop a messages field here to draw it"; + ignore (plotter#connect#destroy ~callback:(fun () -> plot#destroy ())); + + (* Auto Scale *) + let auto_scale = GButton.check_button ~label:"Auto Scale" ~active:true ~packing:h#pack () in + ignore (auto_scale#connect#toggled (fun () -> plot#set_auto_scale auto_scale#active)); + let _, min_entry= labelled_entry ~width_chars:5 "Min" "" h in + let _, max_entry= labelled_entry ~width_chars:5 "Max" "" h in + ignore (GMain.Timeout.add 1000 (fun () -> if plot#auto_scale then begin min_entry#set_text (string_of_float plot#min); max_entry#set_text (string_of_float plot#max) end; true)); + ignore (min_entry#connect#activate ~callback:(fun () -> if not plot#auto_scale then plot#set_min (float_of_string min_entry#text))); + ignore (max_entry#connect#activate ~callback:(fun () -> if not plot#auto_scale then plot#set_max (float_of_string max_entry#text))); + + (* X range *) + let _, _x_min_entry= labelled_entry ~width_chars:5 "Min" "" h in + let _, _x_max_entry= labelled_entry ~width_chars:5 "Max" "" h in + + (* Constants *) + let _, cst = labelled_entry ~width_chars:5 "Constant:" "" h in + let add_cst = fun s -> + let v = float_of_string s in + plot#add_cst v; + let eb = GBin.event_box ~width:10 ~height:10 () in + eb#coerce#misc#modify_bg [`NORMAL, `NAME "black"]; + let item = curves_menu_fact#add_image_item ~image:eb#coerce ~label:s () in + + let delete = fun () -> + plot#delete_cst v; + curves_menu#remove (item :> GMenu.menu_item) in + ignore (item#connect#activate ~callback:delete); + in + ignore (cst#connect#activate ~callback:(fun () ->add_cst cst#text)); + tooltips#set_tip cst#coerce ~text:"Enter value for a constant curve"; + + List.iter (fun f -> load_log plot factory f) init; + + plotter#add_accel_group accel_group; + plotter#show () + + + + +let _ = + let logs = ref [] in + Arg.parse + [] + (fun x -> logs := x :: !logs) + "Usage: "; + + plot_window !logs; + + let loop = Glib.Main.create true in + while Glib.Main.is_running loop do + ignore (Glib.Main.iteration true) + done