diff --git a/README b/README deleted file mode 100644 index f93c8bf9a8..0000000000 --- a/README +++ /dev/null @@ -1,98 +0,0 @@ -# Copyright (C) 2003-2011 The Paparazzi Team -# -# 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. - - -Intro ------ - -Paparazzi is an attempt to develop a free software Unmanned (Air) Vehicle System. - As of today the system is being used successfuly by a number of hobyists, universities and companies all over the world, on vehicle of various size ( 100g to 25Kg ) and of various nature ( fixed wing, rotorcrafts, boats and surface vehicles). - -Up to date information is available from the wiki website - - http://paparazzi.enac.fr - -and from the mailing list (http://savannah.nongnu.org/mail/?group=paparazzi) -and the IRC channel (freenode, #paparazzi). - -Directories quick and dirty description: ---------------------------------------- - -conf: the configuration directory (airframe, radio, ... descriptions). - -data: where to put read-only data (e.g. maps, terrain elevation files, icons) - -sw: software (onboard, ground station, simulation, ...) - -var: products of compilation, cache for the map tiles, ... - -debian: Debian packaging control files - - -Required Software ------------------ - -Installation is described in the wiki (paparazzi.enac.fr/wiki/Installation). -Main requirements include - - OCaml (ocaml.org), xml-light library (http://tech.motion-twin.com/xmllight) - - gcc, GTK2, Glib2, libgnomecanvas, libxml2 - - ARM7 micro-controller development environnment (gcc, loader, libc, binutils) - - ... - -For Debian or Ubuntu users, required packages are available at - - http://paparazzi.enac.fr/debian - - - - "paparazzi-dev" will provide everything needed to compile and run the ground segment and the simulator. If something is missing, please report it. - - "paparazzi-arm-multilib" is required to compile the code for LPC21 and STM32 based boards - - "paparazzi-omap" is needed for building code for the optional Gumstix Overo module available on lisa/L - - - "paparazzi-jsbsim" is needed for using jsbsim as flight dynamic model for the simulator. - -Compilation and demo simulation -------------------------------- - - 1) type "make" in the top directory to compile all the libraries and tools. - - 2) "./paparazzi" to run the Paparazzi Center - - 3) Select the "Microjet" aircraft in the upper-left A/C -combo box. Select "sim" from upper-middle "target" combo box. Click -"Build". When the compilation is finished, select "Simulation" from -the upper-right session combo box and click "Execute". - - 4) In the GCS, wait about 10s for the aircraft to be in the "Holding -point" navigation block. Switch to the "Takeoff" block (lower-left -blue airway button in the strip). Takeoff with the green launch button. - -Uploading of the embedded software ----------------------------------- - - 1) Power the flight controller board while it is connected to the PC with -the USB cable. - - 2) From the Paparazzi center, select the "ap" target, and click "Upload". - - -Flight -------------------------------------- - - 1) From the Paparazzi Center, select the flight session and ... do -the same than in simulation ! diff --git a/README.md b/README.md new file mode 100644 index 0000000000..8400e0d98a --- /dev/null +++ b/README.md @@ -0,0 +1,69 @@ +Paparazzi UAS +============= + +Paparazzi is an attempt to develop a free software Unmanned (Air) Vehicle System. + As of today the system is being used successfuly by a number of hobyists, universities and companies all over the world, on vehicle of various size ( 100g to 25Kg ) and of various nature ( fixed wing, rotorcrafts, boats and surface vehicles). + +Up to date information is available in the wiki http://paparazzi.enac.fr + +and from the mailing list [paparazzi-devel@nongnu.org] (http://savannah.nongnu.org/mail/?group=paparazzi) +and the IRC channel (freenode, #paparazzi). + + +Required Software +----------------- + +Installation is described in the wiki (http://paparazzi.enac.fr/wiki/Installation). + +For Ubuntu users, required packages are available in the [paparazzi-uav PPA] (https://launchpad.net/~paparazzi-uav/+archive/ppa), +Debian users can use http://paparazzi.enac.fr/debian + + +- **paparazzi-dev** is the meta-package that depends on everything needed to compile and run the ground segment and the simulator. +- **paparazzi-arm-multilib** ARM cross-compiling toolchain for LPC21 and STM32 based boards. +- **paparazzi-omap** toolchain for the optional Gumstix Overo module available on lisa/L. +- **paparazzi-jsbsim** is needed for using JSBSim as flight dynamic model for the simulator. + + +Directories quick and dirty description: +---------------------------------------- + +_conf_: the configuration directory (airframe, radio, ... descriptions). + +_data_: where to put read-only data (e.g. maps, terrain elevation files, icons) + +_doc_: documentation (diagrams, manual source files, ...) + +_sw_: software (onboard, ground station, simulation, ...) + +_var_: products of compilation, cache for the map tiles, ... + + +Compilation and demo simulation +------------------------------- + +1. type "make" in the top directory to compile all the libraries and tools. + +2. "./paparazzi" to run the Paparazzi Center + +3. Select the "Microjet" aircraft in the upper-left A/C combo box. + Select "sim" from upper-middle "target" combo box. Click "Build". + When the compilation is finished, select "Simulation" from + the upper-right session combo box and click "Execute". + +4. In the GCS, wait about 10s for the aircraft to be in the "Holding point" navigation block. + Switch to the "Takeoff" block (lower-left blue airway button in the strip). + Takeoff with the green launch button. + +Uploading of the embedded software +---------------------------------- + +1. Power the flight controller board while it is connected to the PC with the USB cable. + +2. From the Paparazzi center, select the "ap" target, and click "Upload". + + +Flight +------ + +1. From the Paparazzi Center, select the flight session and ... do the same than in simulation ! \ No newline at end of file diff --git a/conf/airframes/ENAC/fixed-wing/twinjet2.xml b/conf/airframes/ENAC/fixed-wing/twinjet2.xml index 91cf90a9cb..7ae81eb513 100644 --- a/conf/airframes/ENAC/fixed-wing/twinjet2.xml +++ b/conf/airframes/ENAC/fixed-wing/twinjet2.xml @@ -14,10 +14,10 @@ - + @@ -33,7 +33,7 @@ - + @@ -217,103 +217,4 @@ - - diff --git a/conf/airframes/ENAC/quadrotor/blender.xml b/conf/airframes/ENAC/quadrotor/blender.xml index e6a47257d5..d7e52bbdf9 100644 --- a/conf/airframes/ENAC/quadrotor/blender.xml +++ b/conf/airframes/ENAC/quadrotor/blender.xml @@ -1,11 +1,11 @@ - + @@ -21,13 +21,13 @@ - - - + + + @@ -47,17 +47,11 @@ - - - - - - + @@ -66,20 +60,15 @@ - + +
- - - -
- - +
diff --git a/conf/airframes/ENAC/quadrotor/navgo.xml b/conf/airframes/ENAC/quadrotor/navgo.xml index 745662131c..ec2b8262d3 100644 --- a/conf/airframes/ENAC/quadrotor/navgo.xml +++ b/conf/airframes/ENAC/quadrotor/navgo.xml @@ -20,7 +20,6 @@ - @@ -29,11 +28,11 @@ - - - - + + + + @@ -72,31 +71,39 @@
- - - + + + - - - + + + - - - + + + - - - + + + + + + + + + @@ -124,6 +131,8 @@ + + @@ -148,7 +157,8 @@
- + +
diff --git a/conf/autopilot/rotorcraft.makefile b/conf/autopilot/rotorcraft.makefile index 052a38d8cb..dce50ace9c 100644 --- a/conf/autopilot/rotorcraft.makefile +++ b/conf/autopilot/rotorcraft.makefile @@ -145,9 +145,11 @@ ap.CFLAGS += -DUSE_I2C2 else ifeq ($(BOARD), lisa_m) ap.CFLAGS += -DUSE_I2C2 else ifeq ($(BOARD), navgo) -ap.CFLAGS += -DUSE_I2C1 -ap.CFLAGS += -DADS1114_I2C_DEVICE=i2c1 -ap.srcs += peripherals/ads1114.c +include $(CFG_ROTORCRAFT)/spi.makefile +ap.CFLAGS += -DUSE_SPI_SLAVE0 +ap.CFLAGS += -DSPI_NO_UNSELECT_SLAVE +ap.CFLAGS += -DSPI_MASTER +ap.srcs += peripherals/mcp355x.c endif ifneq ($(BARO_LED),none) ap.CFLAGS += -DROTORCRAFT_BARO_LED=$(BARO_LED) diff --git a/conf/autopilot/subsystems/shared/imu_navgo.makefile b/conf/autopilot/subsystems/shared/imu_navgo.makefile index e10385bbc3..2a24fbf0d0 100644 --- a/conf/autopilot/subsystems/shared/imu_navgo.makefile +++ b/conf/autopilot/subsystems/shared/imu_navgo.makefile @@ -12,10 +12,12 @@ IMU_NAVGO_CFLAGS += -DUSE_I2C1 -DI2C1_SCLL=25 -DI2C1_SCLH=25 IMU_NAVGO_CFLAGS += -DITG3200_I2C_DEVICE=$(IMU_NAVGO_I2C_DEVICE) IMU_NAVGO_CFLAGS += -DITG3200_I2C_ADDR=ITG3200_ADDR_ALT IMU_NAVGO_CFLAGS += -DITG3200_SMPLRT_DIV=1 +IMU_NAVGO_CFLAGS += -DITG3200_DLFP_CFG=5 IMU_NAVGO_SRCS += peripherals/itg3200.c IMU_NAVGO_CFLAGS += -DADXL345_I2C_DEVICE=$(IMU_NAVGO_I2C_DEVICE) IMU_NAVGO_CFLAGS += -DADXL345_I2C_ADDR=ADXL345_ADDR_ALT +IMU_NAVGO_CFLAGS += -DADXL345_BW_RATE=0x8 IMU_NAVGO_SRCS += peripherals/adxl345.i2c.c IMU_NAVGO_CFLAGS += -DHMC58XX_I2C_DEVICE=$(IMU_NAVGO_I2C_DEVICE) diff --git a/sw/airborne/arch/lpc21/mcu_periph/spi_arch.c b/sw/airborne/arch/lpc21/mcu_periph/spi_arch.c index 5ec122bcb8..d7286e6dcd 100644 --- a/sw/airborne/arch/lpc21/mcu_periph/spi_arch.c +++ b/sw/airborne/arch/lpc21/mcu_periph/spi_arch.c @@ -193,7 +193,9 @@ void SPI1_ISR(void) { } if (bit_is_set(SSPMIS, RTMIS)) { /* Rx fifo is not empty and no receive took place in the last 32 bits period */ +#if !SPI_NO_UNSELECT_SLAVE SpiUnselectCurrentSlave(); +#endif SpiReceive(); SpiDisableRti(); SpiClearRti(); /* clear interrupt */ diff --git a/sw/airborne/boards/navgo/baro_board.c b/sw/airborne/boards/navgo/baro_board.c index 8940bae2f7..b42b69ee3a 100644 --- a/sw/airborne/boards/navgo/baro_board.c +++ b/sw/airborne/boards/navgo/baro_board.c @@ -27,57 +27,43 @@ #include "subsystems/sensors/baro.h" #include "led.h" +#include "mcu_periph/spi.h" /* Common Baro struct */ struct Baro baro; -/* Number of values to compute an offset at startup */ -#define OFFSET_NBSAMPLES_AVRG 300 -uint16_t offset_cnt; - -#if USE_BARO_AS_ALTIMETER -/* Weight for offset IIR filter */ -#define OFFSET_FILTER 7 - -float baro_alt; -float baro_alt_offset; -#endif +/* Counter to init mcp355x at startup */ +#define STARTUP_COUNTER 200 +uint16_t startup_cnt; void baro_init( void ) { - ads1114_init(); + mcp355x_init(); + SpiSelectSlave0(); // never unselect this slave (continious conversion mode) baro.status = BS_UNINITIALIZED; baro.absolute = 0; baro.differential = 0; /* not handled on this board */ #ifdef ROTORCRAFT_BARO_LED LED_OFF(ROTORCRAFT_BARO_LED); #endif - offset_cnt = OFFSET_NBSAMPLES_AVRG; -#if USE_BARO_AS_ALTIMETER - baro_alt = 0.; - baro_alt_offset = 0.; -#endif + startup_cnt = STARTUP_COUNTER; } void baro_periodic( void ) { if (baro.status == BS_UNINITIALIZED) { -#if USE_BARO_AS_ALTIMETER - // IIR filter to compute an initial offset - baro_alt_offset = (OFFSET_FILTER * baro_alt_offset + (float)baro.absolute) / (OFFSET_FILTER + 1); -#endif - // decrease init counter - --offset_cnt; + // Run some loops to get correct readings from the adc + --startup_cnt; #ifdef ROTORCRAFT_BARO_LED LED_TOGGLE(ROTORCRAFT_BARO_LED); #endif - if (offset_cnt == 0) { + if (startup_cnt == 0) { baro.status = BS_RUNNING; #ifdef ROTORCRAFT_BARO_LED LED_ON(ROTORCRAFT_BARO_LED); #endif } } - // Read the ADC - ads1114_read(); + // Read the ADC (at 50/4 Hz, conversion time is 68 ms) + RunOnceEvery(4,mcp355x_read()); } diff --git a/sw/airborne/boards/navgo/baro_board.h b/sw/airborne/boards/navgo/baro_board.h index 64a58b1ff6..250476b148 100644 --- a/sw/airborne/boards/navgo/baro_board.h +++ b/sw/airborne/boards/navgo/baro_board.h @@ -31,22 +31,16 @@ #include "std.h" -#include "peripherals/ads1114.h" - -#if USE_BARO_AS_ALTIMETER -extern float baro_alt; -extern float baro_alt_offset; -#define BaroAltHandler() { baro_alt = BARO_SENS*(baro_alt_offset - (float)baro.absolute); } -#endif +#include "peripherals/mcp355x.h" #define BARO_FILTER_GAIN 5 #define BaroEvent(_b_abs_handler, _b_diff_handler) { \ - Ads1114Event(); \ - if (ads1114_data_available) { \ - baro.absolute = (baro.absolute + BARO_FILTER_GAIN*Ads1114GetValue()) / (BARO_FILTER_GAIN+1); \ + mcp355x_event(); \ + if (mcp355x_data_available) { \ + baro.absolute = (baro.absolute + BARO_FILTER_GAIN*mcp355x_data) / (BARO_FILTER_GAIN+1); \ _b_abs_handler(); \ - ads1114_data_available = FALSE; \ + mcp355x_data_available = FALSE; \ } \ } diff --git a/sw/airborne/boards/navgo/imu_navgo.c b/sw/airborne/boards/navgo/imu_navgo.c index 78be53e4a5..e03736c172 100644 --- a/sw/airborne/boards/navgo/imu_navgo.c +++ b/sw/airborne/boards/navgo/imu_navgo.c @@ -103,7 +103,7 @@ void imu_navgo_event( void ) // If the itg3200 I2C transaction has succeeded: convert the data itg3200_event(); if (itg3200_data_available) { - RATES_COPY(imu.gyro_unscaled, itg3200_data); + RATES_ASSIGN(imu.gyro_unscaled, -itg3200_data.q, itg3200_data.p, itg3200_data.r); itg3200_data_available = FALSE; gyr_valid = TRUE; } @@ -119,7 +119,7 @@ void imu_navgo_event( void ) // HMC58XX event task hmc58xx_event(); if (hmc58xx_data_available) { - VECT3_ASSIGN(imu.mag_unscaled, -hmc58xx_data.x, -hmc58xx_data.y, hmc58xx_data.z); + VECT3_ASSIGN(imu.mag_unscaled, hmc58xx_data.x, hmc58xx_data.y, hmc58xx_data.z); hmc58xx_data_available = FALSE; mag_valid = TRUE; } diff --git a/sw/airborne/boards/navgo_1.0.h b/sw/airborne/boards/navgo_1.0.h index 0f23fa9ee0..97d9b0784b 100644 --- a/sw/airborne/boards/navgo_1.0.h +++ b/sw/airborne/boards/navgo_1.0.h @@ -18,17 +18,17 @@ #define PCLK (CCLK / PBSD_VAL) /* Onboard LEDs */ -#define LED_1_BANK 1 -#define LED_1_PIN 25 +#define LED_1_BANK 0 +#define LED_1_PIN 22 #define LED_2_BANK 1 -#define LED_2_PIN 24 +#define LED_2_PIN 28 #define LED_3_BANK 1 -#define LED_3_PIN 23 +#define LED_3_PIN 29 #define LED_4_BANK 1 -#define LED_4_PIN 31 +#define LED_4_PIN 30 /* PPM : rc rx on P0.28 ( CAP0.2 ) */ #define PPM_PINSEL PINSEL1 @@ -45,19 +45,22 @@ /* battery */ /* allow to define ADC_CHANNEL_VSUPPLY in the airframe file*/ #ifndef ADC_CHANNEL_VSUPPLY -#define ADC_CHANNEL_VSUPPLY AdcBank1(3) -#ifndef USE_AD1 -#define USE_AD1 +#define ADC_CHANNEL_VSUPPLY AdcBank0(2) +#ifndef USE_AD0 +#define USE_AD0 #endif -#define USE_AD1_3 +#define USE_AD0_2 #endif -#define DefaultVoltageOfAdc(adc) (0.01837*adc) +#define DefaultVoltageOfAdc(adc) (0.017889*adc) /* SPI (SSP) */ #define SPI_SELECT_SLAVE0_PORT 0 #define SPI_SELECT_SLAVE0_PIN 20 +//#define SPI_SELECT_SLAVE1_PORT 1 +//#define SPI_SELECT_SLAVE1_PIN 19 + #define SPI1_DRDY_PINSEL PINSEL1 #define SPI1_DRDY_PINSEL_BIT 0 #define SPI1_DRDY_PINSEL_VAL 1 diff --git a/sw/airborne/math/Makefile b/sw/airborne/math/Makefile new file mode 100644 index 0000000000..782cfb0b30 --- /dev/null +++ b/sw/airborne/math/Makefile @@ -0,0 +1,47 @@ +# Build shared pprz math library +# + +CC= gcc +CFLAGS= -fpic +INCLUDES= -I $(PAPARAZZI_SRC)/sw/include -I $(PAPARAZZI_SRC)/sw/airborne + +# build in ../../../var/build/math +ifndef BUILDDIR +BUILDDIR=../../../var/build/math +endif + +ifndef PREFIX +PREFIX=/usr +endif +LIB_INSTALLDIR=${PREFIX}/lib +INCLUDE_INSTALLDIR=${PREFIX}/include/pprz +PKGCONFIG_INSTALLDIR=${PREFIX}/lib/pkgconfig +PKGCONFIG_FILE=pprzmath.pc + +SRC= $(wildcard *.c) +OBJ= $(addprefix $(BUILDDIR)/,$(SRC:.c=.o)) + +LIBNAME=libpprzmath + +all: + @cat README + +shared_lib: $(OBJ) + $(CC) -shared -o $(BUILDDIR)/$(LIBNAME).so $(OBJ) + +install_shared_lib: shared_lib + test -d $(LIB_INSTALLDIR) || mkdir -p $(LIB_INSTALLDIR) + cp $(BUILDDIR)/$(LIBNAME).so $(LIB_INSTALLDIR) + test -d $(INCLUDE_INSTALLDIR)/math || mkdir -p $(INCLUDE_INSTALLDIR)/math + cp *.h $(INCLUDE_INSTALLDIR)/math + cp ../../include/std.h $(INCLUDE_INSTALLDIR) + test -d $(PKGCONFIG_INSTALLDIR) || mkdir -p $(PKGCONFIG_INSTALLDIR) + sed -e 's#PREFIX#$(PREFIX)#g' $(PKGCONFIG_FILE).in > $(PKGCONFIG_INSTALLDIR)/$(PKGCONFIG_FILE) + +$(BUILDDIR)/%.o: %.c + test -d $(BUILDDIR) || mkdir -p $(BUILDDIR) + $(CC) -c $< $(CFLAGS) $(INCLUDES) -o $@ + +clean: + rm -f $(BUILDDIR)/*.o $(BUILDDIR)/$(LIBNAME).so + diff --git a/sw/airborne/math/README b/sw/airborne/math/README new file mode 100644 index 0000000000..9c68398093 --- /dev/null +++ b/sw/airborne/math/README @@ -0,0 +1,34 @@ +Math lib used in all airborne code of paparazzi + +HOWTO install a shared library to use in other projects + +1. Build library: in this folder, type + make shared_lib + + the default build directory is var/build/math + to change it: BUILDDIR= make shared_lib + +2. Install library: in this folder, type + make install_shared_lib + + the default install dir is /usr + and will install files in + /usr/lib + /usr/lib/pkgconfig + /usr/include/pprz + + to change the install dir: PREFIX= make install_shared_lib + + note that the default install dir needs root privilege + +HOWTO use the shared library + +1. with pkg-config --cflags --libs + +2. by hand: + LIBS: -L/lib -lpprzmath + CFLAGS: -I/include/pprz + + +"make clean" will only clean the build directory + diff --git a/sw/airborne/math/pprzmath.pc.in b/sw/airborne/math/pprzmath.pc.in new file mode 100644 index 0000000000..b70fbd26f4 --- /dev/null +++ b/sw/airborne/math/pprzmath.pc.in @@ -0,0 +1,9 @@ +prefix=PREFIX +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${exec_prefix}/include +Name: pprzmath +Description: math library used in Paparazzi project (http://paparazzi.enac.fr) +Version:0.1 +Libs: -L${libdir} -lpprzmath +Cflags: -I${includedir}/pprz diff --git a/sw/airborne/peripherals/mcp355x.c b/sw/airborne/peripherals/mcp355x.c index 7cf0892807..3eec8438ab 100644 --- a/sw/airborne/peripherals/mcp355x.c +++ b/sw/airborne/peripherals/mcp355x.c @@ -41,32 +41,20 @@ void mcp355x_init(void) { void mcp355x_read(void) { spi_buffer_length = 4; spi_buffer_input = mcp355x_spi_buf; - SpiSelectSlave0(); + //SpiSelectSlave0(); SpiStart(); } -#ifndef DOWNLINK_DEVICE -#define DOWNLINK_DEVICE DOWNLINK_AP_DEVICE -#endif - -#include "mcu_periph/uart.h" -#include "messages.h" -#include "subsystems/datalink/downlink.h" - void mcp355x_event(void) { - static uint32_t filtered = 0; if (spi_message_received) { spi_message_received = FALSE; if ((mcp355x_spi_buf[0]>>4) == 0) { - //mcp355x_data = (int32_t)(((uint32_t)mcp355x_spi_buf[0]<<16) | ((uint32_t)mcp355x_spi_buf[1]<<8) | (mcp355x_spi_buf[2])); mcp355x_data = (int32_t)( ((uint32_t)mcp355x_spi_buf[0]<<17) | ((uint32_t)mcp355x_spi_buf[1]<<9) | ((uint32_t)mcp355x_spi_buf[2]<<1) | (mcp355x_spi_buf[3]>>7)); - filtered = (5*filtered + mcp355x_data) / (6); - DOWNLINK_SEND_DEBUG(DefaultChannel, DefaultDevice,4,mcp355x_spi_buf); - DOWNLINK_SEND_BARO_RAW(DefaultChannel, DefaultDevice,&mcp355x_data,&filtered); + mcp355x_data_available = TRUE; } } } diff --git a/sw/lib/ocaml/mapTrack.ml b/sw/lib/ocaml/mapTrack.ml index 2bdbc979c0..42501fad1f 100644 --- a/sw/lib/ocaml/mapTrack.ml +++ b/sw/lib/ocaml/mapTrack.ml @@ -75,13 +75,14 @@ class track = fun ?(name="Noname") ?(size = 500) ?(color="red") (geomap:MapCanva (** rectangle representing the field covered by the cam *) let _ac_cam_targeted = ignore ( GnoCanvas.ellipse ~x1: (-. 2.5) ~y1: (-. 2.5 ) ~x2: 2.5 ~y2: 2.5 ~fill_color:color ~props:[`WIDTH_UNITS 1.; `OUTLINE_COLOR color; `FILL_STIPPLE (Gdk.Bitmap.create_from_data ~width:2 ~height:2 "\002\001")] cam) in + let _ = cam#hide () in let mission_target = GnoCanvas.group group in (** red circle : target of the mission *) - let ac_mission_target = - GnoCanvas.ellipse ~x1: (-5.) ~y1: (-5.) ~x2: 5. ~y2: 5. ~fill_color:"red" ~props:[`WIDTH_UNITS 1.; `OUTLINE_COLOR "red"; `FILL_STIPPLE (Gdk.Bitmap.create_from_data ~width:2 ~height:2 "\002\001")] mission_target in - let _ = ac_mission_target#hide () in + let _ac_mission_target = + ignore ( GnoCanvas.ellipse ~x1: (-5.) ~y1: (-5.) ~x2: 5. ~y2: 5. ~fill_color:"red" ~props:[`WIDTH_UNITS 1.; `OUTLINE_COLOR "red"; `FILL_STIPPLE (Gdk.Bitmap.create_from_data ~width:2 ~height:2 "\002\001")] mission_target) in + let _ = mission_target#hide () in (** data at map scale *) let max_cam_half_height_scaled = 10000.0 in @@ -92,6 +93,8 @@ class track = fun ?(name="Noname") ?(size = 500) ?(color="red") (geomap:MapCanva let _desired_circle = GnoCanvas.ellipse group and _desired_segment = GnoCanvas.line group in + let _ = aircraft#raise_to_top () in + object (self) val mutable top = 0 val mutable color = color diff --git a/sw/logalizer/plotter.ml b/sw/logalizer/plotter.ml index d925600091..fc1f523d88 100644 --- a/sw/logalizer/plotter.ml +++ b/sw/logalizer/plotter.ml @@ -80,6 +80,7 @@ type status = class plot = fun ~size ~width ~height ~packing () -> let curves = Hashtbl.create 3 in + let bindings = Hashtbl.create 3 in object (self) inherit Gtk_tools.pixmap_in_drawin_area ~width ~height ~packing () as pm @@ -119,184 +120,189 @@ class plot = fun ~size ~width ~height ~packing () -> method reset () = if auto_scale then begin - min <- max_float; - max <- -. max_float + min <- max_float; + max <- -. max_float end; Hashtbl.iter (fun _ a -> - a.index <- 0; - a.average#set_value 0.; - a.stdev#set_value 0.; - for i = 0 to Array.length a.array - 1 do a.array.(i) <- None done) - curves + a.index <- 0; + a.average#set_value 0.; + a.stdev#set_value 0.; + for i = 0 to Array.length a.array - 1 do a.array.(i) <- None done) + curves method set_size = fun new_size -> if new_size <> size && new_size > 0 then begin - Hashtbl.iter (fun _ a -> - let new_array = Array.create new_size None in - for i = 0 to Pervasives.min size new_size - 1 do - new_array.(new_size - 1 - i) <- a.array.((a.index-i+size) mod size) - done; - a.array <- new_array; - a.index <- new_size - 1) - curves; - size <- new_size + Hashtbl.iter (fun _ a -> + let new_array = Array.create new_size None in + for i = 0 to Pervasives.min size new_size - 1 do + new_array.(new_size - 1 - i) <- a.array.((a.index-i+size) mod size) + done; + a.array <- new_array; + a.index <- new_size - 1) + curves; + size <- new_size end - method create_curve = fun (name:string) -> + method create_curve = fun (name:string) binding -> let color = colors.(color_index) in let values = create_values size color in color_index <- (color_index+1) mod Array.length colors; Hashtbl.add curves name values; + Hashtbl.add bindings name binding; values method delete_curve = fun name -> - Hashtbl.remove curves name + Hashtbl.remove curves name; + try (* this try should not be needed *) + let binding = Hashtbl.find bindings name in + Ivy.unbind binding; + Hashtbl.remove bindings name + with _ -> () method add_value = fun name v -> if status <> Stop then - let a = Hashtbl.find curves name in - a.array.(a.index) <- Some v; - if auto_scale then begin - min <- Pervasives.min min v; - max <- Pervasives.max max v - end + let a = Hashtbl.find curves name in + a.array.(a.index) <- Some v; + if auto_scale then begin + min <- Pervasives.min min v; + max <- Pervasives.max max v + end method reset_scale = fun () -> min <- max_float; max <- -. max_float; Hashtbl.iter (* for all curves *) - (fun name a -> - Array.iter (* for all values *) - (function - None -> () - | Some v -> - min <- Pervasives.min min v; - max <- Pervasives.max max v) - a.array) - curves + (fun name a -> + Array.iter (* for all values *) + (function + None -> () + | Some v -> + min <- Pervasives.min min v; + max <- Pervasives.max max v) + a.array) + curves method shift = fun () -> Hashtbl.iter - (fun _ a -> - (* Shift *) - a.index <- (a.index + 1) mod (Array.length a.array); - a.array.(a.index) <- None) - curves + (fun _ a -> + (* Shift *) + a.index <- (a.index + 1) mod (Array.length a.array); + a.array.(a.index) <- None) + curves method update_curves = fun () -> if Hashtbl.length curves > 0 then - try - if status <> Stop then - self#shift (); - if status <> Suspend then - let da = pm#drawing_area in - let {Gtk.width=width; height=height} = da#misc#allocation in - let dr = pm#get_pixmap () in - dr#set_foreground (`NAME "white"); - dr#rectangle ~x:0 ~y:0 ~width ~height ~filled:true (); - let margin = Pervasives.min (height / 10) 20 in + try + if status <> Stop then + self#shift (); + if status <> Suspend then + let da = pm#drawing_area in + let {Gtk.width=width; height=height} = da#misc#allocation in + let dr = pm#get_pixmap () in + dr#set_foreground (`NAME "white"); + dr#rectangle ~x:0 ~y:0 ~width ~height ~filled:true (); + let margin = Pervasives.min (height / 10) 20 in - (* Time Graduations *) - let context = da#misc#create_pango_context in - context#set_font_by_name ("sans " ^ string_of_int (margin/2)); - let layout = context#create_layout in + (* Time Graduations *) + let context = da#misc#create_pango_context in + context#set_font_by_name ("sans " ^ string_of_int (margin/2)); + let layout = context#create_layout in - Pango.Layout.set_text layout "X"; - let (_, h) = Pango.Layout.get_pixel_size layout in + Pango.Layout.set_text layout "X"; + let (_, h) = Pango.Layout.get_pixel_size 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/2) ~fore:`BLACK 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/2) ~fore:`BLACK layout in - let t = dt *. float size in - f (width-width/size) (height-h/2) "0"; - f (width/2) (height-h/2) (Printf.sprintf "-%.1fs" (t/.2.)); - f 0 (height-h/2) (Printf.sprintf "-%.1fs" t); + let t = dt *. float size in + f (width-width/size) (height-h/2) "0"; + f (width/2) (height-h/2) (Printf.sprintf "-%.1fs" (t/.2.)); + f 0 (height-h/2) (Printf.sprintf "-%.1fs" t); - (* Y graduations *) - let (min, max) = - if max > min then (min, max) - else let d = abs_float max /. 10. in (max -. d, max +. d) in - let delta = max -. min in + (* Y graduations *) + let (min, max) = + if max > min then (min, max) + else let d = abs_float max /. 10. in (max -. d, max +. d) in + let delta = max -. min in - let dy = float (height-2*margin) /. delta in - let y = fun v -> - height - margin - truncate ((v-.min)*.dy) in + let dy = float (height-2*margin) /. delta in + let y = fun v -> + height - margin - truncate ((v-.min)*.dy) in - let scale = log delta /. log 10. in - let d = 10. ** floor scale in - let u = - if delta < 2.*.d then d/.5. - else if delta < 5.*.d then d/.2. - else d in - let tick_min = min -. mod_float min u in - for i = 0 to truncate (delta/.u) + 1 do - let tick = tick_min +. float i *. u in - f 0 (y tick) (Printf.sprintf "%.*f" (Pervasives.max 0 (2-truncate scale)) tick) - done; + let scale = log delta /. log 10. in + let d = 10. ** floor scale in + let u = + if delta < 2.*.d then d/.5. + else if delta < 5.*.d then d/.2. + else d in + let tick_min = min -. mod_float min u in + for i = 0 to truncate (delta/.u) + 1 do + let tick = tick_min +. float i *. u in + f 0 (y tick) (Printf.sprintf "%.*f" (Pervasives.max 0 (2-truncate scale)) tick) + done; - (* Constants *) - List.iter (fun v -> - dr#set_foreground (`NAME "black"); - dr#lines [(0, y v); (width-width/size, y v)]) - csts; + (* Constants *) + List.iter (fun v -> + dr#set_foreground (`NAME "black"); + dr#lines [(0, y v); (width-width/size, y v)]) + csts; - let margin = 3 in - let title_y = ref margin in - Hashtbl.iter - (fun title a -> - (* Draw and compute average and stdev*) - let curve = ref [] - and sum = ref 0. and sum_squares = ref 0. - and n = ref 0 in - assert (size = Array.length a.array); - let last_value = ref None in - for i = 0 to size - 1 do - let i' = (i+a.index) mod size in - match a.array.(i') with - None -> () - | Some v -> - incr n; - sum := !sum +. v; - sum_squares := !sum_squares +. v *. v; - let x = (i * width) / size in - begin - match !last_value with - Some lv when a.discrete -> - curve := (x, y lv) :: !curve - | _ -> () - end; - curve := (x, y v) :: !curve; - last_value := Some v - done; - if !curve <> [] then begin - dr#set_foreground (`NAME a.color); - dr#lines !curve; - end; - let fn = float !n in - let avg = !sum /. fn in - let stdev = sqrt ((!sum_squares -. fn *. avg *. avg) /. fn) in - set_float_value a.average avg; - set_float_value a.stdev stdev; + let margin = 3 in + let title_y = ref margin in + Hashtbl.iter (fun title a -> + (* Draw and compute average and stdev*) + let curve = ref [] + and sum = ref 0. and sum_squares = ref 0. + and n = ref 0 in + assert (size = Array.length a.array); + let last_value = ref None in + for i = 0 to size - 1 do + let i' = (i+a.index) mod size in + match a.array.(i') with + None -> () + | Some v -> + incr n; + sum := !sum +. v; + sum_squares := !sum_squares +. v *. v; + let x = (i * width) / size in + begin + match !last_value with + Some lv when a.discrete -> + curve := (x, y lv) :: !curve + | _ -> () + end; + curve := (x, y v) :: !curve; + last_value := Some v + done; + if !curve <> [] then begin + dr#set_foreground (`NAME a.color); + dr#lines !curve; + end; + let fn = float !n in + let avg = !sum /. fn in + let stdev = sqrt ((!sum_squares -. fn *. avg *. avg) /. fn) in + set_float_value a.average avg; + set_float_value a.stdev stdev; - (* Title *) - Pango.Layout.set_text layout title; - let (w, h) = Pango.Layout.get_pixel_size layout in - dr#rectangle ~x:(width-h-margin) ~y:!title_y ~width:h ~height:h ~filled:true (); + (* Title *) + Pango.Layout.set_text layout title; + let (w, h) = Pango.Layout.get_pixel_size layout in + dr#rectangle ~x:(width-h-margin) ~y:!title_y ~width:h ~height:h ~filled:true (); - dr#set_foreground `BLACK; - dr#put_layout ~x:(width-2*margin-w-h) ~y:(!title_y) layout; - title_y := !title_y + h + margin) + dr#set_foreground `BLACK; + dr#put_layout ~x:(width-2*margin-w-h) ~y:(!title_y) layout; + title_y := !title_y + h + margin) curves; pm#redraw () - with - exc -> - prerr_endline (Printexc.to_string exc) + with + exc -> + prerr_endline (Printexc.to_string exc) method stop_timer = fun () -> match timer with - None -> () + None -> () | Some t -> GMain.Timeout.remove t method set_update_time = fun delay -> @@ -306,7 +312,7 @@ class plot = fun ~size ~width ~height ~packing () -> method button_press = fun ev -> match GdkEvent.Button.button ev with - 3 -> self#reset_scale (); true + 3 -> self#reset_scale (); true | _ -> false initializer ignore (self#drawing_area#event#add [`BUTTON_PRESS]) @@ -327,7 +333,7 @@ let base_and_index = fun field_descr -> if Str.string_match field_regexp field_descr 0 then ( Str.matched_group 1 field_descr, - int_of_string (Str.matched_group 2 field_descr)) + int_of_string (Str.matched_group 2 field_descr)) else (field_descr, 0) @@ -339,26 +345,32 @@ let rec plot_window = fun window -> (* Register the window *) let oid = plotter#get_oid in - Hashtbl.add windows oid (); + Hashtbl.add windows oid []; ignore (plotter#parse_geometry window.geometry); plotter#set_icon (Some (GdkPixbuf.from_file Env.icon_file)); let vbox = GPack.vbox ~packing:plotter#add () in - let quit = fun () -> GMain.Main.quit (); exit 0 in - - let close = fun () -> - plotter#destroy (); - Hashtbl.remove windows oid; - if Hashtbl.length windows = 0 then - quit () 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 "Plot" in let file_menu_fact = new GMenu.factory file_menu ~accel_group in + let h = GPack.hbox ~packing:vbox#pack () in + let curves_menu = factory#add_submenu "Curves" in + let curves_menu_fact = new GMenu.factory curves_menu in + let tooltips = GData.tooltips () in + + let width = 900 and height = 200 in + let plot = new plot ~size: !size ~width ~height ~packing:(vbox#pack ~expand:true) () in + + let quit = fun () -> GMain.Main.quit (); exit 0 in + + let close = fun () -> + List.iter (fun c -> plot#delete_curve c) (Hashtbl.find windows oid); + plotter#destroy (); + Hashtbl.remove windows oid; + if Hashtbl.length windows = 0 then + quit () in ignore (file_menu_fact#add_item "New" ~key:GdkKeysyms._N ~callback:(fun () -> plot_window {window with curves=[]})); @@ -369,18 +381,12 @@ let rec plot_window = fun window -> ignore (file_menu_fact#add_separator ()); 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 tooltips#set_tip reset_item#coerce ~text:"Reset the current display and the current data"; tooltips#set_tip curves_menu#coerce ~text:"Delete the curve"; tooltips#set_tip suspend_item#coerce ~text:"Freeze the display while the data are still updated"; tooltips#set_tip stop_item#coerce ~text:"Freeze the data update while the display is active (e.g. resizable)"; tooltips#set_tip start_item#coerce ~text:"UnFreeze"; - let h = GPack.hbox ~packing:vbox#pack () in - - let width = 900 and height = 200 in - let plot = new plot ~size: !size ~width ~height ~packing:(vbox#pack ~expand:true) () in tooltips#set_tip plot#drawing_area#coerce ~text:"Drop a messages field here to draw it"; ignore (plotter#connect#destroy ~callback:close); @@ -448,8 +454,7 @@ let rec plot_window = fun window -> (* Delete *) let delete_item = submenu_fact#add_item "Delete" in let delete = fun () -> - plot#delete_curve name; - Ivy.unbind binding; + plot#delete_curve name; curves_menu#remove (curve_item :> GMenu.menu_item) in ignore (delete_item#connect#activate ~callback:delete); @@ -471,7 +476,8 @@ let rec plot_window = fun window -> let _item = submenu_fact#add_image_item ~image:stdev_value#coerce ~label:"Stdev" () in let update_stdev_value = fun () -> stdev_value#set_text (sprintf "%.6f" curve.stdev#value) in - ignore (curve.stdev#connect#value_changed update_stdev_value) in + ignore (curve.stdev#connect#value_changed update_stdev_value) + in let add_curve = fun ?(factor=(1.,0.)) name -> let (a, b) = factor in @@ -482,10 +488,9 @@ let rec plot_window = fun window -> let cb = fun _sender values -> let (field_name, index) = base_and_index field_descr in let value = - match Pprz.assoc field_name values with - Pprz.Array array -> - array.(index) - | scalar -> scalar in + match Pprz.assoc field_name values with + Pprz.Array array -> array.(index) + | scalar -> scalar in let float = pprz_float value in let v = float *. a +. b in plot#add_value name v in @@ -493,30 +498,35 @@ let rec plot_window = fun window -> let module P = Pprz.Messages (struct let name = class_name end) in let binding = if sender = "*" then - P.message_bind msg_name cb + P.message_bind msg_name cb else - P.message_bind ~sender msg_name cb in + P.message_bind ~sender msg_name cb in - let curve = plot#create_curve name in - insert_in_menu curve name binding in + let curve = plot#create_curve name binding in + insert_in_menu curve name binding; + + (* store name of the curves associated to a window correct closing *) + let curves_name = Hashtbl.find windows oid in + Hashtbl.replace windows oid (curves_name @ [name]) + in (* Drag and drop handler *) - let data_received = fun context ~x ~y data ~info ~time -> - let factor = Ocaml_tools.affine_transform factor#text in - try - let name = data#data in - add_curve ~factor name - with - exc -> prerr_endline (Printexc.to_string exc) + let data_received = fun context ~x ~y data ~info ~time -> + let factor = Ocaml_tools.affine_transform factor#text in + try + let name = data#data in + add_curve ~factor name + with + exc -> prerr_endline (Printexc.to_string exc) in - plotter#drag#dest_set dnd_targets ~actions:[`COPY]; - ignore (plotter#drag#connect#data_received ~callback:(data_received)); + plotter#drag#dest_set dnd_targets ~actions:[`COPY]; + ignore (plotter#drag#connect#data_received ~callback:(data_received)); - (* Init curves *) - List.iter add_curve window.curves; + (* Init curves *) + List.iter add_curve window.curves; - plotter#add_accel_group accel_group; - plotter#show () + plotter#add_accel_group accel_group; + plotter#show ()