diff --git a/QGCExternalLibs.pri b/QGCExternalLibs.pri index 0a2edba922d0b9567084f3a9b11fbebc1ed10559..eaea69384b685a54713558d38c67f2757249af14 100644 --- a/QGCExternalLibs.pri +++ b/QGCExternalLibs.pri @@ -416,9 +416,10 @@ contains(DEFINES, DISABLE_3DMOUSE) { exists(/usr/local/lib/libxdrvlib.so) { message("Including support for 3DConnexion mice") - DEFINES += + DEFINES += \ QGC_MOUSE_ENABLED_LINUX \ - ParameterCheck # Hack: Has to be defined for magellan usage + ParameterCheck + # Hack: Has to be defined for magellan usage HEADERS += src/input/Mouse6dofInput.h SOURCES += src/input/Mouse6dofInput.cpp diff --git a/README.md b/README.md index b13d4a5f280015717271bd3b5eccfbcea2e0bfd6..5771904be0d5dcb1bb2578b527d14f701fe481df 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# QGroundControl +# QGroundControl ## Open Source Micro Air Vehicle Ground Control Station @@ -16,8 +16,8 @@ For generating documentation, refer to /doc/README. ## Notes -Please make sure to delete your build folder before re-building. Independent of which -build system you use (this is not related to Qt or your OS) the dependency checking and +Please make sure to delete your build folder before re-building. Independent of which +build system you use (this is not related to Qt or your OS) the dependency checking and cleaning is based on the current project revision. So if you change the project and don't remove the build folder before your next build, incremental building can leave you with stale object files. ## Additional functionality @@ -83,7 +83,7 @@ To build on Mac OSX (10.6 or later): 3. Run `make -j4` -# Build on Linux +# Build on Linux To build on Linux: @@ -91,6 +91,7 @@ To build on Linux: 1. Install base dependencies (QT + phonon/webkit, SDL) * For Ubuntu: `sudo apt-get install libqt4-dev libphonon-dev libphonon4 phonon-backend-gstreamer qtcreator libsdl1.2-dev build-essential libudev-dev` * For Fedora: `sudo yum install qt qt-creator qt-webkit-devel SDL-devel SDL-static systemd-devel` + * For Arch Linux: `pacman -Sy qtwebkit phonon-qt4` 2. **[OPTIONAL]** Install additional libraries * For text-to-speech (espeak) diff --git a/files/px4/general/calibration/calibration.qgw b/files/px4/general/calibration/calibration.qgw deleted file mode 100644 index 2a498a3ebfdd93c12a8a8e89738eb3cf75496281..0000000000000000000000000000000000000000 --- a/files/px4/general/calibration/calibration.qgw +++ /dev/null @@ -1,61 +0,0 @@ -[PX4%20Calibration%20Tool] -QGC_TOOL_WIDGET_ITEMS\1\TYPE=COMMANDBUTTON -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_DESCRIPTION=Reboot (only in standby) -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_BUTTONTEXT=REBOOT -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_COMMANDID=246 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAMS_VISIBLE=false -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM1=1 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM2=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM3=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM4=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM5=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM6=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM7=0 -QGC_TOOL_WIDGET_ITEMS\2\TYPE=COMMANDBUTTON -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_DESCRIPTION=Magnetometer calibration -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_BUTTONTEXT=MAG -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_COMMANDID=241 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAMS_VISIBLE=false -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM1=0 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM2=1 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM3=0 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM4=0 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM5=0 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM6=0 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM7=0 -QGC_TOOL_WIDGET_ITEMS\3\TYPE=COMMANDBUTTON -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_DESCRIPTION=Accelerometer calibration -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_BUTTONTEXT=ACCEL -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_COMMANDID=241 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAMS_VISIBLE=false -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM1=0 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM2=0 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM3=0 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM4=0 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM5=1 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM6=0 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM7=0 -QGC_TOOL_WIDGET_ITEMS\4\TYPE=COMMANDBUTTON -QGC_TOOL_WIDGET_ITEMS\4\QGC_COMMAND_BUTTON_DESCRIPTION=Gyroscope calibration -QGC_TOOL_WIDGET_ITEMS\4\QGC_COMMAND_BUTTON_BUTTONTEXT=GYRO -QGC_TOOL_WIDGET_ITEMS\4\QGC_COMMAND_BUTTON_COMMANDID=241 -QGC_TOOL_WIDGET_ITEMS\4\QGC_COMMAND_BUTTON_PARAMS_VISIBLE=false -QGC_TOOL_WIDGET_ITEMS\4\QGC_COMMAND_BUTTON_PARAM1=1 -QGC_TOOL_WIDGET_ITEMS\4\QGC_COMMAND_BUTTON_PARAM2=0 -QGC_TOOL_WIDGET_ITEMS\4\QGC_COMMAND_BUTTON_PARAM3=0 -QGC_TOOL_WIDGET_ITEMS\4\QGC_COMMAND_BUTTON_PARAM4=0 -QGC_TOOL_WIDGET_ITEMS\4\QGC_COMMAND_BUTTON_PARAM5=0 -QGC_TOOL_WIDGET_ITEMS\4\QGC_COMMAND_BUTTON_PARAM6=0 -QGC_TOOL_WIDGET_ITEMS\4\QGC_COMMAND_BUTTON_PARAM7=0 -QGC_TOOL_WIDGET_ITEMS\5\QGC_COMMAND_BUTTON_DESCRIPTION=RC Trim calibration -QGC_TOOL_WIDGET_ITEMS\5\QGC_COMMAND_BUTTON_BUTTONTEXT=TRIM -QGC_TOOL_WIDGET_ITEMS\5\QGC_COMMAND_BUTTON_COMMANDID=241 -QGC_TOOL_WIDGET_ITEMS\5\QGC_COMMAND_BUTTON_PARAMS_VISIBLE=false -QGC_TOOL_WIDGET_ITEMS\5\QGC_COMMAND_BUTTON_PARAM1=1 -QGC_TOOL_WIDGET_ITEMS\5\QGC_COMMAND_BUTTON_PARAM2=0 -QGC_TOOL_WIDGET_ITEMS\5\QGC_COMMAND_BUTTON_PARAM3=0 -QGC_TOOL_WIDGET_ITEMS\5\QGC_COMMAND_BUTTON_PARAM4=1 -QGC_TOOL_WIDGET_ITEMS\5\QGC_COMMAND_BUTTON_PARAM5=0 -QGC_TOOL_WIDGET_ITEMS\5\QGC_COMMAND_BUTTON_PARAM6=0 -QGC_TOOL_WIDGET_ITEMS\5\QGC_COMMAND_BUTTON_PARAM7=0 -QGC_TOOL_WIDGET_ITEMS\size=5 diff --git a/files/px4/general/calibration/description.txt b/files/px4/general/calibration/description.txt deleted file mode 100644 index c243d4ef8aa7e07b93b0f77256986e98eb98f299..0000000000000000000000000000000000000000 --- a/files/px4/general/calibration/description.txt +++ /dev/null @@ -1,19 +0,0 @@ - - -

Sensor Calibration

-


-

The PX4FMU sensors can be calibrated with the buttons on the right. Gyroscope (GYRO) and Accelerometer (ACCEL) calibrations have to be performed with a static, unmoved system. The magnetometer calibration needs to be performed while moving the device.

-


-

Magnetometer Calibration

-


-

Carefully follow the instructions. Click on MAG to start the calibration. Watch the communication console for further instructions (Available through Main Menu -> Tool Widgets -> Communication Console). Do not calibrate the vehicle in vincinity of metal, e.g. from a table or chair. Start the calibration, leave the system unmoved on the table. Wait for the double beep. Next move the system in a figure eight, roll and pitch it strongly, rotate around all axes and perform the figure eight also upside-down. The calibration is finished after the triple beep.

-


-

Accelerometer Calibration

-


-

Put the system on an absolutely level surface and press ACCEL, wait for the the triple beep. Do not move the system. If no flat surface is available, rather not calibrate the system.

-


-

Gyroscope Calibration

-


-

The orientation is not important for this calibration, but do not move the system until the triple beep or the matching text message in the console.

\ No newline at end of file diff --git a/files/px4/general/widgets/px4_fw_attitude_pid_params.qgw b/files/px4/general/widgets/px4_fw_attitude_pid_params.qgw deleted file mode 100644 index 6f3186e78f3544c718ee98a9d5f02d205f3fc85b..0000000000000000000000000000000000000000 --- a/files/px4/general/widgets/px4_fw_attitude_pid_params.qgw +++ /dev/null @@ -1,8 +0,0 @@ -[PX4%20Fixed%20Wing%20Attitude%20Control] -QGC_TOOL_WIDGET_ITEMS\1\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_DESCRIPTION=Roll Rate P Gain -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_PARAMID=FW_ROLLRATE_P -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_MAX=2 -QGC_TOOL_WIDGET_ITEMS\size=1 diff --git a/files/px4/general/widgets/px4_fw_position_pid_params.qgw b/files/px4/general/widgets/px4_fw_position_pid_params.qgw deleted file mode 100644 index e99f9890e9beb6984c4932c9a2be46cad04bb521..0000000000000000000000000000000000000000 --- a/files/px4/general/widgets/px4_fw_position_pid_params.qgw +++ /dev/null @@ -1,8 +0,0 @@ -[PX4%20Fixed%20Wing%20Position%20Control] -QGC_TOOL_WIDGET_ITEMS\1\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_DESCRIPTION=Heading P Gain -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_PARAMID=FW_HEADING_P -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_MAX=2 -QGC_TOOL_WIDGET_ITEMS\size=1 diff --git a/files/px4/general/widgets/px4_mc_attitude_pid_params.qgw b/files/px4/general/widgets/px4_mc_attitude_pid_params.qgw deleted file mode 100644 index 1931dfa3b912adac6f5185a7bfee217e3dee332a..0000000000000000000000000000000000000000 --- a/files/px4/general/widgets/px4_mc_attitude_pid_params.qgw +++ /dev/null @@ -1,72 +0,0 @@ -[PX4%20Multirotor%20Attitude%20Control] -QGC_TOOL_WIDGET_ITEMS\1\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_DESCRIPTION=Attitude P Gain -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_PARAMID=MC_ATT_P -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_MAX=1.5 -QGC_TOOL_WIDGET_ITEMS\2\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\2\QGC_PARAM_SLIDER_DESCRIPTION=Attitude I Gain -QGC_TOOL_WIDGET_ITEMS\2\QGC_PARAM_SLIDER_PARAMID=MC_ATT_I -QGC_TOOL_WIDGET_ITEMS\2\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\2\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\2\QGC_PARAM_SLIDER_MAX=1 -QGC_TOOL_WIDGET_ITEMS\3\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\3\QGC_PARAM_SLIDER_DESCRIPTION=Attitude D Gain -QGC_TOOL_WIDGET_ITEMS\3\QGC_PARAM_SLIDER_PARAMID=MC_ATT_D -QGC_TOOL_WIDGET_ITEMS\3\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\3\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\3\QGC_PARAM_SLIDER_MAX=1 -QGC_TOOL_WIDGET_ITEMS\4\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_DESCRIPTION=Attitude Anti-Windup -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_PARAMID=MC_ATT_AWU -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_MAX=1 -QGC_TOOL_WIDGET_ITEMS\5\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_DESCRIPTION=Attitude Output Limit -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_PARAMID=MC_ATT_LIM -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_MAX=3 -QGC_TOOL_WIDGET_ITEMS\6\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_DESCRIPTION=Heading / Yaw P Gain -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_PARAMID=MC_YAWPOS_P -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_MAX=1.2 -QGC_TOOL_WIDGET_ITEMS\7\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_DESCRIPTION=Heading / Yaw D Gain -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_PARAMID=MC_YAWPOS_D -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_MAX=1 -QGC_TOOL_WIDGET_ITEMS\8\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\8\QGC_PARAM_SLIDER_DESCRIPTION=Roll / Pitch Rate P Gain -QGC_TOOL_WIDGET_ITEMS\8\QGC_PARAM_SLIDER_PARAMID=MC_ATTRATE_P -QGC_TOOL_WIDGET_ITEMS\8\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\8\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\8\QGC_PARAM_SLIDER_MAX=1.5 -QGC_TOOL_WIDGET_ITEMS\9\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\9\QGC_PARAM_SLIDER_DESCRIPTION=Roll / Pitch Rate D Gain -QGC_TOOL_WIDGET_ITEMS\9\QGC_PARAM_SLIDER_PARAMID=MC_ATTRATE_D -QGC_TOOL_WIDGET_ITEMS\9\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\9\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\9\QGC_PARAM_SLIDER_MAX=0.3 -QGC_TOOL_WIDGET_ITEMS\10\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\10\QGC_PARAM_SLIDER_DESCRIPTION=Yaw Rate P Gain -QGC_TOOL_WIDGET_ITEMS\10\QGC_PARAM_SLIDER_PARAMID=MC_YAWRATE_P -QGC_TOOL_WIDGET_ITEMS\10\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\10\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\10\QGC_PARAM_SLIDER_MAX=1 -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_DISPLAY_INFO=false -QGC_TOOL_WIDGET_ITEMS\2\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\3\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\8\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\9\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\10\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\size=10 diff --git a/files/px4/general/widgets/px4_mc_position_pid_params.qgw b/files/px4/general/widgets/px4_mc_position_pid_params.qgw deleted file mode 100644 index 1931dfa3b912adac6f5185a7bfee217e3dee332a..0000000000000000000000000000000000000000 --- a/files/px4/general/widgets/px4_mc_position_pid_params.qgw +++ /dev/null @@ -1,72 +0,0 @@ -[PX4%20Multirotor%20Attitude%20Control] -QGC_TOOL_WIDGET_ITEMS\1\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_DESCRIPTION=Attitude P Gain -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_PARAMID=MC_ATT_P -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_MAX=1.5 -QGC_TOOL_WIDGET_ITEMS\2\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\2\QGC_PARAM_SLIDER_DESCRIPTION=Attitude I Gain -QGC_TOOL_WIDGET_ITEMS\2\QGC_PARAM_SLIDER_PARAMID=MC_ATT_I -QGC_TOOL_WIDGET_ITEMS\2\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\2\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\2\QGC_PARAM_SLIDER_MAX=1 -QGC_TOOL_WIDGET_ITEMS\3\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\3\QGC_PARAM_SLIDER_DESCRIPTION=Attitude D Gain -QGC_TOOL_WIDGET_ITEMS\3\QGC_PARAM_SLIDER_PARAMID=MC_ATT_D -QGC_TOOL_WIDGET_ITEMS\3\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\3\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\3\QGC_PARAM_SLIDER_MAX=1 -QGC_TOOL_WIDGET_ITEMS\4\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_DESCRIPTION=Attitude Anti-Windup -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_PARAMID=MC_ATT_AWU -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_MAX=1 -QGC_TOOL_WIDGET_ITEMS\5\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_DESCRIPTION=Attitude Output Limit -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_PARAMID=MC_ATT_LIM -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_MAX=3 -QGC_TOOL_WIDGET_ITEMS\6\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_DESCRIPTION=Heading / Yaw P Gain -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_PARAMID=MC_YAWPOS_P -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_MAX=1.2 -QGC_TOOL_WIDGET_ITEMS\7\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_DESCRIPTION=Heading / Yaw D Gain -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_PARAMID=MC_YAWPOS_D -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_MAX=1 -QGC_TOOL_WIDGET_ITEMS\8\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\8\QGC_PARAM_SLIDER_DESCRIPTION=Roll / Pitch Rate P Gain -QGC_TOOL_WIDGET_ITEMS\8\QGC_PARAM_SLIDER_PARAMID=MC_ATTRATE_P -QGC_TOOL_WIDGET_ITEMS\8\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\8\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\8\QGC_PARAM_SLIDER_MAX=1.5 -QGC_TOOL_WIDGET_ITEMS\9\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\9\QGC_PARAM_SLIDER_DESCRIPTION=Roll / Pitch Rate D Gain -QGC_TOOL_WIDGET_ITEMS\9\QGC_PARAM_SLIDER_PARAMID=MC_ATTRATE_D -QGC_TOOL_WIDGET_ITEMS\9\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\9\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\9\QGC_PARAM_SLIDER_MAX=0.3 -QGC_TOOL_WIDGET_ITEMS\10\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\10\QGC_PARAM_SLIDER_DESCRIPTION=Yaw Rate P Gain -QGC_TOOL_WIDGET_ITEMS\10\QGC_PARAM_SLIDER_PARAMID=MC_YAWRATE_P -QGC_TOOL_WIDGET_ITEMS\10\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\10\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\10\QGC_PARAM_SLIDER_MAX=1 -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_DISPLAY_INFO=false -QGC_TOOL_WIDGET_ITEMS\2\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\3\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\8\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\9\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\10\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\size=10 diff --git a/files/px4/widgets/px4_calibration.qgw b/files/px4/widgets/px4_calibration.qgw deleted file mode 100644 index bb895bc3711fc1e8be882953522613cc90dd79f3..0000000000000000000000000000000000000000 --- a/files/px4/widgets/px4_calibration.qgw +++ /dev/null @@ -1,73 +0,0 @@ -[PX4%20Calibration%20Tool] -QGC_TOOL_WIDGET_ITEMS\1\TYPE=COMMANDBUTTON -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_DESCRIPTION=Reboot (only in standby) -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_BUTTONTEXT=REBOOT -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_COMMANDID=246 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAMS_VISIBLE=false -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM1=1 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM2=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM3=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM4=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM5=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM6=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM7=0 -QGC_TOOL_WIDGET_ITEMS\2\TYPE=COMMANDBUTTON -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_DESCRIPTION=Magnetometer calibration -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_BUTTONTEXT=MAG -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_COMMANDID=241 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAMS_VISIBLE=false -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM1=0 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM2=1 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM3=0 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM4=0 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM5=0 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM6=0 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM7=0 -QGC_TOOL_WIDGET_ITEMS\3\TYPE=COMMANDBUTTON -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_DESCRIPTION=Accelerometer calibration -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_BUTTONTEXT=ACCEL -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_COMMANDID=241 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAMS_VISIBLE=false -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM1=0 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM2=0 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM3=0 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM4=0 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM5=1 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM6=0 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM7=0 -QGC_TOOL_WIDGET_ITEMS\4\TYPE=COMMANDBUTTON -QGC_TOOL_WIDGET_ITEMS\4\QGC_COMMAND_BUTTON_DESCRIPTION=Gyroscope calibration -QGC_TOOL_WIDGET_ITEMS\4\QGC_COMMAND_BUTTON_BUTTONTEXT=GYRO -QGC_TOOL_WIDGET_ITEMS\4\QGC_COMMAND_BUTTON_COMMANDID=241 -QGC_TOOL_WIDGET_ITEMS\4\QGC_COMMAND_BUTTON_PARAMS_VISIBLE=false -QGC_TOOL_WIDGET_ITEMS\4\QGC_COMMAND_BUTTON_PARAM1=1 -QGC_TOOL_WIDGET_ITEMS\4\QGC_COMMAND_BUTTON_PARAM2=0 -QGC_TOOL_WIDGET_ITEMS\4\QGC_COMMAND_BUTTON_PARAM3=0 -QGC_TOOL_WIDGET_ITEMS\4\QGC_COMMAND_BUTTON_PARAM4=0 -QGC_TOOL_WIDGET_ITEMS\4\QGC_COMMAND_BUTTON_PARAM5=0 -QGC_TOOL_WIDGET_ITEMS\4\QGC_COMMAND_BUTTON_PARAM6=0 -QGC_TOOL_WIDGET_ITEMS\4\QGC_COMMAND_BUTTON_PARAM7=0 -QGC_TOOL_WIDGET_ITEMS\5\QGC_COMMAND_BUTTON_DESCRIPTION=RC Trim calibration -QGC_TOOL_WIDGET_ITEMS\5\QGC_COMMAND_BUTTON_BUTTONTEXT=TRIM -QGC_TOOL_WIDGET_ITEMS\5\QGC_COMMAND_BUTTON_COMMANDID=241 -QGC_TOOL_WIDGET_ITEMS\5\QGC_COMMAND_BUTTON_PARAMS_VISIBLE=false -QGC_TOOL_WIDGET_ITEMS\5\QGC_COMMAND_BUTTON_PARAM1=1 -QGC_TOOL_WIDGET_ITEMS\5\QGC_COMMAND_BUTTON_PARAM2=0 -QGC_TOOL_WIDGET_ITEMS\5\QGC_COMMAND_BUTTON_PARAM3=0 -QGC_TOOL_WIDGET_ITEMS\5\QGC_COMMAND_BUTTON_PARAM4=1 -QGC_TOOL_WIDGET_ITEMS\5\QGC_COMMAND_BUTTON_PARAM5=0 -QGC_TOOL_WIDGET_ITEMS\5\QGC_COMMAND_BUTTON_PARAM6=0 -QGC_TOOL_WIDGET_ITEMS\5\QGC_COMMAND_BUTTON_PARAM7=0 -QGC_TOOL_WIDGET_ITEMS\6\TYPE=COMMANDBUTTON -QGC_TOOL_WIDGET_ITEMS\6\QGC_COMMAND_BUTTON_DESCRIPTION=Reboot to Bootloader -QGC_TOOL_WIDGET_ITEMS\6\QGC_COMMAND_BUTTON_BUTTONTEXT=BOOTLOADER -QGC_TOOL_WIDGET_ITEMS\6\QGC_COMMAND_BUTTON_COMMANDID=246 -QGC_TOOL_WIDGET_ITEMS\6\QGC_COMMAND_BUTTON_PARAMS_VISIBLE=false -QGC_TOOL_WIDGET_ITEMS\6\QGC_COMMAND_BUTTON_PARAM1=3 -QGC_TOOL_WIDGET_ITEMS\6\QGC_COMMAND_BUTTON_PARAM2=0 -QGC_TOOL_WIDGET_ITEMS\6\QGC_COMMAND_BUTTON_PARAM3=0 -QGC_TOOL_WIDGET_ITEMS\6\QGC_COMMAND_BUTTON_PARAM4=0 -QGC_TOOL_WIDGET_ITEMS\6\QGC_COMMAND_BUTTON_PARAM5=0 -QGC_TOOL_WIDGET_ITEMS\6\QGC_COMMAND_BUTTON_PARAM6=0 -QGC_TOOL_WIDGET_ITEMS\6\QGC_COMMAND_BUTTON_PARAM7=0 -QGC_TOOL_WIDGET_ITEMS\size=7 diff --git a/files/px4/widgets/px4_fw_attitude_pid_params.qgw b/files/px4/widgets/px4_fw_attitude_pid_params.qgw deleted file mode 100644 index 6f3186e78f3544c718ee98a9d5f02d205f3fc85b..0000000000000000000000000000000000000000 --- a/files/px4/widgets/px4_fw_attitude_pid_params.qgw +++ /dev/null @@ -1,8 +0,0 @@ -[PX4%20Fixed%20Wing%20Attitude%20Control] -QGC_TOOL_WIDGET_ITEMS\1\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_DESCRIPTION=Roll Rate P Gain -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_PARAMID=FW_ROLLRATE_P -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_MAX=2 -QGC_TOOL_WIDGET_ITEMS\size=1 diff --git a/files/px4/widgets/px4_fw_position_pid_params.qgw b/files/px4/widgets/px4_fw_position_pid_params.qgw deleted file mode 100644 index e99f9890e9beb6984c4932c9a2be46cad04bb521..0000000000000000000000000000000000000000 --- a/files/px4/widgets/px4_fw_position_pid_params.qgw +++ /dev/null @@ -1,8 +0,0 @@ -[PX4%20Fixed%20Wing%20Position%20Control] -QGC_TOOL_WIDGET_ITEMS\1\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_DESCRIPTION=Heading P Gain -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_PARAMID=FW_HEADING_P -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_MAX=2 -QGC_TOOL_WIDGET_ITEMS\size=1 diff --git a/files/px4/widgets/px4_mc_attitude_pid_params.qgw b/files/px4/widgets/px4_mc_attitude_pid_params.qgw deleted file mode 100644 index 0fd691b6bf7836c012464e8f5e53bd8213d9aafe..0000000000000000000000000000000000000000 --- a/files/px4/widgets/px4_mc_attitude_pid_params.qgw +++ /dev/null @@ -1,72 +0,0 @@ -[PX4%20Multirotor%20Attitude%20Control] -QGC_TOOL_WIDGET_ITEMS\1\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_DESCRIPTION=Attitude P Gain -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_PARAMID=MC_ATT_P -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_MAX=20 -QGC_TOOL_WIDGET_ITEMS\2\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\2\QGC_PARAM_SLIDER_DESCRIPTION=Attitude I Gain -QGC_TOOL_WIDGET_ITEMS\2\QGC_PARAM_SLIDER_PARAMID=MC_ATT_I -QGC_TOOL_WIDGET_ITEMS\2\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\2\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\2\QGC_PARAM_SLIDER_MAX=1 -QGC_TOOL_WIDGET_ITEMS\3\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\3\QGC_PARAM_SLIDER_DESCRIPTION=Attitude D Gain -QGC_TOOL_WIDGET_ITEMS\3\QGC_PARAM_SLIDER_PARAMID=MC_ATT_D -QGC_TOOL_WIDGET_ITEMS\3\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\3\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\3\QGC_PARAM_SLIDER_MAX=1 -QGC_TOOL_WIDGET_ITEMS\4\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_DESCRIPTION=Attitude Anti-Windup -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_PARAMID=MC_ATT_AWU -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_MAX=0.5 -QGC_TOOL_WIDGET_ITEMS\5\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_DESCRIPTION=Attitude Output Limit -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_PARAMID=MC_ATT_LIM -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_MAX=20 -QGC_TOOL_WIDGET_ITEMS\6\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_DESCRIPTION=Heading / Yaw P Gain -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_PARAMID=MC_YAWPOS_P -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_MAX=2 -QGC_TOOL_WIDGET_ITEMS\7\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_DESCRIPTION=Heading / Yaw D Gain -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_PARAMID=MC_YAWPOS_D -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_MAX=0.5 -QGC_TOOL_WIDGET_ITEMS\8\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\8\QGC_PARAM_SLIDER_DESCRIPTION=Roll / Pitch Rate P Gain -QGC_TOOL_WIDGET_ITEMS\8\QGC_PARAM_SLIDER_PARAMID=MC_ATTRATE_P -QGC_TOOL_WIDGET_ITEMS\8\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\8\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\8\QGC_PARAM_SLIDER_MAX=1 -QGC_TOOL_WIDGET_ITEMS\9\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\9\QGC_PARAM_SLIDER_DESCRIPTION=Roll / Pitch Rate D Gain -QGC_TOOL_WIDGET_ITEMS\9\QGC_PARAM_SLIDER_PARAMID=MC_ATTRATE_D -QGC_TOOL_WIDGET_ITEMS\9\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\9\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\9\QGC_PARAM_SLIDER_MAX=1 -QGC_TOOL_WIDGET_ITEMS\10\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\10\QGC_PARAM_SLIDER_DESCRIPTION=Yaw Rate P Gain -QGC_TOOL_WIDGET_ITEMS\10\QGC_PARAM_SLIDER_PARAMID=MC_YAWRATE_P -QGC_TOOL_WIDGET_ITEMS\10\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\10\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\10\QGC_PARAM_SLIDER_MAX=1 -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_DISPLAY_INFO=false -QGC_TOOL_WIDGET_ITEMS\2\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\3\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\8\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\9\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\10\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\size=10 diff --git a/files/px4/widgets/px4_mc_position_pid_params.qgw b/files/px4/widgets/px4_mc_position_pid_params.qgw deleted file mode 100644 index 1931dfa3b912adac6f5185a7bfee217e3dee332a..0000000000000000000000000000000000000000 --- a/files/px4/widgets/px4_mc_position_pid_params.qgw +++ /dev/null @@ -1,72 +0,0 @@ -[PX4%20Multirotor%20Attitude%20Control] -QGC_TOOL_WIDGET_ITEMS\1\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_DESCRIPTION=Attitude P Gain -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_PARAMID=MC_ATT_P -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_MAX=1.5 -QGC_TOOL_WIDGET_ITEMS\2\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\2\QGC_PARAM_SLIDER_DESCRIPTION=Attitude I Gain -QGC_TOOL_WIDGET_ITEMS\2\QGC_PARAM_SLIDER_PARAMID=MC_ATT_I -QGC_TOOL_WIDGET_ITEMS\2\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\2\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\2\QGC_PARAM_SLIDER_MAX=1 -QGC_TOOL_WIDGET_ITEMS\3\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\3\QGC_PARAM_SLIDER_DESCRIPTION=Attitude D Gain -QGC_TOOL_WIDGET_ITEMS\3\QGC_PARAM_SLIDER_PARAMID=MC_ATT_D -QGC_TOOL_WIDGET_ITEMS\3\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\3\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\3\QGC_PARAM_SLIDER_MAX=1 -QGC_TOOL_WIDGET_ITEMS\4\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_DESCRIPTION=Attitude Anti-Windup -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_PARAMID=MC_ATT_AWU -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_MAX=1 -QGC_TOOL_WIDGET_ITEMS\5\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_DESCRIPTION=Attitude Output Limit -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_PARAMID=MC_ATT_LIM -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_MAX=3 -QGC_TOOL_WIDGET_ITEMS\6\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_DESCRIPTION=Heading / Yaw P Gain -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_PARAMID=MC_YAWPOS_P -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_MAX=1.2 -QGC_TOOL_WIDGET_ITEMS\7\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_DESCRIPTION=Heading / Yaw D Gain -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_PARAMID=MC_YAWPOS_D -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_MAX=1 -QGC_TOOL_WIDGET_ITEMS\8\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\8\QGC_PARAM_SLIDER_DESCRIPTION=Roll / Pitch Rate P Gain -QGC_TOOL_WIDGET_ITEMS\8\QGC_PARAM_SLIDER_PARAMID=MC_ATTRATE_P -QGC_TOOL_WIDGET_ITEMS\8\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\8\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\8\QGC_PARAM_SLIDER_MAX=1.5 -QGC_TOOL_WIDGET_ITEMS\9\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\9\QGC_PARAM_SLIDER_DESCRIPTION=Roll / Pitch Rate D Gain -QGC_TOOL_WIDGET_ITEMS\9\QGC_PARAM_SLIDER_PARAMID=MC_ATTRATE_D -QGC_TOOL_WIDGET_ITEMS\9\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\9\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\9\QGC_PARAM_SLIDER_MAX=0.3 -QGC_TOOL_WIDGET_ITEMS\10\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\10\QGC_PARAM_SLIDER_DESCRIPTION=Yaw Rate P Gain -QGC_TOOL_WIDGET_ITEMS\10\QGC_PARAM_SLIDER_PARAMID=MC_YAWRATE_P -QGC_TOOL_WIDGET_ITEMS\10\QGC_PARAM_SLIDER_COMPONENTID=50 -QGC_TOOL_WIDGET_ITEMS\10\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\10\QGC_PARAM_SLIDER_MAX=1 -QGC_TOOL_WIDGET_ITEMS\1\QGC_PARAM_SLIDER_DISPLAY_INFO=false -QGC_TOOL_WIDGET_ITEMS\2\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\3\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\8\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\9\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\10\QGC_PARAM_SLIDER_DISPLAY_INFO=true -QGC_TOOL_WIDGET_ITEMS\size=10 diff --git a/libs/opmapcontrol/src/core/urlfactory.cpp b/libs/opmapcontrol/src/core/urlfactory.cpp index d6d0dc473fbc614b5ec4abc6bd978bed94fb5008..0d64b9448570ae44623176bf90fae7e549d39864 100644 --- a/libs/opmapcontrol/src/core/urlfactory.cpp +++ b/libs/opmapcontrol/src/core/urlfactory.cpp @@ -37,9 +37,9 @@ namespace core { /// /// timeout for map connections /// + QNetworkProxyFactory::setUseSystemConfiguration(true); - Proxy.setType(QNetworkProxy::NoProxy); - + /// /// Gets or sets the value of the User-agent HTTP header. /// @@ -90,6 +90,12 @@ namespace core { void UrlFactory::TryCorrectGoogleVersions() { + static bool versionRetrieved = false; + + if (versionRetrieved) + { + return; + } QMutexLocker locker(&mutex); if(CorrectGoogleVersions && !IsCorrectGoogleVersions()) { @@ -106,8 +112,8 @@ namespace core { #ifdef DEBUG_URLFACTORY qDebug()<<"Correct GoogleVersion"; #endif //DEBUG_URLFACTORY - setIsCorrectGoogleVersions(true); - QString url = "http://maps.google.com"; + //setIsCorrectGoogleVersions(true); + QString url = "https://maps.google.com"; qheader.setUrl(QUrl(url)); qheader.setRawHeader("User-Agent",UserAgent); @@ -125,18 +131,19 @@ namespace core { return; } QString html=QString(reply->readAll()); - QRegExp reg("\"*http://mt0.google.com/vt/lyrs=m@(\\d*)",Qt::CaseInsensitive); + QRegExp reg("\"*https://mts0.google.com/vt/lyrs=m@(\\d*)",Qt::CaseInsensitive); if(reg.indexIn(html)!=-1) { QStringList gc=reg.capturedTexts(); VersionGoogleMap = QString("m@%1").arg(gc[1]); VersionGoogleMapChina = VersionGoogleMap; + #ifdef DEBUG_URLFACTORY qDebug()<<"TryCorrectGoogleVersions, VersionGoogleMap: "<deleteLater(); - + } } @@ -182,48 +188,50 @@ namespace core { { case MapType::GoogleMap: { - QString server = "mt"; + QString server = "mts"; QString request = "vt"; QString sec1 = ""; // after &x=... QString sec2 = ""; // after &zoom=... GetSecGoogleWords(pos, sec1, sec2); TryCorrectGoogleVersions(); - - return QString("http://%1%2.google.com/%3/lyrs=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(GetServerNum(pos, 4)).arg(request).arg(VersionGoogleMap).arg(language).arg(pos.X()).arg(sec1).arg(pos.Y()).arg(zoom).arg(sec2); + + return QString("https://%1%2.google.com/%3/lyrs=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(GetServerNum(pos, 4)).arg(request).arg(VersionGoogleMap).arg(language).arg(pos.X()).arg(sec1).arg(pos.Y()).arg(zoom).arg(sec2); } break; case MapType::GoogleSatellite: { - QString server = "khm"; + QString server = "khms"; QString request = "kh"; QString sec1 = ""; // after &x=... QString sec2 = ""; // after &zoom=... GetSecGoogleWords(pos, sec1, sec2); TryCorrectGoogleVersions(); - return QString("http://%1%2.google.com/%3/v=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(GetServerNum(pos, 4)).arg(request).arg(VersionGoogleSatellite).arg(language).arg(pos.X()).arg(sec1).arg(pos.Y()).arg(zoom).arg(sec2); + + return QString("https://%1%2.google.com/%3/v=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(GetServerNum(pos, 4)).arg(request).arg(VersionGoogleSatellite).arg(language).arg(pos.X()).arg(sec1).arg(pos.Y()).arg(zoom).arg(sec2); } break; case MapType::GoogleLabels: { - QString server = "mt"; + QString server = "mts"; QString request = "vt"; QString sec1 = ""; // after &x=... QString sec2 = ""; // after &zoom=... GetSecGoogleWords(pos, sec1, sec2); TryCorrectGoogleVersions(); - - return QString("http://%1%2.google.com/%3/lyrs=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(GetServerNum(pos, 4)).arg(request).arg(VersionGoogleLabels).arg(language).arg(pos.X()).arg(sec1).arg(pos.Y()).arg(zoom).arg(sec2); + + return QString("https://%1%2.google.com/%3/lyrs=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(GetServerNum(pos, 4)).arg(request).arg(VersionGoogleLabels).arg(language).arg(pos.X()).arg(sec1).arg(pos.Y()).arg(zoom).arg(sec2); } break; case MapType::GoogleTerrain: { - QString server = "mt"; + QString server = "mts"; QString request = "vt"; QString sec1 = ""; // after &x=... QString sec2 = ""; // after &zoom=... GetSecGoogleWords(pos, sec1, sec2); TryCorrectGoogleVersions(); - return QString("http://%1%2.google.com/%3/v=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(GetServerNum(pos, 4)).arg(request).arg(VersionGoogleTerrain).arg(language).arg(pos.X()).arg(sec1).arg(pos.Y()).arg(zoom).arg(sec2); + + return QString("https://%1%2.google.com/%3/v=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(GetServerNum(pos, 4)).arg(request).arg(VersionGoogleTerrain).arg(language).arg(pos.X()).arg(sec1).arg(pos.Y()).arg(zoom).arg(sec2); } break; case MapType::GoogleMapChina: @@ -235,7 +243,7 @@ namespace core { GetSecGoogleWords(pos, sec1, sec2); TryCorrectGoogleVersions(); // http://mt0.google.cn/vt/v=w2.101&hl=zh-CN&gl=cn&x=12&y=6&z=4&s=Ga - + return QString("http://%1%2.google.cn/%3/lyrs=%4&hl=%5&gl=cn&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(GetServerNum(pos, 4)).arg(request).arg(VersionGoogleMapChina).arg("zh-CN").arg(pos.X()).arg(sec1).arg(pos.Y()).arg(zoom).arg(sec2); } break; @@ -273,6 +281,7 @@ namespace core { QString sec2 = ""; // after &zoom=... GetSecGoogleWords(pos, sec1, sec2); TryCorrectGoogleVersions(); + // http://mt0.google.cn/vt/v=w2p.110&hl=zh-CN&gl=cn&x=12&y=6&z=4&s=Ga return QString("http://%1%2.google.com/%3/lyrs=%4&hl=%5&gl=cn&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(GetServerNum(pos, 4)).arg(request).arg(VersionGoogleTerrainChina).arg("zh-CN").arg(pos.X()).arg(sec1).arg(pos.Y()).arg(zoom).arg(sec2); @@ -285,10 +294,10 @@ namespace core { QString sec1 = ""; // after &x=... QString sec2 = ""; // after &zoom=... GetSecGoogleWords(pos, sec1, sec2); - + //http://mt3.gmaptiles.co.kr/mt/v=kr1.11&hl=lt&x=109&y=49&z=7&s= - QString ret = QString("http://%1%2.gmaptiles.co.kr/%3/v=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(GetServerNum(pos, 4)).arg(request).arg(VersionGoogleMapKorea).arg(language).arg(pos.X()).arg(sec1).arg(pos.Y()).arg(zoom).arg(sec2); + QString ret = QString("https://%1%2.gmaptiles.co.kr/%3/v=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(GetServerNum(pos, 4)).arg(request).arg(VersionGoogleMapKorea).arg(language).arg(pos.X()).arg(sec1).arg(pos.Y()).arg(zoom).arg(sec2); return ret; } break; @@ -299,7 +308,7 @@ namespace core { QString sec1 = ""; // after &x=... QString sec2 = ""; // after &zoom=... GetSecGoogleWords(pos, sec1, sec2); - + // http://khm1.google.co.kr/kh/v=54&x=109&y=49&z=7&s= return QString("http://%1%2.google.co.kr/%3/v=%4&x=%5%6&y=%7&z=%8&s=%9").arg(server).arg(GetServerNum(pos, 4)).arg(request).arg(VersionGoogleSatelliteKorea).arg(pos.X()).arg(sec1).arg(pos.Y()).arg(zoom).arg(sec2); @@ -315,7 +324,7 @@ namespace core { // http://mt1.gmaptiles.co.kr/mt/v=kr1t.11&hl=lt&x=109&y=50&z=7&s=G - return QString("http://%1%2.gmaptiles.co.kr/%3/v=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(GetServerNum(pos, 4)).arg(request).arg(VersionGoogleLabelsKorea).arg(language).arg(pos.X()).arg(sec1).arg(pos.Y()).arg(zoom).arg(sec2); + return QString("https://%1%2.gmaptiles.co.kr/%3/v=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(GetServerNum(pos, 4)).arg(request).arg(VersionGoogleLabelsKorea).arg(language).arg(pos.X()).arg(sec1).arg(pos.Y()).arg(zoom).arg(sec2); } break; case MapType::YahooMap: diff --git a/libs/opmapcontrol/src/internals/core.cpp b/libs/opmapcontrol/src/internals/core.cpp index a059583c71f5a21e1971da0119fff848fe6526a0..211603bc450e1e085c0d1b087afe51663be3c9ae 100644 --- a/libs/opmapcontrol/src/internals/core.cpp +++ b/libs/opmapcontrol/src/internals/core.cpp @@ -352,13 +352,25 @@ namespace internals { } break; + case MapType::BingHybrid: + case MapType::BingMap: + case MapType::BingSatellite: + { + if(Projection()->Type()!="MercatorProjection") + { + SetProjection(new MercatorProjection()); + } + maxzoom=21; + } + break; + default: { if(Projection()->Type()!="MercatorProjection") { SetProjection(new MercatorProjection()); - maxzoom=21; } + maxzoom=21; } break; } diff --git a/libs/opmapcontrol/src/mapwidget/waypointitem.cpp b/libs/opmapcontrol/src/mapwidget/waypointitem.cpp index 0118c2776f2ca33ff8147908e71fab6c7e8861f6..17ebdc8e8ee9fd840d7cab87ec7deee9510afe90 100644 --- a/libs/opmapcontrol/src/mapwidget/waypointitem.cpp +++ b/libs/opmapcontrol/src/mapwidget/waypointitem.cpp @@ -308,7 +308,7 @@ namespace mapcontrol } void WayPointItem::RefreshToolTip() { - QString coord_str = QString::number(coord.Lat(), 'f', 6) + " " + QString::number(coord.Lng(), 'f', 6); + QString coord_str = QString::number(coord.Lat(), 'f', 7) + " " + QString::number(coord.Lng(), 'f', 7); setToolTip(QString("WayPoint Number: %1\nDescription: %2\nCoordinate: %4\nAltitude: %5 m (MSL)\nHeading: %6 deg").arg(QString::number(WayPointItem::number)).arg(description).arg(coord_str).arg(QString::number(altitude)).arg(QString::number(heading))); } diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index 9e9072ab48533e3f0ae56427fd30ac93c6237830..070402c50ae6d83058d53535435713854ea3ba4e 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -187,7 +187,6 @@ DebugBuild { src/qgcunittest/MockUAS.h \ src/qgcunittest/MockQGCUASParamManager.h \ src/qgcunittest/MultiSignalSpy.h \ - src/qgcunittest/TCPLinkTest.h \ src/qgcunittest/FlightModeConfigTest.h SOURCES += \ @@ -196,7 +195,6 @@ DebugBuild { src/qgcunittest/MockUAS.cc \ src/qgcunittest/MockQGCUASParamManager.cc \ src/qgcunittest/MultiSignalSpy.cc \ - src/qgcunittest/TCPLinkTest.cc \ src/qgcunittest/FlightModeConfigTest.cc } @@ -567,7 +565,9 @@ HEADERS += \ src/uas/UASManagerInterface.h \ src/uas/QGCUASParamManagerInterface.h \ src/uas/QGCUASFileManager.h \ - src/ui/QGCUASFileView.h + src/ui/QGCUASFileView.h \ + src/uas/QGCUASWorker.h \ + src/CmdLineOptParser.h SOURCES += \ src/main.cc \ @@ -753,4 +753,6 @@ SOURCES += \ src/ui/designer/QGCXYPlot.cc \ src/ui/menuactionhelper.cpp \ src/uas/QGCUASFileManager.cc \ - src/ui/QGCUASFileView.cc + src/ui/QGCUASFileView.cc \ + src/uas/QGCUASWorker.cc \ + src/CmdLineOptParser.cc diff --git a/qupgrade b/qupgrade index 5eb9a98393368a16ecf17199d0f23d68973939ad..e223e5eb8ba0cb0bf6b732b0538ffba8ae2faac6 160000 --- a/qupgrade +++ b/qupgrade @@ -1 +1 @@ -Subproject commit 5eb9a98393368a16ecf17199d0f23d68973939ad +Subproject commit e223e5eb8ba0cb0bf6b732b0538ffba8ae2faac6 diff --git a/src/CmdLineOptParser.cc b/src/CmdLineOptParser.cc new file mode 100644 index 0000000000000000000000000000000000000000..5e237a766b7d6bc0a2c465d4872c808796676547 --- /dev/null +++ b/src/CmdLineOptParser.cc @@ -0,0 +1,59 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009 - 2014 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL 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 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see . + + ======================================================================*/ + +/// @file +/// @brief Command line option parser +/// +/// @author Don Gagne + +#include "CmdLineOptParser.h" + +#include + +/// @brief Implements a simple command line parser which sets booleans to true if the option is found. +void ParseCmdLineOptions(int& argc, ///< count of arguments in argv + char* argv[], ///< command line arguments + CmdLineOpt_t* prgOpts, ///< command line options + size_t cOpts, ///< count of command line options + bool removeParsedOptions) ///< true: remove parsed option from argc/argv +{ + // Start with all options off + for (size_t iOption=0; iOption + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL 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 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see . + + ======================================================================*/ + +/// @file +/// @brief Command line option parser +/// +/// @author Don Gagne + +#ifndef CMDLINEOPTPARSER_H +#define CMDLINEOPTPARSER_H + +#include + +/// @brief Structure used to pass command line options to the ParseCmdLineOptions function. +typedef struct { + const char* optionStr; ///< command line option, for example "--foo" + bool* flag; ///< if option is found this variable will be set to true +} CmdLineOpt_t; + +void ParseCmdLineOptions(int& argc, + char* argv[], + CmdLineOpt_t* prgOpts, + size_t cOpts, + bool removeParsedOptions); + +#endif diff --git a/src/GAudioOutput.cc b/src/GAudioOutput.cc index 739c7acf3078132d3a9b7fccdcbf2639c97c5d45..ff88dfe9434305a5741e2ffbb6c25a09d79e1e16 100644 --- a/src/GAudioOutput.cc +++ b/src/GAudioOutput.cc @@ -187,8 +187,8 @@ bool GAudioOutput::say(QString text, int severity) if (!emergency) { - // Speech synthesis is only supported with MSVC compiler -#if defined _MSC_VER && defined QGC_SPEECH_ENABLED +#if defined QGC_SPEECH_ENABLED +#if defined _MSC_VER /*SpeechSynthesizer synth = new SpeechSynthesizer(); synth.SelectVoice("Microsoft Anna"); synth.SpeakText(text.toStdString().c_str()); @@ -209,14 +209,14 @@ bool GAudioOutput::say(QString text, int severity) pVoice = NULL; } }*/ -#endif +#endif // _MSC_VER -#if defined Q_OS_LINUX && defined QGC_SPEECH_ENABLED +#if defined Q_OS_LINUX unsigned int espeak_size = strlen(text.toStdString().c_str()); espeak_Synth(text.toStdString().c_str(), espeak_size, 0, POS_CHARACTER, 0, espeakCHARS_AUTO, NULL, NULL); -#endif +#endif // Q_OS_LINUX -#if defined Q_OS_MAC && defined QGC_SPEECH_ENABLED +#if defined Q_OS_MAC // Slashes necessary to have the right start to the sentence // copying data prevents SpeakString from reading additional chars text = "\\" + text; @@ -225,7 +225,11 @@ bool GAudioOutput::say(QString text, int severity) memcpy(str2, text.toAscii().data(), str.length()); SpeakString(str2); res = true; -#endif +#endif // Q_OS_MAC + +#else + Q_UNUSED(text); +#endif // QGC_SPEECH_ENABLED } return res; diff --git a/src/QGCCore.cc b/src/QGCCore.cc index ac09084c6744891c2f1622e168e4f81bad3960ab..375f3c0c8ab76c07faee48255facf98301030221 100644 --- a/src/QGCCore.cc +++ b/src/QGCCore.cc @@ -47,6 +47,7 @@ This file is part of the QGROUNDCONTROL project #include "MainWindow.h" #include "QGCWelcomeMainWindow.h" #include "GAudioOutput.h" +#include "CmdLineOptParser.h" #ifdef QGC_RTLAB_ENABLED #include "OpalLink.h" @@ -82,12 +83,25 @@ QGCCore::QGCCore(bool firstStart, int &argc, char* argv[]) : QApplication(argc, // Set settings format QSettings::setDefaultFormat(QSettings::IniFormat); - - // Check application settings - // clear them if they mismatch - // QGC then falls back to default + + // Parse command line options + + bool fClearSettingsOptions = false; // Clear stored settings + + CmdLineOpt_t rgCmdLineOptions[] = { + { "--clear-settings", &fClearSettingsOptions }, + // Add additional command line option flags here + }; + + ParseCmdLineOptions(argc, argv, rgCmdLineOptions, sizeof(rgCmdLineOptions)/sizeof(rgCmdLineOptions[0]), false); + QSettings settings; + if (fClearSettingsOptions) { + // User requested settings to be cleared on command line + settings.clear(); + } + // Show user an upgrade message if QGC got upgraded (see code below, after splash screen) bool upgraded = false; enum MainWindow::CUSTOM_MODE mode = MainWindow::CUSTOM_MODE_NONE; @@ -98,7 +112,7 @@ QGCCore::QGCCore(bool firstStart, int &argc, char* argv[]) : QApplication(argc, if (qgcVersion != QGC_APPLICATION_VERSION) { lastApplicationVersion = qgcVersion; - settings.clear(); + settings.clear(); // Clear settings from different version // Write current application version settings.setValue("QGC_APPLICATION_VERSION", QGC_APPLICATION_VERSION); upgraded = true; diff --git a/src/Waypoint.cc b/src/Waypoint.cc index 40447c1545cc730d18e8a71e72d09158ba82a296..dc9d3a6c9374cc6f795baeb3524f4a7249571a89 100644 --- a/src/Waypoint.cc +++ b/src/Waypoint.cc @@ -216,7 +216,8 @@ void Waypoint::setCurrent(bool current) if (this->current != current) { this->current = current; - emit changed(this); + // The current waypoint index is handled by the list + // and not part of the individual waypoint update state } } diff --git a/src/Waypoint.h b/src/Waypoint.h index 6f5477c0a2d4b88dd8213d560e4841835d69c7c5..35999a264872665659cdb099048c28ff0fc205ed 100644 --- a/src/Waypoint.h +++ b/src/Waypoint.h @@ -123,6 +123,7 @@ public: const QString& getDescription() const { return description; } + /** @brief Returns true if x, y, z contain reasonable navigation data */ bool isNavigationType(); @@ -185,6 +186,9 @@ public slots: bool isReached() { return (reachedTime > 0); } /** @brief Get the time this waypoint was reached */ quint64 getReachedTime() { return reachedTime; } + void setChanged() { + emit changed(this); + } signals: /** @brief Announces a change to the waypoint data */ diff --git a/src/comm/LinkInterface.h b/src/comm/LinkInterface.h index 833a804a9c60f51d5df0060cd06c2eb5da467f21..3335677522895aa2cf1a03972cf8903a09738531 100644 --- a/src/comm/LinkInterface.h +++ b/src/comm/LinkInterface.h @@ -36,6 +36,7 @@ along with PIXHAWK. If not, see . #include #include #include +#include /** * The link interface defines the interface for all links used to communicate @@ -62,6 +63,7 @@ public: outDataWriteTimes[i] = 0; } + qRegisterMetaType("LinkInterface*"); } virtual ~LinkInterface() { diff --git a/src/comm/LinkManager.cc b/src/comm/LinkManager.cc index de948775727412d940074df04e8812e0e990dd23..eecf5a5825bf4d468dffd24a081318c084e59647 100644 --- a/src/comm/LinkManager.cc +++ b/src/comm/LinkManager.cc @@ -63,20 +63,26 @@ LinkManager::LinkManager() LinkManager::~LinkManager() { disconnectAll(); + dataMutex.lock(); foreach (LinkInterface* link, links) { if(link) link->deleteLater(); } + dataMutex.unlock(); } void LinkManager::add(LinkInterface* link) { + dataMutex.lock(); if (!links.contains(link)) { if(!link) return; connect(link, SIGNAL(destroyed(QObject*)), this, SLOT(removeObj(QObject*))); links.append(link); + dataMutex.unlock(); emit newLink(link); + } else { + dataMutex.unlock(); } } @@ -86,6 +92,7 @@ void LinkManager::addProtocol(LinkInterface* link, ProtocolInterface* protocol) // the protocol will receive new bytes from the link if (!link || !protocol) return; + dataMutex.lock(); QList linkList = protocolLinks.values(protocol); // If protocol has not been added before (list length == 0) @@ -98,31 +105,42 @@ void LinkManager::addProtocol(LinkInterface* link, ProtocolInterface* protocol) connect(link, SIGNAL(connected(bool)), protocol, SLOT(linkStatusChanged(bool))); // Store the connection information in the protocol links map protocolLinks.insertMulti(protocol, link); + dataMutex.unlock(); // Make sure the protocol clears its metadata for this link. protocol->resetMetadataForLink(link); + } else { + dataMutex.unlock(); } //qDebug() << __FILE__ << __LINE__ << "ADDED LINK TO PROTOCOL" << link->getName() << protocol->getName() << "NEW SIZE OF LINK LIST:" << protocolLinks.size(); } QList LinkManager::getLinksForProtocol(ProtocolInterface* protocol) { - return protocolLinks.values(protocol); + dataMutex.lock(); + QList links = protocolLinks.values(protocol); + dataMutex.unlock(); + return links; } ProtocolInterface* LinkManager::getProtocolForLink(LinkInterface* link) { - return protocolLinks.key(link); + dataMutex.lock(); + ProtocolInterface* interface = protocolLinks.key(link); + dataMutex.unlock(); + return interface; } bool LinkManager::connectAll() { bool allConnected = true; + dataMutex.lock(); foreach (LinkInterface* link, links) { if(!link) {} else if(!link->connect()) allConnected = false; } + dataMutex.unlock(); return allConnected; } @@ -131,12 +149,14 @@ bool LinkManager::disconnectAll() { bool allDisconnected = true; + dataMutex.lock(); foreach (LinkInterface* link, links) { //static int i=0; if(!link) {} else if(!link->disconnect()) allDisconnected = false; } + dataMutex.unlock(); return allDisconnected; } @@ -166,6 +186,7 @@ bool LinkManager::removeLink(LinkInterface* link) { if(link) { + dataMutex.lock(); for (int i=0; i < QList(links).size(); i++) { if(link==links.at(i)) @@ -179,6 +200,7 @@ bool LinkManager::removeLink(LinkInterface* link) { protocolLinks.remove(proto, link); } + dataMutex.unlock(); // Emit removal of link emit linkRemoved(link); @@ -196,11 +218,17 @@ bool LinkManager::removeLink(LinkInterface* link) */ LinkInterface* LinkManager::getLinkForId(int id) { + dataMutex.lock(); + LinkInterface* linkret = NULL; foreach (LinkInterface* link, links) { - if (link->getId() == id) return link; + if (link->getId() == id) + { + linkret = link; + } } - return NULL; + dataMutex.unlock(); + return linkret; } /** @@ -208,11 +236,15 @@ LinkInterface* LinkManager::getLinkForId(int id) */ const QList LinkManager::getLinks() { - return QList(links); + dataMutex.lock(); + QList ret(links); + dataMutex.unlock(); + return ret; } const QList LinkManager::getSerialLinks() { + dataMutex.lock(); QList s; foreach (LinkInterface* i, links) @@ -222,6 +254,7 @@ const QList LinkManager::getSerialLinks() if (link) s.append(link); } + dataMutex.unlock(); return s; } diff --git a/src/comm/LinkManager.h b/src/comm/LinkManager.h index f949ba909a6247eecb83340b63fbd3e809af23b7..6c38b6492c0eb5a9eac11d184dee2d81569a1c03 100644 --- a/src/comm/LinkManager.h +++ b/src/comm/LinkManager.h @@ -35,6 +35,7 @@ This file is part of the PIXHAWK project #include #include #include +#include #include #include #include @@ -91,6 +92,7 @@ protected: LinkManager(); QList links; QMultiMap protocolLinks; + QMutex dataMutex; private: static LinkManager* _instance; diff --git a/src/comm/MAVLinkProtocol.cc b/src/comm/MAVLinkProtocol.cc index 2dc631c0bdcf8955618e161c46a7b3e88af803f2..450f45c1c4c7ba7cbb2523c354457d1554c44d83 100644 --- a/src/comm/MAVLinkProtocol.cc +++ b/src/comm/MAVLinkProtocol.cc @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include "MAVLinkProtocol.h" #include "UASInterface.h" @@ -35,15 +37,16 @@ #include #endif +Q_DECLARE_METATYPE(mavlink_message_t) /** * The default constructor will create a new MAVLink object sending heartbeats at * the MAVLINK_HEARTBEAT_DEFAULT_RATE to all connected links. */ MAVLinkProtocol::MAVLinkProtocol() : - heartbeatTimer(new QTimer(this)), + heartbeatTimer(NULL), heartbeatRate(MAVLINK_HEARTBEAT_DEFAULT_RATE), - m_heartbeatsEnabled(false), + m_heartbeatsEnabled(true), m_multiplexingEnabled(false), m_authEnabled(false), m_loggingEnabled(false), @@ -55,14 +58,14 @@ MAVLinkProtocol::MAVLinkProtocol() : m_actionGuardEnabled(false), m_actionRetransmissionTimeout(100), versionMismatchIgnore(false), - systemId(QGC::defaultSystemId) + systemId(QGC::defaultSystemId), + _should_exit(false) { + qRegisterMetaType("mavlink_message_t"); + m_authKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; loadSettings(); - //start(QThread::LowPriority); - // Start heartbeat timer, emitting a heartbeat at the configured rate - connect(heartbeatTimer, SIGNAL(timeout()), this, SLOT(sendHeartbeat())); - heartbeatTimer->start(1000/heartbeatRate); + moveToThread(this); // All the *Counter variables are not initialized here, as they should be initialized // on a per-link basis before those links are used. @see resetMetadataForLink(). @@ -76,6 +79,8 @@ MAVLinkProtocol::MAVLinkProtocol() : } } + start(QThread::HighPriority); + emit versionCheckChanged(m_enable_version_check); } @@ -161,6 +166,35 @@ MAVLinkProtocol::~MAVLinkProtocol() delete m_logfile; m_logfile = NULL; } + + // Tell the thread to exit + _should_exit = true; + // Wait for it to exit + wait(); +} + +/** + * @brief Runs the thread + * + **/ +void MAVLinkProtocol::run() +{ + heartbeatTimer = new QTimer(); + heartbeatTimer->moveToThread(this); + // Start heartbeat timer, emitting a heartbeat at the configured rate + connect(heartbeatTimer, SIGNAL(timeout()), this, SLOT(sendHeartbeat())); + heartbeatTimer->start(1000/heartbeatRate); + + while(!_should_exit) { + + if (isFinished()) { + qDebug() << "MAVLINK WORKER DONE!"; + return; + } + + QCoreApplication::processEvents(); + QGC::SLEEP::msleep(2); + } } QString MAVLinkProtocol::getLogfileName() @@ -358,19 +392,26 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b) // Log data if (m_loggingEnabled && m_logfile) { - uint8_t buf[MAVLINK_MAX_PACKET_LEN+sizeof(quint64)] = {0}; - quint64 time = QGC::groundTimeUsecs(); - memcpy(buf, (void*)&time, sizeof(quint64)); - // Write message to buffer - mavlink_msg_to_send_buffer(buf+sizeof(quint64), &message); - //we need to write the maximum package length for having a - //consistent file structure and beeing able to parse it again - int len = MAVLINK_MAX_PACKET_LEN + sizeof(quint64); + uint8_t buf[MAVLINK_MAX_PACKET_LEN+sizeof(quint64)]; + + // Write the uint64 time in microseconds in big endian format before the message. + // This timestamp is saved in UTC time. We are only saving in ms precision because + // getting more than this isn't possible with Qt without a ton of extra code. + quint64 time = (quint64)QDateTime::currentMSecsSinceEpoch() * 1000; + qToBigEndian(time, buf); + + // Then write the message to the buffer + int len = mavlink_msg_to_send_buffer(buf + sizeof(quint64), &message); + + // Determine how many bytes were written by adding the timestamp size to the message size + len += sizeof(quint64); + + // Now write this timestamp/message pair to the log. QByteArray b((const char*)buf, len); if(m_logfile->write(b) != len) { + // If there's an error logging data, raise an alert and stop logging. emit protocolStatusMessage(tr("MAVLink Logging failed"), tr("Could not write to file %1, disabling logging.").arg(m_logfile->fileName())); - // Stop logging enableLogging(false); } } diff --git a/src/comm/MAVLinkProtocol.h b/src/comm/MAVLinkProtocol.h index 3dc72563f50ebd4c8e34594d4c34b45d3aa7cae4..158890dbab600a9a71fcebb15e254d288f398056 100644 --- a/src/comm/MAVLinkProtocol.h +++ b/src/comm/MAVLinkProtocol.h @@ -150,6 +150,8 @@ public: */ virtual void resetMetadataForLink(const LinkInterface *link); + void run(); + public slots: /** @brief Receive bytes from a communication interface */ void receiveBytes(LinkInterface* link, QByteArray b); @@ -212,7 +214,7 @@ public slots: void storeSettings(); protected: - QTimer* heartbeatTimer; ///< Timer to emit heartbeats + QTimer *heartbeatTimer; ///< Timer to emit heartbeats int heartbeatRate; ///< Heartbeat rate, controls the timer interval bool m_heartbeatsEnabled; ///< Enabled/disable heartbeat emission bool m_multiplexingEnabled; ///< Enable/disable packet multiplexing @@ -235,6 +237,8 @@ protected: int currLossCounter[MAVLINK_COMM_NUM_BUFFERS]; ///< Lost messages during this sample time window. Used for calculating loss %. bool versionMismatchIgnore; int systemId; + bool _should_exit; + #if defined(QGC_PROTOBUF_ENABLED) && defined(QGC_USE_PIXHAWK_MESSAGES) mavlink::ProtobufManager protobufManager; #endif diff --git a/src/comm/ProtocolInterface.h b/src/comm/ProtocolInterface.h index 150d5eb8f751385fd21e7541161a85846b2ec90a..a3a5fef128f7cf05c343fdee6f1352ae0d0752dc 100644 --- a/src/comm/ProtocolInterface.h +++ b/src/comm/ProtocolInterface.h @@ -46,7 +46,7 @@ This file is part of the PIXHAWK project * @see LinkManager. * **/ -class ProtocolInterface : public QObject +class ProtocolInterface : public QThread { Q_OBJECT public: diff --git a/src/comm/QGCFlightGearLink.cc b/src/comm/QGCFlightGearLink.cc index df3b4515671f3335efcd01f85af1ced238fd3ef2..040e923776e1360ae711b59038b7c9b2fa8f8b43 100644 --- a/src/comm/QGCFlightGearLink.cc +++ b/src/comm/QGCFlightGearLink.cc @@ -80,14 +80,17 @@ void QGCFlightGearLink::run() if (!mav) return; socket = new QUdpSocket(this); + socket->moveToThread(this); connectState = socket->bind(host, port); QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(readBytes())); process = new QProcess(this); + process->moveToThread(this); terraSync = new QProcess(this); + terraSync->moveToThread(this); - connect(mav, SIGNAL(hilControlsChanged(uint64_t, float, float, float, float, uint8_t, uint8_t)), this, SLOT(updateControls(uint64_t,float,float,float,float,uint8_t,uint8_t))); + connect(mav, SIGNAL(hilControlsChanged(quint64, float, float, float, float, quint8, quint8)), this, SLOT(updateControls(quint64,float,float,float,float,quint8,quint8))); connect(this, SIGNAL(hilStateChanged(quint64, float, float, float, float,float, float, double, double, double, float, float, float, float, float, float, float, float)), mav, SLOT(sendHilState(quint64, float, float, float, float,float, float, double, double, double, float, float, float, float, float, float, float, float))); connect(this, SIGNAL(sensorHilGpsChanged(quint64, double, double, double, int, float, float, float, float, float, float, float, int)), mav, SLOT(sendHilGps(quint64, double, double, double, int, float, float, float, float, float, float, float, int))); connect(this, SIGNAL(sensorHilRawImuChanged(quint64,float,float,float,float,float,float,float,float,float,float,float,float,float,quint32)), mav, SLOT(sendHilSensors(quint64,float,float,float,float,float,float,float,float,float,float,float,float,float,quint32))); @@ -189,13 +192,13 @@ void QGCFlightGearLink::run() flightGearArguments << QString("--fg-aircraft=%1").arg(fgAircraft); if (mav->getSystemType() == MAV_TYPE_QUADROTOR) { - flightGearArguments << QString("--generic=socket,out,50,127.0.0.1,%1,udp,qgroundcontrol-quadrotor").arg(port); - flightGearArguments << QString("--generic=socket,in,50,127.0.0.1,%1,udp,qgroundcontrol-quadrotor").arg(currentPort); + flightGearArguments << QString("--generic=socket,out,300,127.0.0.1,%1,udp,qgroundcontrol-quadrotor").arg(port); + flightGearArguments << QString("--generic=socket,in,300,127.0.0.1,%1,udp,qgroundcontrol-quadrotor").arg(currentPort); } else { - flightGearArguments << QString("--generic=socket,out,50,127.0.0.1,%1,udp,qgroundcontrol-fixed-wing").arg(port); - flightGearArguments << QString("--generic=socket,in,50,127.0.0.1,%1,udp,qgroundcontrol-fixed-wing").arg(currentPort); + flightGearArguments << QString("--generic=socket,out,300,127.0.0.1,%1,udp,qgroundcontrol-fixed-wing").arg(port); + flightGearArguments << QString("--generic=socket,in,300,127.0.0.1,%1,udp,qgroundcontrol-fixed-wing").arg(currentPort); } flightGearArguments << "--atlas=socket,out,1,localhost,5505,udp"; // flightGearArguments << "--in-air"; @@ -363,7 +366,7 @@ void QGCFlightGearLink::setRemoteHost(const QString& host) } -void QGCFlightGearLink::updateActuators(uint64_t time, float act1, float act2, float act3, float act4, float act5, float act6, float act7, float act8) +void QGCFlightGearLink::updateActuators(quint64 time, float act1, float act2, float act3, float act4, float act5, float act6, float act7, float act8) { Q_UNUSED(time); Q_UNUSED(act1); @@ -376,7 +379,7 @@ void QGCFlightGearLink::updateActuators(uint64_t time, float act1, float act2, f Q_UNUSED(act8); } -void QGCFlightGearLink::updateControls(uint64_t time, float rollAilerons, float pitchElevator, float yawRudder, float throttle, uint8_t systemMode, uint8_t navMode) +void QGCFlightGearLink::updateControls(quint64 time, float rollAilerons, float pitchElevator, float yawRudder, float throttle, quint8 systemMode, quint8 navMode) { // magnetos,aileron,elevator,rudder,throttle\n @@ -461,7 +464,7 @@ void QGCFlightGearLink::readBytes() // Parse string float roll, pitch, yaw, rollspeed, pitchspeed, yawspeed; - double lat, lon, alt; + double lat, lon, alt; float ind_airspeed; float true_airspeed; float vx, vy, vz, xacc, yacc, zacc; @@ -504,7 +507,7 @@ void QGCFlightGearLink::readBytes() float density = abs_pressure / (air_gas_constant * (temperature - absolute_null_celsius)); diff_pressure = true_airspeed * true_airspeed * density / 2.0f; //qDebug() << "diff_pressure: " << diff_pressure << "abs_pressure: " << abs_pressure; - + /* Calculate indicated airspeed */ const float air_density_sea_level_15C = 1.225f; //kg/m^3 if (diff_pressure > 0) @@ -514,9 +517,9 @@ void QGCFlightGearLink::readBytes() { ind_airspeed = -sqrtf((2.0f*fabsf(diff_pressure)) / air_density_sea_level_15C); } - + //qDebug() << "ind_airspeed: " << ind_airspeed << "true_airspeed: " << true_airspeed; - + // Send updated state //qDebug() << "sensorHilEnabled: " << sensorHilEnabled; if (_sensorHilEnabled) @@ -585,7 +588,7 @@ void QGCFlightGearLink::readBytes() vx, vy, vz, ind_airspeed, true_airspeed, xacc, yacc, zacc); - //qDebug() << "hilStateChanged " << (int32_t)lat << (int32_t)lon << (int32_t)alt; + //qDebug() << "hilStateChanged " << (qint32)lat << (qint32)lon << (qint32)alt; } // // Echo data for debugging purposes @@ -619,7 +622,7 @@ bool QGCFlightGearLink::disconnectSimulation() { disconnect(process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError))); - disconnect(mav, SIGNAL(hilControlsChanged(uint64_t, float, float, float, float, uint8_t, uint8_t)), this, SLOT(updateControls(uint64_t,float,float,float,float,uint8_t,uint8_t))); + disconnect(mav, SIGNAL(hilControlsChanged(quint64, float, float, float, float, quint8, quint8)), this, SLOT(updateControls(quint64,float,float,float,float,quint8,quint8))); disconnect(this, SIGNAL(hilStateChanged(quint64, float, float, float, float,float, float, double, double, double, float, float, float, float, float, float, float, float)), mav, SLOT(sendHilState(quint64, float, float, float, float,float, float, double, double, double, float, float, float, float, float, float, float, float))); disconnect(this, SIGNAL(sensorHilGpsChanged(quint64, double, double, double, int, float, float, float, float, float, float, float, int)), mav, SLOT(sendHilGps(quint64, double, double, double, int, float, float, float, float, float, float, float, int))); disconnect(this, SIGNAL(sensorHilRawImuChanged(quint64,float,float,float,float,float,float,float,float,float,float,float,float,float,quint32)), mav, SLOT(sendHilSensors(quint64,float,float,float,float,float,float,float,float,float,float,float,float,float,quint32))); diff --git a/src/comm/QGCJSBSimLink.cc b/src/comm/QGCJSBSimLink.cc index ffe29e610e5d3da2337416cfa216aa1a4cf4c11a..947161d1488de60fb3b08791f8c492e2c5932cbb 100644 --- a/src/comm/QGCJSBSimLink.cc +++ b/src/comm/QGCJSBSimLink.cc @@ -75,13 +75,14 @@ void QGCJSBSimLink::run() if (!mav) return; socket = new QUdpSocket(this); + socket->moveToThread(this); connectState = socket->bind(host, port); QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(readBytes())); process = new QProcess(this); - connect(mav, SIGNAL(hilControlsChanged(uint64_t, float, float, float, float, uint8_t, uint8_t)), this, SLOT(updateControls(uint64_t,float,float,float,float,uint8_t,uint8_t))); + connect(mav, SIGNAL(hilControlsChanged(quint64, float, float, float, float, quint8, quint8)), this, SLOT(updateControls(quint64,float,float,float,float,quint8,quint8))); connect(this, SIGNAL(hilStateChanged(quint64,float,float,float,float,float,float,double,double,double,float,float,float,float,float,float,float,float)), mav, SLOT(sendHilState(quint64,float,float,float,float,float,float,double,double,double,float,float,float,float,float,float,float,float))); @@ -230,7 +231,7 @@ void QGCJSBSimLink::setRemoteHost(const QString& host) } -void QGCJSBSimLink::updateActuators(uint64_t time, float act1, float act2, float act3, float act4, float act5, float act6, float act7, float act8) +void QGCJSBSimLink::updateActuators(quint64 time, float act1, float act2, float act3, float act4, float act5, float act6, float act7, float act8) { Q_UNUSED(time); Q_UNUSED(act1); @@ -243,7 +244,7 @@ void QGCJSBSimLink::updateActuators(uint64_t time, float act1, float act2, float Q_UNUSED(act8); } -void QGCJSBSimLink::updateControls(uint64_t time, float rollAilerons, float pitchElevator, float yawRudder, float throttle, uint8_t systemMode, uint8_t navMode) +void QGCJSBSimLink::updateControls(quint64 time, float rollAilerons, float pitchElevator, float yawRudder, float throttle, quint8 systemMode, quint8 navMode) { // magnetos,aileron,elevator,rudder,throttle\n @@ -356,7 +357,7 @@ bool QGCJSBSimLink::disconnectSimulation() { disconnect(process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError))); - disconnect(mav, SIGNAL(hilControlsChanged(uint64_t, float, float, float, float, uint8_t, uint8_t)), this, SLOT(updateControls(uint64_t,float,float,float,float,uint8_t,uint8_t))); + disconnect(mav, SIGNAL(hilControlsChanged(quint64, float, float, float, float, quint8, quint8)), this, SLOT(updateControls(quint64,float,float,float,float,quint8,quint8))); disconnect(this, SIGNAL(hilStateChanged(quint64,float,float,float,float,float,float,double,double,double,float,float,float,float,float,float,float,float)), mav, SLOT(sendHilState(quint64,float,float,float,float,float,float,double,double,double,float,float,float,float,float,float,float,float))); if (process) diff --git a/src/comm/QGCXPlaneLink.cc b/src/comm/QGCXPlaneLink.cc index 25018a1f940cd0bb148a7a87fd20c1947e1cdf1f..b30b5216e46ea1c14fa815c2c2caa6b8479a936c 100644 --- a/src/comm/QGCXPlaneLink.cc +++ b/src/comm/QGCXPlaneLink.cc @@ -55,8 +55,10 @@ QGCXPlaneLink::QGCXPlaneLink(UASInterface* mav, QString remoteHost, QHostAddress simUpdateLast(QGC::groundTimeMilliseconds()), simUpdateFirst(0), simUpdateLastText(QGC::groundTimeMilliseconds()), + simUpdateLastGroundTruth(QGC::groundTimeMilliseconds()), simUpdateHz(0), - _sensorHilEnabled(true) + _sensorHilEnabled(true), + _should_exit(false) { // We're doing it wrong - because the Qt folks got the API wrong: // http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/ @@ -73,6 +75,11 @@ QGCXPlaneLink::QGCXPlaneLink(UASInterface* mav, QString remoteHost, QHostAddress QGCXPlaneLink::~QGCXPlaneLink() { storeSettings(); + // Tell the thread to exit + _should_exit = true; + // Wait for it to exit + wait(); + // if(connectState) { // disconnectSimulation(); // } @@ -148,18 +155,19 @@ void QGCXPlaneLink::run() if (connectState) return; socket = new QUdpSocket(this); + socket->moveToThread(this); connectState = socket->bind(localHost, localPort); if (!connectState) return; QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(readBytes())); - connect(mav, SIGNAL(hilControlsChanged(quint64, float, float, float, float, quint8, quint8)), this, SLOT(updateControls(quint64,float,float,float,float,quint8,quint8))); - connect(mav, SIGNAL(hilActuatorsChanged(quint64, float, float, float, float, float, float, float, float)), this, SLOT(updateActuators(quint64,float,float,float,float,float,float,float,float))); + connect(mav, SIGNAL(hilControlsChanged(quint64, float, float, float, float, quint8, quint8)), this, SLOT(updateControls(quint64,float,float,float,float,quint8,quint8)), Qt::QueuedConnection); + connect(mav, SIGNAL(hilActuatorsChanged(quint64, float, float, float, float, float, float, float, float)), this, SLOT(updateActuators(quint64,float,float,float,float,float,float,float,float)), Qt::QueuedConnection); - connect(this, SIGNAL(hilGroundTruthChanged(quint64,float,float,float,float,float,float,double,double,double,float,float,float,float,float,float,float,float)), mav, SLOT(sendHilGroundTruth(quint64,float,float,float,float,float,float,double,double,double,float,float,float,float,float,float,float,float))); - connect(this, SIGNAL(hilStateChanged(quint64,float,float,float,float,float,float,double,double,double,float,float,float,float,float,float,float,float)), mav, SLOT(sendHilState(quint64,float,float,float,float,float,float,double,double,double,float,float,float,float,float,float,float,float))); - connect(this, SIGNAL(sensorHilGpsChanged(quint64,double,double,double,int,float,float,float,float,float,float,float,int)), mav, SLOT(sendHilGps(quint64,double,double,double,int,float,float,float,float,float,float,float,int))); - connect(this, SIGNAL(sensorHilRawImuChanged(quint64,float,float,float,float,float,float,float,float,float,float,float,float,float,quint32)), mav, SLOT(sendHilSensors(quint64,float,float,float,float,float,float,float,float,float,float,float,float,float,quint32))); + connect(this, SIGNAL(hilGroundTruthChanged(quint64,float,float,float,float,float,float,double,double,double,float,float,float,float,float,float,float,float)), mav, SLOT(sendHilGroundTruth(quint64,float,float,float,float,float,float,double,double,double,float,float,float,float,float,float,float,float)), Qt::QueuedConnection); + connect(this, SIGNAL(hilStateChanged(quint64,float,float,float,float,float,float,double,double,double,float,float,float,float,float,float,float,float)), mav, SLOT(sendHilState(quint64,float,float,float,float,float,float,double,double,double,float,float,float,float,float,float,float,float)), Qt::QueuedConnection); + connect(this, SIGNAL(sensorHilGpsChanged(quint64,double,double,double,int,float,float,float,float,float,float,float,int)), mav, SLOT(sendHilGps(quint64,double,double,double,int,float,float,float,float,float,float,float,int)), Qt::QueuedConnection); + connect(this, SIGNAL(sensorHilRawImuChanged(quint64,float,float,float,float,float,float,float,float,float,float,float,float,float,quint32)), mav, SLOT(sendHilSensors(quint64,float,float,float,float,float,float,float,float,float,float,float,float,float,quint32)), Qt::QueuedConnection); UAS* uas = dynamic_cast(mav); if (uas) @@ -209,7 +217,10 @@ void QGCXPlaneLink::run() writeBytes((const char*)&ip, sizeof(ip)); - exec(); + while(!_should_exit) { + QCoreApplication::processEvents(); + QGC::SLEEP::msleep(5); + } } void QGCXPlaneLink::setPort(int localPort) @@ -734,6 +745,8 @@ void QGCXPlaneLink::readBytes() simUpdateLastText = QGC::groundTimeMilliseconds(); } + simUpdateLast = QGC::groundTimeMilliseconds(); + if (_sensorHilEnabled) { diff_pressure = (ind_airspeed * ind_airspeed * 1.225f) / 2.0f; @@ -783,13 +796,13 @@ void QGCXPlaneLink::readBytes() } // Limit ground truth to 25 Hz - if (QGC::groundTimeMilliseconds() - simUpdateLast > 40) { + if (QGC::groundTimeMilliseconds() - simUpdateLastGroundTruth > 40) { emit hilGroundTruthChanged(QGC::groundTimeUsecs(), roll, pitch, yaw, rollspeed, pitchspeed, yawspeed, lat, lon, alt, vx, vy, vz, ind_airspeed, true_airspeed, xacc, yacc, zacc); - } - simUpdateLast = QGC::groundTimeMilliseconds(); + simUpdateLastGroundTruth = QGC::groundTimeMilliseconds(); + } } if (!oldConnectionState && xPlaneConnected) @@ -834,8 +847,8 @@ bool QGCXPlaneLink::disconnectSimulation() this, SLOT(processError(QProcess::ProcessError))); if (mav) { - disconnect(mav, SIGNAL(hilControlsChanged(uint64_t, float, float, float, float, uint8_t, uint8_t)), this, SLOT(updateControls(uint64_t,float,float,float,float,uint8_t,uint8_t))); - disconnect(mav, SIGNAL(hilActuatorsChanged(uint64_t, float, float, float, float, float, float, float, float)), this, SLOT(updateActuators(uint64_t,float,float,float,float,float,float,float,float))); + disconnect(mav, SIGNAL(hilControlsChanged(quint64, float, float, float, float, quint8, quint8)), this, SLOT(updateControls(quint64,float,float,float,float,quint8,quint8))); + disconnect(mav, SIGNAL(hilActuatorsChanged(quint64, float, float, float, float, float, float, float, float)), this, SLOT(updateActuators(quint64,float,float,float,float,float,float,float,float))); disconnect(this, SIGNAL(hilGroundTruthChanged(quint64,float,float,float,float,float,float,double,double,double,float,float,float,float,float,float,float,float)), mav, SLOT(sendHilGroundTruth(quint64,float,float,float,float,float,float,double,double,double,float,float,float,float,float,float,float,float))); disconnect(this, SIGNAL(hilStateChanged(quint64,float,float,float,float,float,float,double,double,double,float,float,float,float,float,float,float,float)), mav, SLOT(sendHilState(quint64,float,float,float,float,float,float,double,double,double,float,float,float,float,float,float,float,float))); diff --git a/src/comm/QGCXPlaneLink.h b/src/comm/QGCXPlaneLink.h index 3ec98e45429af1ca1c11fb7df64731d89761bf4c..ae4497432da0a51d824d9e438b9270f0871491b6 100644 --- a/src/comm/QGCXPlaneLink.h +++ b/src/comm/QGCXPlaneLink.h @@ -207,8 +207,10 @@ protected: quint64 simUpdateLast; quint64 simUpdateFirst; quint64 simUpdateLastText; + quint64 simUpdateLastGroundTruth; float simUpdateHz; bool _sensorHilEnabled; + bool _should_exit; void setName(QString name); }; diff --git a/src/comm/SerialLink.cc b/src/comm/SerialLink.cc index 10141b4ed4451b973954f96f3f1f74795c661298..ac628f91e332e2452b38bc07fa1802ac42e3b1df 100644 --- a/src/comm/SerialLink.cc +++ b/src/comm/SerialLink.cc @@ -73,6 +73,7 @@ SerialLink::SerialLink(QString portname, int baudRate, bool hardwareFlowControl, qDebug() << "m_portName " << m_portName; LinkManager::instance()->add(this); + qDebug() << "link added to link manager"; } void SerialLink::requestReset() @@ -86,6 +87,11 @@ SerialLink::~SerialLink() disconnect(); if(m_port) delete m_port; m_port = NULL; + + // Tell the thread to exit + quit(); + // Wait for it to exit + wait(); } QList SerialLink::getCurrentPorts() @@ -109,6 +115,32 @@ QList SerialLink::getCurrentPorts() return m_ports; } +bool SerialLink::isBootloader() +{ + QList portList = QSerialPortInfo::availablePorts(); + + if( portList.count() == 0){ + return false; + } + + foreach (const QSerialPortInfo &info, portList) + { +// qDebug() << "PortName : " << info.portName() +// << "Description : " << info.description(); +// qDebug() << "Manufacturer: " << info.manufacturer(); + + if (info.portName().trimmed() == this->m_portName.trimmed() && + (info.description().toLower().contains("bootloader") || + info.description().toLower().contains("px4 bl"))) { + qDebug() << "BOOTLOADER FOUND"; + return true; + } + } + + // Not found + return false; +} + void SerialLink::loadSettings() { // Load defaults from settings @@ -188,42 +220,54 @@ void SerialLink::run() err = m_port->errorString(); } emit communicationError(getName(),"Error connecting: " + err); -// disconnect(); // This tidies up and sends the necessary signals return; } - // Qt way to make clear what a while(1) loop does qint64 msecs = QDateTime::currentMSecsSinceEpoch(); qint64 initialmsecs = QDateTime::currentMSecsSinceEpoch(); quint64 bytes = 0; -// bool triedreset = false; -// bool triedDTR = false; qint64 timeout = 5000; int linkErrorCount = 0; + // Qt way to make clear what a while(1) loop does forever { { QMutexLocker locker(&this->m_stoppMutex); - if(m_stopp) { + if (m_stopp) { m_stopp = false; break; // exit the thread } - - if (m_reqReset) { - m_reqReset = false; - emit communicationUpdate(getName(),"Reset requested via DTR signal"); - m_port->setDataTerminalReady(true); - msleep(250); - m_port->setDataTerminalReady(false); - } } // If there are too many errors on this link, disconnect. - if (isConnected() && (linkErrorCount > 1000)) { - qDebug() << "linkErrorCount too high: disconnecting!"; + if (isConnected() && (linkErrorCount > 100)) { + qDebug() << "linkErrorCount too high: re-connecting!"; linkErrorCount = 0; - emit communicationUpdate(getName(), tr("Disconnecting on too many link errors")); - disconnect(); + emit communicationUpdate(getName(), tr("Reconnecting on too many link errors")); + + if (m_port) { + m_port->close(); + delete m_port; + m_port = NULL; + + emit disconnected(); + emit connected(false); + } + + QGC::SLEEP::msleep(500); + + unsigned tries = 0; + const unsigned tries_max = 15; + while (!hardwareConnect(type) && tries < tries_max) { + tries++; + QGC::SLEEP::msleep(500); + } + + // Give up + if (tries == tries_max) { + break; + } + } // Write all our buffered data out the serial port. @@ -294,30 +338,12 @@ void SerialLink::run() //TODO ^^ timeout = 30000; } -// if (!triedDTR && triedreset) { -// triedDTR = true; -// emit communicationUpdate(getName(),"No data to receive on COM port. Attempting to reset via DTR signal"); -// qDebug() << "No data!!! Attempting reset via DTR."; -// m_port->setDataTerminalReady(true); -// msleep(250); -// m_port->setDataTerminalReady(false); -// } -// else if (!triedreset) { -// qDebug() << "No data!!! Attempting reset via reboot command."; -// emit communicationUpdate(getName(),"No data to receive on COM port. Assuming possible terminal mode, attempting to reset via \"reboot\" command"); -// m_port->write("reboot\r\n",8); -// triedreset = true; -// } -// else { -// emit communicationUpdate(getName(),"No data to receive on COM port...."); -// qDebug() << "No data!!!"; -// } } } - MG::SLEEP::msleep(SerialLink::poll_interval); + QGC::SLEEP::msleep(SerialLink::poll_interval); } // end of forever - if (m_port) { // [TODO][BB] Not sure we need to close the port here + if (m_port) { qDebug() << "Closing Port #"<< __LINE__ << m_port->portName(); m_port->close(); delete m_port; @@ -337,7 +363,6 @@ void SerialLink::writeBytes(const char* data, qint64 size) m_transmitBuffer.append(byteArray); m_writeMutex.unlock(); } else { - disconnect(); // Error occured emit communicationError(getName(), tr("Could not send data - link %1 is disconnected!").arg(getName())); } @@ -391,10 +416,6 @@ qint64 SerialLink::bytesAvailable() **/ bool SerialLink::disconnect() { - qDebug() << "disconnect"; - if (m_port) - qDebug() << m_port->portName(); - if (isRunning()) { { @@ -403,8 +424,6 @@ bool SerialLink::disconnect() } wait(); // This will terminate the thread and close the serial port - emit disconnected(); // [TODO] There are signals from QSerialPort we should use - emit connected(false); return true; } @@ -421,6 +440,7 @@ bool SerialLink::disconnect() **/ bool SerialLink::connect() { + qDebug() << "CONNECT CALLED"; if (isRunning()) disconnect(); { @@ -451,7 +471,30 @@ bool SerialLink::hardwareConnect(QString &type) } qDebug() << "SerialLink: hardwareConnect to " << m_portName; + + if (isBootloader()) { + qDebug() << "Not connecting to a bootloader, waiting for 2nd chance"; + + const unsigned retry_limit = 12; + unsigned retries; + + for (retries = 0; retries < retry_limit; retries++) { + if (!isBootloader()) { + break; + } + QGC::SLEEP::msleep(500); + } + + // Check limit + if (retries == retry_limit) { + + // bail out + return false; + } + } + m_port = new QSerialPort(m_portName); + m_port->moveToThread(this); if (!m_port) { emit communicationUpdate(getName(),"Error opening port: " + m_portName); diff --git a/src/comm/SerialLink.h b/src/comm/SerialLink.h index 6f27e4b3d0f4d1b757d82a9bf7f865493f7b2ce1..0534417697879010b2aa3fce0cd032a886d32133 100644 --- a/src/comm/SerialLink.h +++ b/src/comm/SerialLink.h @@ -72,6 +72,9 @@ public: /** @brief Get a list of the currently available ports */ QList getCurrentPorts(); + /** @brief Check if the current port is a bootloader */ + bool isBootloader(); + void requestReset(); bool isConnected() const; diff --git a/src/comm/TCPLink.cc b/src/comm/TCPLink.cc index 392edbfcbb8e7be4961e16ab9ef4c6696ebc6015..146e7a39306b03d4a67b4b370894f6f563a19f19 100644 --- a/src/comm/TCPLink.cc +++ b/src/comm/TCPLink.cc @@ -56,6 +56,12 @@ TCPLink::TCPLink(QHostAddress hostAddress, quint16 socketPort) : TCPLink::~TCPLink() { disconnect(); + + // Tell the thread to exit + quit(); + // Wait for it to exit + wait(); + deleteLater(); } diff --git a/src/comm/UDPLink.cc b/src/comm/UDPLink.cc index 7c401c73402bffc4dc4d6e6dfa6c0e6c4bff5104..d02e9290a3abcc13cf5cb128511d0b89ccf1f66c 100644 --- a/src/comm/UDPLink.cc +++ b/src/comm/UDPLink.cc @@ -60,6 +60,12 @@ UDPLink::UDPLink(QHostAddress host, quint16 port) : UDPLink::~UDPLink() { disconnect(); + + // Tell the thread to exit + quit(); + // Wait for it to exit + wait(); + this->deleteLater(); } diff --git a/src/comm/px4_custom_mode.h b/src/comm/px4_custom_mode.h index 9c0c8ae91ea11ffbcd6e1d101da32c12ab207174..a0fed6a277e931ef3b7c4b7300565c2214641fb7 100644 --- a/src/comm/px4_custom_mode.h +++ b/src/comm/px4_custom_mode.h @@ -3,8 +3,8 @@ enum PX4_CUSTOM_MAIN_MODE { PX4_CUSTOM_MAIN_MODE_MANUAL = 1, - PX4_CUSTOM_MAIN_MODE_SEATBELT, - PX4_CUSTOM_MAIN_MODE_EASY, + PX4_CUSTOM_MAIN_MODE_ALTCTL, + PX4_CUSTOM_MAIN_MODE_POSCTL, PX4_CUSTOM_MAIN_MODE_AUTO, }; diff --git a/src/configuration.h b/src/configuration.h index e0e5fcaaf74b4385fa0e1c3d41a31ae0ef1fe24f..bbfa865eec7d14faf3aba1619be0ba1bbcb66d99 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -4,14 +4,14 @@ #include /** @brief Polling interval in ms */ -#define SERIAL_POLL_INTERVAL 5 +#define SERIAL_POLL_INTERVAL 4 /** @brief Heartbeat emission rate, in Hertz (times per second) */ #define MAVLINK_HEARTBEAT_DEFAULT_RATE 1 #define WITH_TEXT_TO_SPEECH 1 #define QGC_APPLICATION_NAME "QGroundControl" -#define QGC_APPLICATION_VERSION "v. 2.0.1 (beta)" +#define QGC_APPLICATION_VERSION "v. 2.0.3 (beta)" namespace QGC @@ -19,7 +19,7 @@ namespace QGC const QString APPNAME = "QGROUNDCONTROL"; const QString ORG_NAME = "QGROUNDCONTROL.ORG"; //can be customized by forks to e.g. mycompany.com to maintain separate Settings for customized apps const QString ORG_DOMAIN = "org.qgroundcontrol";//can be customized by forks -const int APPLICATIONVERSION = 201; // 2.0.1 +const int APPLICATIONVERSION = 203; // 2.0.3 } #endif // QGC_CONFIGURATION_H diff --git a/src/main.cc b/src/main.cc index 1b0e8846a8ebf0a2ca3123528a0c922d7f295072..e425ba62dd08d5b44421fddd02319b7a1ae0458e 100644 --- a/src/main.cc +++ b/src/main.cc @@ -36,6 +36,10 @@ This file is part of the QGROUNDCONTROL project #include "TCPLink.h" #ifdef QT_DEBUG #include "AutoTest.h" +#include "CmdLineOptParser.h" +#ifdef Q_OS_WIN +#include +#endif #endif /* SDL does ugly things to main() */ @@ -44,10 +48,10 @@ This file is part of the QGROUNDCONTROL project #endif -// Install a message handler so you do not need -// the MSFT debug tools installed to se -// qDebug(), qWarning(), qCritical and qAbort #ifdef Q_OS_WIN + +/// @brief Message handler which is installed using qInstallMsgHandler so you do not need +/// the MSFT debug tools installed to see qDebug(), qWarning(), qCritical and qAbort void msgHandler( QtMsgType type, const char* msg ) { const char symbols[] = { 'I', 'E', '!', 'X' }; @@ -56,6 +60,17 @@ void msgHandler( QtMsgType type, const char* msg ) if( type == QtFatalMsg ) abort(); } +/// @brief CRT Report Hook installed using _CrtSetReportHook. We install this hook when +/// we don't want asserts to pop a dialog on windows. +int WindowsCrtReportHook(int reportType, char* message, int* returnValue) +{ + Q_UNUSED(reportType); + + std::cerr << message << std::endl; // Output message to stderr + *returnValue = 0; // Don't break into debugger + return true; // We handled this fully ourselves +} + #endif /** @@ -68,7 +83,14 @@ void msgHandler( QtMsgType type, const char* msg ) int main(int argc, char *argv[]) { -// install the message handler + +#ifdef Q_OS_MAC + // Prevent Apple's app nap from screwing us over + // tip: the domain can be cross-checked on the command line with + QProcess::execute("defaults write org.qgroundcontrol.qgroundcontrol NSAppSleepDisabled -bool YES"); +#endif + + // install the message handler #ifdef Q_OS_WIN qInstallMsgHandler( msgHandler ); #endif @@ -81,13 +103,27 @@ int main(int argc, char *argv[]) qRegisterMetaType(); #ifdef QT_DEBUG - if (argc > 1 && QString(argv[1]).compare("--unittest", Qt::CaseInsensitive) == 0) { - // Strip off extra command line args so QTest doesn't complain - for (int i=1; i #include +#include + UASUnitTest::UASUnitTest() { } @@ -8,7 +10,7 @@ UASUnitTest::UASUnitTest() void UASUnitTest::init() { mav = new MAVLinkProtocol(); - uas = new UAS(mav, UASID); + uas = new UAS(mav, QThread::currentThread(), UASID); uas->deleteSettings(); } //this function is called after every test @@ -24,7 +26,7 @@ void UASUnitTest::cleanup() void UASUnitTest::getUASID_test() { // Test a default ID of zero is assigned - UAS* uas2 = new UAS(mav); + UAS* uas2 = new UAS(mav, QThread::currentThread()); QCOMPARE(uas2->getUASID(), 0); delete uas2; @@ -49,7 +51,7 @@ void UASUnitTest::getUASName_test() void UASUnitTest::getUpTime_test() { - UAS* uas2 = new UAS(mav); + UAS* uas2 = new UAS(mav, QThread::currentThread()); // Test that the uptime starts at zero to a // precision of seconds QCOMPARE(floor(uas2->getUptime()/1000.0), 0.0); @@ -73,15 +75,20 @@ void UASUnitTest::getCommunicationStatus_test() void UASUnitTest::filterVoltage_test() { float verificar=uas->filterVoltage(0.4f); - // Verify that upon construction the Comm status is disconnected - QCOMPARE(verificar, 8.52f); + + // We allow the voltage returned to be within a small delta + const float allowedDelta = 0.05f; + const float desiredVoltage = 7.36f; + QVERIFY(verificar > (desiredVoltage - allowedDelta) && verificar < (desiredVoltage + allowedDelta)); } + void UASUnitTest:: getAutopilotType_test() { int type = uas->getAutopilotType(); // Verify that upon construction the autopilot is set to -1 QCOMPARE(type, -1); } + void UASUnitTest::setAutopilotType_test() { uas->setAutopilotType(2); @@ -276,7 +283,7 @@ void UASUnitTest::signalWayPoint_test() delete uas;// delete(destroyed) uas for validating uas = NULL; QCOMPARE(spyDestroyed.count(), 1);// count destroyed uas should are 1 - uas = new UAS(mav,UASID); + uas = new UAS(mav, QThread::currentThread(), UASID); QSignalSpy spy2(uas->getWaypointManager(), SIGNAL(waypointEditableListChanged())); QCOMPARE(spy2.count(), 0); Waypoint* wp2 = new Waypoint(0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,false, false, MAV_FRAME_GLOBAL, MAV_CMD_MISSION_START, "blah"); diff --git a/src/uas/ArduPilotMegaMAV.cc b/src/uas/ArduPilotMegaMAV.cc index eaabfc34a76088396c099e66384fabb7c100fe0e..e8b61c697accd67774ba4a50c683dcd5aa234c3c 100644 --- a/src/uas/ArduPilotMegaMAV.cc +++ b/src/uas/ArduPilotMegaMAV.cc @@ -38,8 +38,8 @@ This file is part of the QGROUNDCONTROL project #endif #endif -ArduPilotMegaMAV::ArduPilotMegaMAV(MAVLinkProtocol* mavlink, int id) : - UAS(mavlink, id)//, +ArduPilotMegaMAV::ArduPilotMegaMAV(MAVLinkProtocol* mavlink, QThread* thread, int id) : + UAS(mavlink, thread, id)//, // place other initializers here { //This does not seem to work. Manually request each stream type at a specified rate. diff --git a/src/uas/ArduPilotMegaMAV.h b/src/uas/ArduPilotMegaMAV.h index 2c3990f4ce1f7a37399dbd7aa93f44d9a5ec4a00..1ff5bf57ebb1622b426c65f98948cd8c2a6d94bc 100644 --- a/src/uas/ArduPilotMegaMAV.h +++ b/src/uas/ArduPilotMegaMAV.h @@ -29,7 +29,7 @@ class ArduPilotMegaMAV : public UAS { Q_OBJECT public: - ArduPilotMegaMAV(MAVLinkProtocol* mavlink, int id = 0); + ArduPilotMegaMAV(MAVLinkProtocol* mavlink, QThread* thread, int id = 0); /** @brief Set camera mount stabilization modes */ void setMountConfigure(unsigned char mode, bool stabilize_roll,bool stabilize_pitch,bool stabilize_yaw); /** @brief Set camera mount control */ diff --git a/src/uas/PxQuadMAV.cc b/src/uas/PxQuadMAV.cc index 0629924bb3792ae61e464cf4d317221c65a156af..337a83ee0003a23f3d13639c927e55696d865c97 100644 --- a/src/uas/PxQuadMAV.cc +++ b/src/uas/PxQuadMAV.cc @@ -23,8 +23,8 @@ This file is part of the QGROUNDCONTROL project #include "PxQuadMAV.h" #include "GAudioOutput.h" -PxQuadMAV::PxQuadMAV(MAVLinkProtocol* mavlink, int id) : - UAS(mavlink, id) +PxQuadMAV::PxQuadMAV(MAVLinkProtocol* mavlink, QThread* thread, int id) : + UAS(mavlink, thread, id) { } diff --git a/src/uas/PxQuadMAV.h b/src/uas/PxQuadMAV.h index 212c8067f5806bea39da5b25b572644003e59c49..28c3ba3a61bcd0af2419f8fea46c659bdac1d9ac 100644 --- a/src/uas/PxQuadMAV.h +++ b/src/uas/PxQuadMAV.h @@ -31,7 +31,7 @@ class PxQuadMAV : public UAS Q_OBJECT Q_INTERFACES(UASInterface) public: - PxQuadMAV(MAVLinkProtocol* mavlink, int id); + PxQuadMAV(MAVLinkProtocol* mavlink, QThread* thread, int id); public slots: /** @brief Receive a MAVLink message from this MAV */ void receiveMessage(LinkInterface* link, mavlink_message_t message); diff --git a/src/uas/QGCMAVLinkUASFactory.cc b/src/uas/QGCMAVLinkUASFactory.cc index 77860aef52263cf0714b4e9167f92aad36b319e5..4f1b7daa556a754078135bf69cc0e997145ecb34 100644 --- a/src/uas/QGCMAVLinkUASFactory.cc +++ b/src/uas/QGCMAVLinkUASFactory.cc @@ -1,5 +1,6 @@ #include "QGCMAVLinkUASFactory.h" #include "UASManager.h" +#include "QGCUASWorker.h" QGCMAVLinkUASFactory::QGCMAVLinkUASFactory(QObject *parent) : QObject(parent) @@ -21,13 +22,16 @@ UASInterface* QGCMAVLinkUASFactory::createUAS(MAVLinkProtocol* mavlink, LinkInte UASInterface* uas; + QGCUASWorker* worker = new QGCUASWorker(); + switch (heartbeat->autopilot) { case MAV_AUTOPILOT_GENERIC: { - UAS* mav = new UAS(mavlink, sysid); + UAS* mav = new UAS(mavlink, worker, sysid); // Set the system type mav->setSystemType((int)heartbeat->type); + // Connect this robot to the UAS object connect(mavlink, SIGNAL(messageReceived(LinkInterface*, mavlink_message_t)), mav, SLOT(receiveMessage(LinkInterface*, mavlink_message_t))); connect(mavlink, SIGNAL(messageReceived(LinkInterface*,mavlink_message_t)), mav->getFileManager(), SLOT(receiveMessage(LinkInterface*, mavlink_message_t))); @@ -39,9 +43,10 @@ UASInterface* QGCMAVLinkUASFactory::createUAS(MAVLinkProtocol* mavlink, LinkInte break; case MAV_AUTOPILOT_PIXHAWK: { - PxQuadMAV* mav = new PxQuadMAV(mavlink, sysid); + PxQuadMAV* mav = new PxQuadMAV(mavlink, worker, sysid); // Set the system type mav->setSystemType((int)heartbeat->type); + // Connect this robot to the UAS object // it is IMPORTANT here to use the right object type, // else the slot of the parent object is called (and thus the special @@ -55,9 +60,10 @@ UASInterface* QGCMAVLinkUASFactory::createUAS(MAVLinkProtocol* mavlink, LinkInte break; case MAV_AUTOPILOT_SLUGS: { - SlugsMAV* mav = new SlugsMAV(mavlink, sysid); + SlugsMAV* mav = new SlugsMAV(mavlink, worker, sysid); // Set the system type mav->setSystemType((int)heartbeat->type); + // Connect this robot to the UAS object // it is IMPORTANT here to use the right object type, // else the slot of the parent object is called (and thus the special @@ -68,9 +74,10 @@ UASInterface* QGCMAVLinkUASFactory::createUAS(MAVLinkProtocol* mavlink, LinkInte break; case MAV_AUTOPILOT_ARDUPILOTMEGA: { - ArduPilotMegaMAV* mav = new ArduPilotMegaMAV(mavlink, sysid); + ArduPilotMegaMAV* mav = new ArduPilotMegaMAV(mavlink, worker, sysid); // Set the system type mav->setSystemType((int)heartbeat->type); + // Connect this robot to the UAS object // it is IMPORTANT here to use the right object type, // else the slot of the parent object is called (and thus the special @@ -82,8 +89,11 @@ UASInterface* QGCMAVLinkUASFactory::createUAS(MAVLinkProtocol* mavlink, LinkInte #ifdef QGC_USE_SENSESOAR_MESSAGES case MAV_AUTOPILOT_SENSESOAR: { - senseSoarMAV* mav = new senseSoarMAV(mavlink,sysid); + senseSoarMAV* mav = new senseSoarMAV(mavlink,worker, sysid); mav->setSystemType((int)heartbeat->type); + + mav->moveToThread(worker); + connect(mavlink, SIGNAL(messageReceived(LinkInterface*, mavlink_message_t)), mav, SLOT(receiveMessage(LinkInterface*, mavlink_message_t))); uas = mav; break; @@ -91,8 +101,9 @@ UASInterface* QGCMAVLinkUASFactory::createUAS(MAVLinkProtocol* mavlink, LinkInte #endif default: { - UAS* mav = new UAS(mavlink, sysid); + UAS* mav = new UAS(mavlink, worker, sysid); mav->setSystemType((int)heartbeat->type); + // Connect this robot to the UAS object // it is IMPORTANT here to use the right object type, // else the slot of the parent object is called (and thus the special @@ -103,6 +114,10 @@ UASInterface* QGCMAVLinkUASFactory::createUAS(MAVLinkProtocol* mavlink, LinkInte break; } + // Get the UAS ready + worker->start(QThread::HighPriority); + connect(uas, SIGNAL(destroyed()), worker, SLOT(quit())); + // Set the autopilot type uas->setAutopilotType((int)heartbeat->autopilot); diff --git a/src/uas/QGCUASWorker.cc b/src/uas/QGCUASWorker.cc new file mode 100644 index 0000000000000000000000000000000000000000..b726e120b40b14b8988bafb84f272d41b3ec7a31 --- /dev/null +++ b/src/uas/QGCUASWorker.cc @@ -0,0 +1,24 @@ +#include "QGCUASWorker.h" + +#include +#include +#include + +QGCUASWorker::QGCUASWorker() : QThread(), + _should_exit(false) +{ +} + +void QGCUASWorker::quit() +{ + _should_exit = true; +} + +void QGCUASWorker::run() +{ + while(!_should_exit) { + + QCoreApplication::processEvents(); + QGC::SLEEP::msleep(2); + } +} diff --git a/src/uas/QGCUASWorker.h b/src/uas/QGCUASWorker.h new file mode 100644 index 0000000000000000000000000000000000000000..39ea5f011dc923ae9e29b7da057e94ec7525ceae --- /dev/null +++ b/src/uas/QGCUASWorker.h @@ -0,0 +1,20 @@ +#ifndef QGCUASWORKER_H +#define QGCUASWORKER_H + +#include + +class QGCUASWorker : public QThread +{ +public: + QGCUASWorker(); + +public slots: + void quit(); + +protected: + void run(); + + bool _should_exit; +}; + +#endif // QGCUASWORKER_H diff --git a/src/uas/SlugsMAV.cc b/src/uas/SlugsMAV.cc index cd879cd90d8ce88276ff0079611d100ee3cc02ec..047bfea71091fb9b862c78bbebf6a76f29f794a2 100644 --- a/src/uas/SlugsMAV.cc +++ b/src/uas/SlugsMAV.cc @@ -2,8 +2,8 @@ #include -SlugsMAV::SlugsMAV(MAVLinkProtocol* mavlink, int id) : - UAS(mavlink, id) +SlugsMAV::SlugsMAV(MAVLinkProtocol* mavlink, QThread* thread, int id) : + UAS(mavlink, thread, id) { widgetTimer = new QTimer (this); widgetTimer->setInterval(SLUGS_UPDATE_RATE); diff --git a/src/uas/SlugsMAV.h b/src/uas/SlugsMAV.h index d3e7ae8c79478f71ecd68aa5a3ffc52340c1bff7..da88cbea102715011abd8f9a564ba851e305f3f8 100644 --- a/src/uas/SlugsMAV.h +++ b/src/uas/SlugsMAV.h @@ -53,7 +53,7 @@ class SlugsMAV : public UAS public: - SlugsMAV(MAVLinkProtocol* mavlink, int id = 0); + SlugsMAV(MAVLinkProtocol* mavlink, QThread* thread, int id = 0); public slots: /** @brief Receive a MAVLink message from this MAV */ diff --git a/src/uas/UAS.cc b/src/uas/UAS.cc index 43f3bc786459189bcf61d51706c587d5b08d783b..585781b74d943533a965b2167f38f44eddfae7ce 100644 --- a/src/uas/UAS.cc +++ b/src/uas/UAS.cc @@ -41,7 +41,7 @@ * creating the UAS. */ -UAS::UAS(MAVLinkProtocol* protocol, int id) : UASInterface(), +UAS::UAS(MAVLinkProtocol* protocol, QThread* thread, int id) : UASInterface(), lipoFull(4.2f), lipoEmpty(3.5f), uasId(id), @@ -51,7 +51,7 @@ UAS::UAS(MAVLinkProtocol* protocol, int id) : UASInterface(), commStatus(COMM_DISCONNECTED), receiveDropRate(0), sendDropRate(0), - statusTimeout(new QTimer(this)), + statusTimeout(thread), name(""), type(MAV_TYPE_GENERIC), @@ -156,6 +156,7 @@ UAS::UAS(MAVLinkProtocol* protocol, int id) : UASInterface(), paramsOnceRequested(false), paramMgr(this), simulation(0), + _thread(thread), // The protected members. connectionLost(false), @@ -167,76 +168,77 @@ UAS::UAS(MAVLinkProtocol* protocol, int id) : UASInterface(), lastSendTimeGPS(0), lastSendTimeSensors(0) { + moveToThread(thread); + for (unsigned int i = 0; i<255;++i) { componentID[i] = -1; componentMulti[i] = false; } - // Store a list of available actions for this UAS. - // Basically everything exposted as a SLOT with no return value or arguments. + // Basically everything exposed as a SLOT with no return value or arguments. - QAction* newAction = new QAction(tr("Arm"), this); + QAction* newAction = new QAction(tr("Arm"), thread); newAction->setToolTip(tr("Enable the UAS so that all actuators are online")); connect(newAction, SIGNAL(triggered()), this, SLOT(armSystem())); actions.append(newAction); - newAction = new QAction(tr("Disarm"), this); + newAction = new QAction(tr("Disarm"), thread); newAction->setToolTip(tr("Disable the UAS so that all actuators are offline")); connect(newAction, SIGNAL(triggered()), this, SLOT(disarmSystem())); actions.append(newAction); - newAction = new QAction(tr("Toggle armed"), this); + newAction = new QAction(tr("Toggle armed"), thread); newAction->setToolTip(tr("Toggle between armed and disarmed")); connect(newAction, SIGNAL(triggered()), this, SLOT(toggleAutonomy())); actions.append(newAction); - newAction = new QAction(tr("Go home"), this); + newAction = new QAction(tr("Go home"), thread); newAction->setToolTip(tr("Command the UAS to return to its home position")); connect(newAction, SIGNAL(triggered()), this, SLOT(home())); actions.append(newAction); - newAction = new QAction(tr("Land"), this); + newAction = new QAction(tr("Land"), thread); newAction->setToolTip(tr("Command the UAS to land")); connect(newAction, SIGNAL(triggered()), this, SLOT(land())); actions.append(newAction); - newAction = new QAction(tr("Launch"), this); + newAction = new QAction(tr("Launch"), thread); newAction->setToolTip(tr("Command the UAS to launch itself and begin its mission")); connect(newAction, SIGNAL(triggered()), this, SLOT(launch())); actions.append(newAction); - newAction = new QAction(tr("Resume"), this); + newAction = new QAction(tr("Resume"), thread); newAction->setToolTip(tr("Command the UAS to continue its mission")); connect(newAction, SIGNAL(triggered()), this, SLOT(go())); actions.append(newAction); - newAction = new QAction(tr("Stop"), this); + newAction = new QAction(tr("Stop"), thread); newAction->setToolTip(tr("Command the UAS to halt and hold position")); connect(newAction, SIGNAL(triggered()), this, SLOT(halt())); actions.append(newAction); - newAction = new QAction(tr("Go autonomous"), this); + newAction = new QAction(tr("Go autonomous"), thread); newAction->setToolTip(tr("Set the UAS into an autonomous control mode")); connect(newAction, SIGNAL(triggered()), this, SLOT(goAutonomous())); actions.append(newAction); - newAction = new QAction(tr("Go manual"), this); + newAction = new QAction(tr("Go manual"), thread); newAction->setToolTip(tr("Set the UAS into a manual control mode")); connect(newAction, SIGNAL(triggered()), this, SLOT(goManual())); actions.append(newAction); - newAction = new QAction(tr("Toggle autonomy"), this); + newAction = new QAction(tr("Toggle autonomy"), thread); newAction->setToolTip(tr("Toggle between manual and full-autonomy")); connect(newAction, SIGNAL(triggered()), this, SLOT(toggleAutonomy())); actions.append(newAction); color = UASInterface::getNextColor(); setBatterySpecs(QString("")); - connect(statusTimeout, SIGNAL(timeout()), this, SLOT(updateState())); + connect(&statusTimeout, SIGNAL(timeout()), this, SLOT(updateState())); connect(this, SIGNAL(systemSpecsChanged(int)), this, SLOT(writeSettings())); - statusTimeout->start(500); + statusTimeout.start(500); readSettings(); //need to init paramMgr after readSettings have been loaded, to properly set autopilot and so forth paramMgr.initWithUAS(this); @@ -252,8 +254,11 @@ UAS::UAS(MAVLinkProtocol* protocol, int id) : UASInterface(), UAS::~UAS() { writeSettings(); + + _thread->quit(); + _thread->wait(); + delete links; - delete statusTimeout; delete simulation; } @@ -366,34 +371,6 @@ void UAS::updateState() GAudioOutput::instance()->notifyNegative(); } } - -//#define MAVLINK_OFFBOARD_CONTROL_MODE_NONE 0 -//#define MAVLINK_OFFBOARD_CONTROL_MODE_RATES 1 -//#define MAVLINK_OFFBOARD_CONTROL_MODE_ATTITUDE 2 -//#define MAVLINK_OFFBOARD_CONTROL_MODE_VELOCITY 3 -//#define MAVLINK_OFFBOARD_CONTROL_MODE_POSITION 4 -//#define MAVLINK_OFFBOARD_CONTROL_FLAG_ARMED 0x10 - -//#warning THIS IS A HUGE HACK AND SHOULD NEVER SHOW UP IN ANY GIT REPOSITORY -// mavlink_message_t message; - -// mavlink_set_quad_swarm_roll_pitch_yaw_thrust_t sp; - -// sp.group = 0; - -// /* set rate mode, set zero rates and 20% throttle */ -// sp.mode = MAVLINK_OFFBOARD_CONTROL_MODE_RATES | MAVLINK_OFFBOARD_CONTROL_FLAG_ARMED; - -// sp.roll[0] = INT16_MAX * 0.0f; -// sp.pitch[0] = INT16_MAX * 0.0f; -// sp.yaw[0] = INT16_MAX * 0.0f; -// sp.thrust[0] = UINT16_MAX * 0.3f; - - -// /* send from system 200 and component 0 */ -// mavlink_msg_set_quad_swarm_roll_pitch_yaw_thrust_encode(200, 0, &message, &sp); - -// sendMessage(message); } /** @@ -595,7 +572,6 @@ void UAS::receiveMessage(LinkInterface* link, mavlink_message_t message) if (this->base_mode != state.base_mode || this->custom_mode != state.custom_mode) { modechanged = true; - receivedMode = true; this->base_mode = state.base_mode; this->custom_mode = state.custom_mode; shortModeText = getShortModeTextFor(this->base_mode, this->custom_mode, this->autopilot); @@ -605,6 +581,9 @@ void UAS::receiveMessage(LinkInterface* link, mavlink_message_t message) modeAudio = " is now in " + audiomodeText; } + // We got the mode + receivedMode = true; + // AUDIO if (modechanged && statechanged) { @@ -1112,58 +1091,124 @@ void UAS::receiveMessage(LinkInterface* link, mavlink_message_t message) break; case MAVLINK_MSG_ID_MISSION_COUNT: { - mavlink_mission_count_t wpc; - mavlink_msg_mission_count_decode(&message, &wpc); - if(wpc.target_system == mavlink->getSystemId() || wpc.target_system == 0) + mavlink_mission_count_t mc; + mavlink_msg_mission_count_decode(&message, &mc); + + // Special case a 0 for the target system or component, it means that anyone is the target, so we should process this. + if (mc.target_system == 0) { + mc.target_system = mavlink->getSystemId(); + } + if (mc.target_component == 0) { + mc.target_component = mavlink->getComponentId(); + } + + // Check that this message applies to the UAS. + if(mc.target_system == mavlink->getSystemId()) { - waypointManager.handleWaypointCount(message.sysid, message.compid, wpc.count); + + if (mc.target_component != mavlink->getComponentId()) { + qDebug() << "The target component ID is not set correctly. This is currently only a warning, but will be turned into an error."; + qDebug() << "Expecting" << mavlink->getComponentId() << "but got" << mc.target_component; + } + + waypointManager.handleWaypointCount(message.sysid, message.compid, mc.count); } else { - qDebug() << "Got waypoint message, but was wrong system id" << wpc.target_system; + qDebug() << QString("Received mission count message, but was wrong system id. Expected %1, received %2").arg(mavlink->getSystemId()).arg(mc.target_system); } } break; case MAVLINK_MSG_ID_MISSION_ITEM: { - mavlink_mission_item_t wp; - mavlink_msg_mission_item_decode(&message, &wp); - //qDebug() << "got waypoint (" << wp.seq << ") from ID " << message.sysid << " x=" << wp.x << " y=" << wp.y << " z=" << wp.z; - if(wp.target_system == mavlink->getSystemId() || wp.target_system == 0) + mavlink_mission_item_t mi; + mavlink_msg_mission_item_decode(&message, &mi); + + // Special case a 0 for the target system or component, it means that anyone is the target, so we should process this. + if (mi.target_system == 0) { + mi.target_system = mavlink->getSystemId(); + } + if (mi.target_component == 0) { + mi.target_component = mavlink->getComponentId(); + } + + // Check that the item pertains to this UAS. + if(mi.target_system == mavlink->getSystemId()) { - waypointManager.handleWaypoint(message.sysid, message.compid, &wp); + + if (mi.target_component != mavlink->getComponentId()) { + qDebug() << "The target component ID is not set correctly. This is currently only a warning, but will be turned into an error."; + qDebug() << "Expecting" << mavlink->getComponentId() << "but got" << mi.target_component; + } + + waypointManager.handleWaypoint(message.sysid, message.compid, &mi); } else { - qDebug() << "Got waypoint message, but was wrong system id" << wp.target_system; + qDebug() << QString("Received mission item message, but was wrong system id. Expected %1, received %2").arg(mavlink->getSystemId()).arg(mi.target_system); } } break; case MAVLINK_MSG_ID_MISSION_ACK: { - mavlink_mission_ack_t wpa; - mavlink_msg_mission_ack_decode(&message, &wpa); - if((wpa.target_system == mavlink->getSystemId() || wpa.target_system == 0) && - (wpa.target_component == mavlink->getComponentId() || wpa.target_component == 0)) + mavlink_mission_ack_t ma; + mavlink_msg_mission_ack_decode(&message, &ma); + + // Special case a 0 for the target system or component, it means that anyone is the target, so we should process this. + if (ma.target_system == 0) { + ma.target_system = mavlink->getSystemId(); + } + if (ma.target_component == 0) { + ma.target_component = mavlink->getComponentId(); + } + + // Check that the ack pertains to this UAS. + if(ma.target_system == mavlink->getSystemId()) + { + + if (ma.target_component != mavlink->getComponentId()) { + qDebug() << tr("The target component ID is not set correctly. This is currently only a warning, but will be turned into an error."); + qDebug() << "Expecting" << mavlink->getComponentId() << "but got" << ma.target_component; + } + + waypointManager.handleWaypointAck(message.sysid, message.compid, &ma); + } + else { - waypointManager.handleWaypointAck(message.sysid, message.compid, &wpa); + qDebug() << QString("Received mission ack message, but was wrong system id. Expected %1, received %2").arg(mavlink->getSystemId()).arg(ma.target_system); } } break; case MAVLINK_MSG_ID_MISSION_REQUEST: { - mavlink_mission_request_t wpr; - mavlink_msg_mission_request_decode(&message, &wpr); - if(wpr.target_system == mavlink->getSystemId() || wpr.target_system == 0) + mavlink_mission_request_t mr; + mavlink_msg_mission_request_decode(&message, &mr); + + // Special case a 0 for the target system or component, it means that anyone is the target, so we should process this. + if (mr.target_system == 0) { + mr.target_system = mavlink->getSystemId(); + } + if (mr.target_component == 0) { + mr.target_component = mavlink->getComponentId(); + } + + // Check that the request pertains to this UAS. + if(mr.target_system == mavlink->getSystemId()) { - waypointManager.handleWaypointRequest(message.sysid, message.compid, &wpr); + + if (mr.target_component != mavlink->getComponentId()) { + qDebug() << QString("The target component ID is not set correctly. This is currently only a warning, but will be turned into an error."); + qDebug() << "Expecting" << mavlink->getComponentId() << "but got" << mr.target_component; + } + + waypointManager.handleWaypointRequest(message.sysid, message.compid, &mr); } else { - qDebug() << "Got waypoint message, but was wrong system id" << wpr.target_system; + qDebug() << QString("Received mission request message, but was wrong system id. Expected %1, received %2").arg(mavlink->getSystemId()).arg(mr.target_system); } } break; @@ -1175,7 +1220,7 @@ void UAS::receiveMessage(LinkInterface* link, mavlink_message_t message) waypointManager.handleWaypointReached(message.sysid, message.compid, &wpr); QString text = QString("System %1 reached waypoint %2").arg(getUASName()).arg(wpr.seq); GAudioOutput::instance()->say(text); - emit textMessageReceived(message.sysid, message.compid, 0, text); + emit textMessageReceived(message.sysid, message.compid, MAV_SEVERITY_INFO, text); } break; @@ -1426,6 +1471,7 @@ void UAS::receiveMessage(LinkInterface* link, mavlink_message_t message) case MAVLINK_MSG_ID_NAMED_VALUE_INT: case MAVLINK_MSG_ID_MANUAL_CONTROL: case MAVLINK_MSG_ID_HIGHRES_IMU: + case MAVLINK_MSG_ID_DISTANCE_SENSOR: break; default: { @@ -2552,76 +2598,110 @@ void UAS::processParamValueMsg(mavlink_message_t& msg, const QString& paramName, parameters.insert(compId, new QMap()); } + // Insert parameter into registry + if (parameters.value(compId)->contains(paramName)) { + parameters.value(compId)->remove(paramName); + } QVariant param; // Insert with correct type // TODO: This is a hack for MAV_AUTOPILOT_ARDUPILOTMEGA until the new version of MAVLink and a fix for their param handling. - switch (rawValue.param_type) { - case MAV_PARAM_TYPE_REAL32: - if (getAutopilotType() == MAV_AUTOPILOT_ARDUPILOTMEGA) { - param = QVariant(paramValue.param_float); - } else { - param = QVariant(paramValue.param_float); - } - break; - case MAV_PARAM_TYPE_UINT8: - if (getAutopilotType() == MAV_AUTOPILOT_ARDUPILOTMEGA) { - param = QVariant(QChar((unsigned char)paramValue.param_float)); - } else { - param = QVariant(QChar((quint8)paramValue.param_float)); - } - break; - case MAV_PARAM_TYPE_INT8: - if (getAutopilotType() == MAV_AUTOPILOT_ARDUPILOTMEGA) { - param = QVariant(QChar((char)paramValue.param_float)); - } else { - param = QVariant(QChar((qint8)paramValue.param_float)); - } - break; - case MAV_PARAM_TYPE_INT16: - if (getAutopilotType() == MAV_AUTOPILOT_ARDUPILOTMEGA) { - param = QVariant((short)paramValue.param_float); - } else { - param = QVariant((qint16)paramValue.param_float); - } - break; - case MAV_PARAM_TYPE_UINT16: - if (getAutopilotType() == MAV_AUTOPILOT_ARDUPILOTMEGA) { - param = QVariant((unsigned short)paramValue.param_float); - } else { - param = QVariant((quint16)paramValue.param_float); - } - break; - case MAV_PARAM_TYPE_UINT32: - if (getAutopilotType() == MAV_AUTOPILOT_ARDUPILOTMEGA) { - param = QVariant((unsigned int)paramValue.param_float); - } else { - param = QVariant((quint32)paramValue.param_float); - } - break; - case MAV_PARAM_TYPE_INT32: - if (getAutopilotType() == MAV_AUTOPILOT_ARDUPILOTMEGA) { - param = QVariant((int)paramValue.param_float); - } else { - param = QVariant((qint32)paramValue.param_float); - } - break; - default: - qCritical() << "INVALID DATA TYPE USED AS PARAMETER VALUE: " << rawValue.param_type; - return; + switch (rawValue.param_type) + { + case MAV_PARAM_TYPE_REAL32: + { + if (getAutopilotType() == MAV_AUTOPILOT_ARDUPILOTMEGA) { + param = QVariant(paramValue.param_float); + } + else { + param = QVariant(paramValue.param_float); + } + parameters.value(compId)->insert(paramName, param); + // Emit change + emit parameterChanged(uasId, compId, paramName, param); + emit parameterChanged(uasId, compId, rawValue.param_count, rawValue.param_index, paramName, param); +// qDebug() << "RECEIVED PARAM:" << param; + } + break; + case MAV_PARAM_TYPE_UINT8: + { + if (getAutopilotType() == MAV_AUTOPILOT_ARDUPILOTMEGA) { + param = QVariant(QChar((unsigned char)paramValue.param_float)); + } + else { + param = QVariant(QChar((unsigned char)paramValue.param_uint8)); + } + parameters.value(compId)->insert(paramName, param); + // Emit change + emit parameterChanged(uasId, compId, paramName, param); + emit parameterChanged(uasId, compId, rawValue.param_count, rawValue.param_index, paramName, param); + //qDebug() << "RECEIVED PARAM:" << param; + } + break; + case MAV_PARAM_TYPE_INT8: + { + if (getAutopilotType() == MAV_AUTOPILOT_ARDUPILOTMEGA) { + param = QVariant(QChar((char)paramValue.param_float)); + } + else { + param = QVariant(QChar((char)paramValue.param_int8)); + } + parameters.value(compId)->insert(paramName, param); + // Emit change + emit parameterChanged(uasId, compId, paramName, param); + emit parameterChanged(uasId, compId, rawValue.param_count, rawValue.param_index, paramName, param); + //qDebug() << "RECEIVED PARAM:" << param; + } + break; + case MAV_PARAM_TYPE_INT16: + { + if (getAutopilotType() == MAV_AUTOPILOT_ARDUPILOTMEGA) { + param = QVariant((short)paramValue.param_float); + } + else { + param = QVariant(paramValue.param_int16); + } + parameters.value(compId)->insert(paramName, param); + // Emit change + emit parameterChanged(uasId, compId, paramName, param); + emit parameterChanged(uasId, compId, rawValue.param_count, rawValue.param_index, paramName, param); + //qDebug() << "RECEIVED PARAM:" << param; + } + break; + case MAV_PARAM_TYPE_UINT32: + { + if (getAutopilotType() == MAV_AUTOPILOT_ARDUPILOTMEGA) { + param = QVariant((unsigned int)paramValue.param_float); + } + else { + param = QVariant(paramValue.param_uint32); + } + parameters.value(compId)->insert(paramName, param); + // Emit change + emit parameterChanged(uasId, compId, paramName, param); + emit parameterChanged(uasId, compId, rawValue.param_count, rawValue.param_index, paramName, param); + } + break; + case MAV_PARAM_TYPE_INT32: + { + if (getAutopilotType() == MAV_AUTOPILOT_ARDUPILOTMEGA) { + param = QVariant((int)paramValue.param_float); + } + else { + param = QVariant(paramValue.param_int32); + } + parameters.value(compId)->insert(paramName, param); + // Emit change + emit parameterChanged(uasId, compId, paramName, param); + emit parameterChanged(uasId, compId, rawValue.param_count, rawValue.param_index, paramName, param); +// qDebug() << "RECEIVED PARAM:" << param; + } + break; + default: + qCritical() << "INVALID DATA TYPE USED AS PARAMETER VALUE: " << rawValue.param_type; } //switch (value.param_type) - - // We did not return a critical error, now insert parameter into registry - if (parameters.value(compId)->contains(paramName)) { - parameters.value(compId)->remove(paramName); - } - // add new values - parameters.value(compId)->insert(paramName, param); - // Emit change - emit parameterChanged(uasId, compId, paramName, param); - emit parameterChanged(uasId, compId, rawValue.param_count, rawValue.param_index, paramName, param); } /** @@ -2774,17 +2854,17 @@ void UAS::armSystem() */ void UAS::disarmSystem() { - setModeArm(base_mode & ~MAV_MODE_FLAG_SAFETY_ARMED, custom_mode); + setModeArm(base_mode & ~(MAV_MODE_FLAG_SAFETY_ARMED), custom_mode); } void UAS::toggleArmedState() { - setModeArm(base_mode ^ MAV_MODE_FLAG_SAFETY_ARMED, custom_mode); + setModeArm(base_mode ^ (MAV_MODE_FLAG_SAFETY_ARMED), custom_mode); } void UAS::goAutonomous() { - setMode((base_mode & ~MAV_MODE_FLAG_MANUAL_INPUT_ENABLED) | (MAV_MODE_FLAG_AUTO_ENABLED | MAV_MODE_FLAG_STABILIZE_ENABLED | MAV_MODE_FLAG_GUIDED_ENABLED), 0); + setMode((base_mode & ~(MAV_MODE_FLAG_MANUAL_INPUT_ENABLED)) | (MAV_MODE_FLAG_AUTO_ENABLED | MAV_MODE_FLAG_STABILIZE_ENABLED | MAV_MODE_FLAG_GUIDED_ENABLED), 0); } void UAS::goManual() @@ -3071,7 +3151,7 @@ void UAS::sendHilGroundTruth(quint64 time_us, float roll, float pitch, float yaw Q_UNUSED(xacc); Q_UNUSED(yacc); Q_UNUSED(zacc); - + // Emit attitude for cross-check emit valueChanged(uasId, "roll sim", "rad", roll, getUnixTime()); emit valueChanged(uasId, "pitch sim", "rad", pitch, getUnixTime()); @@ -3360,10 +3440,10 @@ QString UAS::getShortModeTextFor(uint8_t base_mode, uint32_t custom_mode, int au px4_mode.data = custom_mode; if (px4_mode.main_mode == PX4_CUSTOM_MAIN_MODE_MANUAL) { mode += "|MANUAL"; - } else if (px4_mode.main_mode == PX4_CUSTOM_MAIN_MODE_SEATBELT) { - mode += "|SEATBELT"; - } else if (px4_mode.main_mode == PX4_CUSTOM_MAIN_MODE_EASY) { - mode += "|EASY"; + } else if (px4_mode.main_mode == PX4_CUSTOM_MAIN_MODE_ALTCTL) { + mode += "|ALTCTL"; + } else if (px4_mode.main_mode == PX4_CUSTOM_MAIN_MODE_POSCTL) { + mode += "|POSCTL"; } else if (px4_mode.main_mode == PX4_CUSTOM_MAIN_MODE_AUTO) { mode += "|AUTO"; if (px4_mode.sub_mode == PX4_CUSTOM_SUB_MODE_AUTO_READY) { diff --git a/src/uas/UAS.h b/src/uas/UAS.h index a7e0bc5be1b7155a9b62eba9043dc27a4b437e67..ec992e5626598d733432a6783d66f21cb8874aab 100644 --- a/src/uas/UAS.h +++ b/src/uas/UAS.h @@ -32,6 +32,7 @@ This file is part of the QGROUNDCONTROL project #ifndef _UAS_H_ #define _UAS_H_ +#include #include "UASInterface.h" #include #include @@ -56,7 +57,7 @@ class UAS : public UASInterface { Q_OBJECT public: - UAS(MAVLinkProtocol* protocol, int id = 0); + UAS(MAVLinkProtocol* protocol, QThread* thread, int id = 0); ~UAS(); float lipoFull; ///< 100% charged voltage @@ -383,7 +384,7 @@ protected: //COMMENTS FOR TEST UNIT float receiveDropRate; ///< Percentage of packets that were dropped on the MAV's receiving link (from GCS and other MAVs) float sendDropRate; ///< Percentage of packets that were not received from the MAV by the GCS quint64 lastHeartbeat; ///< Time of the last heartbeat message - QTimer* statusTimeout; ///< Timer for various status timeouts + QTimer statusTimeout; ///< Timer for various status timeouts /// BASIC UAS TYPE, NAME AND STATE QString name; ///< Human-friendly name of the vehicle, e.g. bravo @@ -528,6 +529,7 @@ protected: //COMMENTS FOR TEST UNIT /// SIMULATION QGCHilLink* simulation; ///< Hardware in the loop simulation link + QThread* _thread; public: /** @brief Set the current battery type */ diff --git a/src/uas/UASInterface.h b/src/uas/UASInterface.h index 64ac3d2223a7f0e81d653951a393203d8acc7c6c..ee7e019d2543cea8d67d0251d7120a06bcaa4022 100644 --- a/src/uas/UASInterface.h +++ b/src/uas/UASInterface.h @@ -655,7 +655,7 @@ signals: protected: // TIMEOUT CONSTANTS - static const unsigned int timeoutIntervalHeartbeat = 3500 * 1000; ///< Heartbeat timeout is 2.5 seconds + static const unsigned int timeoutIntervalHeartbeat = 3500 * 1000; ///< Heartbeat timeout is 3.5 seconds }; diff --git a/src/uas/UASManager.cc b/src/uas/UASManager.cc index 4a38fe22472bdb997a8ff50f1be1175627ce5f7f..fe2fd53daf83742b6cf61039ef9efb5caa5c090d 100644 --- a/src/uas/UASManager.cc +++ b/src/uas/UASManager.cc @@ -230,21 +230,22 @@ void UASManager::nedToWgs84(const double& x, const double& y, const double& z, d */ void UASManager::uavChangedHomePosition(int uav, double lat, double lon, double alt) { - // FIXME: Accept any home position change for now from the active UAS - // this means that the currently select UAS can change the home location - // of the whole swarm. This makes sense, but more control might be needed + // Accept home position changes from the active UAS if (uav == activeUAS->getUASID()) { if (setHomePosition(lat, lon, alt)) { - foreach (UASInterface* mav, systems) - { - // Only update the other systems, not the original source - if (mav->getUASID() != uav) - { - mav->setHomePosition(homeLat, homeLon, homeAlt); - } - } + // XXX DO NOT UPDATE THE WHOLE FLEET + + +// foreach (UASInterface* mav, systems) +// { +// // Only update the other systems, not the original source +// if (mav->getUASID() != uav) +// { +// mav->setHomePosition(homeLat, homeLon, homeAlt); +// } +// } } } } diff --git a/src/uas/UASWaypointManager.cc b/src/uas/UASWaypointManager.cc index 6202798cc3168ed9383a2e3552414839f85d4407..4dcadb7b4f287c7e148830f0b6acd3a9801b70ed 100644 --- a/src/uas/UASWaypointManager.cc +++ b/src/uas/UASWaypointManager.cc @@ -153,7 +153,8 @@ void UASWaypointManager::handleWaypointCount(quint8 systemId, quint8 compId, qui sendWaypointRequest(current_wp_id); } else { protocol_timer.stop(); - emit updateStatusString("done."); + QTime time = QTime::currentTime(); + emit updateStatusString(tr("Done. (updated at %1)").arg(time.toString())); current_state = WP_IDLE; current_count = 0; current_wp_id = 0; @@ -163,7 +164,7 @@ void UASWaypointManager::handleWaypointCount(quint8 systemId, quint8 compId, qui } else { - qDebug("Rejecting message, check mismatch: current_state: %d == %d, system id %d == %d, comp id %d == %d", current_state, WP_GETLIST, current_partner_systemid, systemId, current_partner_compid, compId); + qDebug("Rejecting waypoint count message, check mismatch: current_state: %d == %d, system id %d == %d, comp id %d == %d", current_state, WP_GETLIST, current_partner_systemid, systemId, current_partner_compid, compId); } } @@ -204,15 +205,14 @@ void UASWaypointManager::handleWaypoint(quint8 systemId, quint8 compId, mavlink_ protocol_timer.stop(); emit readGlobalWPFromUAS(false); QTime time = QTime::currentTime(); - QString timeString = time.toString(); - emit updateStatusString(tr("done. (updated at %1)").arg(timeString)); + emit updateStatusString(tr("Done. (updated at %1)").arg(time.toString())); } } else { emit updateStatusString(tr("Waypoint ID mismatch, rejecting waypoint")); } } else { - qDebug("Rejecting message, check mismatch: current_state: %d == %d, system id %d == %d, comp id %d == %d", current_state, WP_GETLIST, current_partner_systemid, systemId, current_partner_compid, compId); + qDebug("Rejecting waypoint message, check mismatch: current_state: %d == %d, system id %d == %d, comp id %d == %d", current_state, WP_GETLIST_GETWPS, current_partner_systemid, systemId, current_partner_compid, compId); } } @@ -223,23 +223,50 @@ void UASWaypointManager::handleWaypointAck(quint8 systemId, quint8 compId, mavli //all waypoints sent and ack received protocol_timer.stop(); current_state = WP_IDLE; - readWaypoints(false); //Update "Onboard Waypoints"-tab immidiately after the waypoint list has been sent. - emit updateStatusString("done."); + readWaypoints(false); //Update "Onboard Waypoints"-tab immediately after the waypoint list has been sent. + QTime time = QTime::currentTime(); + emit updateStatusString(tr("Done. (updated at %1)").arg(time.toString())); } else if((current_state == WP_SENDLIST || current_state == WP_SENDLIST_SENDWPS) && wpa->type != 0) { //give up transmitting if a WP is rejected - if (wpa->type == 1) { - emit updateStatusString("upload failed: general error"); - } else if (wpa->type == 2) { - emit updateStatusString("upload failed: coordinate frame unsupported."); - } else { - emit updateStatusString("upload failed: other error."); + switch (wpa->type) + { + case MAV_MISSION_UNSUPPORTED_FRAME: + emit updateStatusString(tr("ERROR: Coordinate frame unsupported.")); + break; + case MAV_MISSION_UNSUPPORTED: + emit updateStatusString(tr("ERROR: Unsupported command.")); + break; + case MAV_MISSION_NO_SPACE: + emit updateStatusString(tr("ERROR: Mission count exceeds storage.")); + break; + case MAV_MISSION_INVALID: + case MAV_MISSION_INVALID_PARAM1: + case MAV_MISSION_INVALID_PARAM2: + case MAV_MISSION_INVALID_PARAM3: + case MAV_MISSION_INVALID_PARAM4: + case MAV_MISSION_INVALID_PARAM5_X: + case MAV_MISSION_INVALID_PARAM6_Y: + case MAV_MISSION_INVALID_PARAM7: + emit updateStatusString(tr("ERROR: A specified parameter was invalid.")); + break; + case MAV_MISSION_INVALID_SEQUENCE: + emit updateStatusString(tr("ERROR: Mission received out of sequence.")); + break; + case MAV_MISSION_DENIED: + emit updateStatusString(tr("ERROR: UAS not accepting missions.")); + break; + case MAV_MISSION_ERROR: + default: + emit updateStatusString(tr("ERROR: Unspecified error")); + break; } protocol_timer.stop(); current_state = WP_IDLE; } else if(current_state == WP_CLEARLIST) { protocol_timer.stop(); current_state = WP_IDLE; - emit updateStatusString("done."); + QTime time = QTime::currentTime(); + emit updateStatusString(tr("Done. (updated at %1)").arg(time.toString())); } } } @@ -258,7 +285,7 @@ void UASWaypointManager::handleWaypointRequest(quint8 systemId, quint8 compId, m //TODO: Error message or something } } else { - qDebug("Rejecting message, check mismatch: current_state: %d == %d, system id %d == %d, comp id %d == %d", current_state, WP_GETLIST, current_partner_systemid, systemId, current_partner_compid, compId); + qDebug("Rejecting waypoint request message, check mismatch: current_state: %d == %d, system id %d == %d, comp id %d == %d", current_state, WP_SENDLIST_SENDWPS, current_partner_systemid, systemId, current_partner_compid, compId); } } @@ -267,7 +294,7 @@ void UASWaypointManager::handleWaypointReached(quint8 systemId, quint8 compId, m Q_UNUSED(compId); if (!uas) return; if (systemId == uasid) { - emit updateStatusString(QString("Reached waypoint %1").arg(wpr->seq)); + emit updateStatusString(tr("Reached waypoint %1").arg(wpr->seq)); } } @@ -292,7 +319,7 @@ void UASWaypointManager::handleWaypointCurrent(quint8 systemId, quint8 compId, m } } } - emit updateStatusString(QString("New current waypoint %1").arg(wpc->seq)); + emit updateStatusString(tr("New current waypoint %1").arg(wpc->seq)); //emit update to UI widgets emit currentWaypointChanged(wpc->seq); } @@ -347,7 +374,7 @@ int UASWaypointManager::setCurrentEditable(quint16 seq) if (seq < waypointsEditable.count()) { if(current_state == WP_IDLE) { //update local main storage - for(int i = 0; i < waypointsEditable.count(); i++) { + for (int i = 0; i < waypointsEditable.count(); i++) { if (waypointsEditable[i]->getId() == seq) { waypointsEditable[i]->setCurrent(true); } else { @@ -921,94 +948,91 @@ void UASWaypointManager::writeWaypoints() } else { - //we're in another transaction, ignore command - qDebug() << "UASWaypointManager::sendWaypoints() doing something else ignoring command"; + // We're in another transaction, ignore command + qDebug() << tr("UASWaypointManager::sendWaypoints() doing something else. Ignoring command"); } } void UASWaypointManager::sendWaypointClearAll() { if (!uas) return; - mavlink_message_t message; - mavlink_mission_clear_all_t wpca; - - wpca.target_system = uasid; - wpca.target_component = MAV_COMP_ID_MISSIONPLANNER; - - emit updateStatusString(QString("Clearing waypoint list...")); + // Send the message. + mavlink_message_t message; + mavlink_mission_clear_all_t wpca = {(quint8)uasid, MAV_COMP_ID_MISSIONPLANNER}; mavlink_msg_mission_clear_all_encode(uas->mavlink->getSystemId(), uas->mavlink->getComponentId(), &message, &wpca); - uas->sendMessage(message); + + // And update the UI. + emit updateStatusString(tr("Clearing waypoint list...")); + QGC::SLEEP::msleep(PROTOCOL_DELAY_MS); } void UASWaypointManager::sendWaypointSetCurrent(quint16 seq) { if (!uas) return; - mavlink_message_t message; - mavlink_mission_set_current_t wpsc; - - wpsc.target_system = uasid; - wpsc.target_component = MAV_COMP_ID_MISSIONPLANNER; - wpsc.seq = seq; - - emit updateStatusString(QString("Updating target waypoint...")); + // Send the message. + mavlink_message_t message; + mavlink_mission_set_current_t wpsc = {seq, (quint8)uasid, MAV_COMP_ID_MISSIONPLANNER}; mavlink_msg_mission_set_current_encode(uas->mavlink->getSystemId(), uas->mavlink->getComponentId(), &message, &wpsc); uas->sendMessage(message); + + // And update the UI. + emit updateStatusString(tr("Updating target waypoint...")); + QGC::SLEEP::msleep(PROTOCOL_DELAY_MS); } void UASWaypointManager::sendWaypointCount() { if (!uas) return; - mavlink_message_t message; - mavlink_mission_count_t wpc; - - wpc.target_system = uasid; - wpc.target_component = MAV_COMP_ID_MISSIONPLANNER; - wpc.count = current_count; - emit updateStatusString(QString("Starting to transmit waypoints...")); + // Tell the UAS how many missions we'll sending. + mavlink_message_t message; + mavlink_mission_count_t wpc = {current_count, (quint8)uasid, MAV_COMP_ID_MISSIONPLANNER}; mavlink_msg_mission_count_encode(uas->mavlink->getSystemId(), uas->mavlink->getComponentId(), &message, &wpc); uas->sendMessage(message); + + // And update the UI. + emit updateStatusString(tr("Starting to transmit waypoints...")); + QGC::SLEEP::msleep(PROTOCOL_DELAY_MS); } void UASWaypointManager::sendWaypointRequestList() { if (!uas) return; - mavlink_message_t message; - mavlink_mission_request_list_t wprl; - wprl.target_system = uasid; - wprl.target_component = MAV_COMP_ID_MISSIONPLANNER; + // Send a MISSION_REQUEST message to the uas for this mission manager, using the MISSIONPLANNER component. + mavlink_message_t message; + mavlink_mission_request_list_t wprl = {(quint8)uasid, MAV_COMP_ID_MISSIONPLANNER}; + mavlink_msg_mission_request_list_encode(uas->mavlink->getSystemId(), uas->mavlink->getComponentId(), &message, &wprl); + uas->sendMessage(message); + // And update the UI. QString statusMsg(tr("Requesting waypoint list...")); qDebug() << __FILE__ << __LINE__ << statusMsg; emit updateStatusString(statusMsg); - mavlink_msg_mission_request_list_encode(uas->mavlink->getSystemId(), uas->mavlink->getComponentId(), &message, &wprl); - uas->sendMessage(message); QGC::SLEEP::msleep(PROTOCOL_DELAY_MS); } void UASWaypointManager::sendWaypointRequest(quint16 seq) { if (!uas) return; - mavlink_message_t message; - mavlink_mission_request_t wpr; - - wpr.target_system = uasid; - wpr.target_component = MAV_COMP_ID_MISSIONPLANNER; - wpr.seq = seq; - - emit updateStatusString(QString("Retrieving waypoint ID %1 of %2 total").arg(wpr.seq).arg(current_count)); + // Send a MISSION_REQUEST message to the UAS's MISSIONPLANNER component. + mavlink_message_t message; + mavlink_mission_request_t wpr = {seq, (quint8)uasid, MAV_COMP_ID_MISSIONPLANNER}; mavlink_msg_mission_request_encode(uas->mavlink->getSystemId(), uas->mavlink->getComponentId(), &message, &wpr); uas->sendMessage(message); + + // And update the UI. + emit updateStatusString(tr("Retrieving waypoint ID %1 of %2").arg(wpr.seq).arg(current_count)); + QGC::SLEEP::msleep(PROTOCOL_DELAY_MS); } @@ -1019,18 +1043,18 @@ void UASWaypointManager::sendWaypoint(quint16 seq) if (seq < waypoint_buffer.count()) { - mavlink_mission_item_t *wp; - - - wp = waypoint_buffer.at(seq); + // Fetch the current mission to send, and set it to apply to the curent UAS. + mavlink_mission_item_t *wp = waypoint_buffer.at(seq); wp->target_system = uasid; wp->target_component = MAV_COMP_ID_MISSIONPLANNER; - emit updateStatusString(QString("Sending waypoint ID %1 of %2 total").arg(wp->seq).arg(current_count)); - - + // Transmit the new mission mavlink_msg_mission_item_encode(uas->mavlink->getSystemId(), uas->mavlink->getComponentId(), &message, wp); uas->sendMessage(message); + + // And update the UI. + emit updateStatusString(tr("Sending waypoint ID %1 of %2 total").arg(wp->seq).arg(current_count)); + QGC::SLEEP::msleep(PROTOCOL_DELAY_MS); } } @@ -1038,15 +1062,13 @@ void UASWaypointManager::sendWaypoint(quint16 seq) void UASWaypointManager::sendWaypointAck(quint8 type) { if (!uas) return; - mavlink_message_t message; - mavlink_mission_ack_t wpa; - - wpa.target_system = uasid; - wpa.target_component = MAV_COMP_ID_MISSIONPLANNER; - wpa.type = type; + // Send the message. + mavlink_message_t message; + mavlink_mission_ack_t wpa = {(quint8)uasid, MAV_COMP_ID_MISSIONPLANNER, type}; mavlink_msg_mission_ack_encode(uas->mavlink->getSystemId(), uas->mavlink->getComponentId(), &message, &wpa); uas->sendMessage(message); + QGC::SLEEP::msleep(PROTOCOL_DELAY_MS); } diff --git a/src/uas/UASWaypointManager.h b/src/uas/UASWaypointManager.h index 296f477ce0dfbb057bf480770483cce63ad77b6f..5c4f8e2cd61864ab85dd8cbcc5b89bafda0e6358 100644 --- a/src/uas/UASWaypointManager.h +++ b/src/uas/UASWaypointManager.h @@ -177,7 +177,7 @@ private: QList waypoint_buffer; ///< buffer for waypoints during communication QTimer protocol_timer; ///< Timer to catch timeouts bool standalone; ///< If standalone is set, do not write to UAS - quint16 uasid; + int uasid; ///< The ID of the current UAS. Retrieved via `uas->getUASID();`, stored as an `int` to match its return type. // XXX export to settings static const float defaultAltitudeHomeOffset; ///< Altitude offset in meters from home for new waypoints diff --git a/src/uas/senseSoarMAV.cpp b/src/uas/senseSoarMAV.cpp index fee48386293e4b015bfd3ebee84f1a968cddb3ad..234a16be015822d273fbe3db0d4358552fd11dbe 100644 --- a/src/uas/senseSoarMAV.cpp +++ b/src/uas/senseSoarMAV.cpp @@ -2,8 +2,8 @@ #include #include -senseSoarMAV::senseSoarMAV(MAVLinkProtocol* mavlink, int id) - : UAS(mavlink, id), senseSoarState(0) +senseSoarMAV::senseSoarMAV(MAVLinkProtocol* mavlink, QThread* thread, int id) + : UAS(mavlink, thread, id), senseSoarState(0) { } diff --git a/src/uas/senseSoarMAV.h b/src/uas/senseSoarMAV.h index faf9013c1aafc0e6c35a86fd3be49df3a369fe16..0076eb1d69d2e95c898e75c466242ee1509712d6 100644 --- a/src/uas/senseSoarMAV.h +++ b/src/uas/senseSoarMAV.h @@ -14,7 +14,7 @@ class senseSoarMAV : public UAS Q_INTERFACES(UASInterface) public: - senseSoarMAV(MAVLinkProtocol* mavlink, int id); + senseSoarMAV(MAVLinkProtocol* mavlink, QThread* thread, int id); ~senseSoarMAV(void); public slots: /** @brief Receive a MAVLink message from this MAV */ diff --git a/src/ui/MAVLinkDecoder.cc b/src/ui/MAVLinkDecoder.cc index 2b3798271aa5b83b7f027426ebc5dcb99f7d8778..a0571cc06b4bb983d29da2f1e4bc08f66f1d270f 100644 --- a/src/ui/MAVLinkDecoder.cc +++ b/src/ui/MAVLinkDecoder.cc @@ -2,8 +2,13 @@ #include "UASManager.h" MAVLinkDecoder::MAVLinkDecoder(MAVLinkProtocol* protocol, QObject *parent) : - QObject(parent) + QThread() { + Q_UNUSED(parent); + // We're doing it wrong - because the Qt folks got the API wrong: + // http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/ + moveToThread(this); + mavlink_message_info_t msg[256] = MAVLINK_MESSAGE_INFO; memcpy(messageInfo, msg, sizeof(mavlink_message_info_t)*256); memset(receivedMessages, 0, sizeof(mavlink_message_t)*256); @@ -46,6 +51,17 @@ MAVLinkDecoder::MAVLinkDecoder(MAVLinkProtocol* protocol, QObject *parent) : // textMessageFilter.insert(MAVLINK_MSG_ID_HIGHRES_IMU, false); connect(protocol, SIGNAL(messageReceived(LinkInterface*,mavlink_message_t)), this, SLOT(receiveMessage(LinkInterface*,mavlink_message_t))); + + start(LowPriority); +} + +/** + * @brief Runs the thread + * + **/ +void MAVLinkDecoder::run() +{ + exec(); } void MAVLinkDecoder::receiveMessage(LinkInterface* link,mavlink_message_t message) diff --git a/src/ui/MAVLinkDecoder.h b/src/ui/MAVLinkDecoder.h index 2feaa63978a386fa759e7c6345064ec014a2c10d..8eb35fd417bd50306f6280791e401d9380b2f842 100644 --- a/src/ui/MAVLinkDecoder.h +++ b/src/ui/MAVLinkDecoder.h @@ -4,12 +4,14 @@ #include #include "MAVLinkProtocol.h" -class MAVLinkDecoder : public QObject +class MAVLinkDecoder : public QThread { Q_OBJECT public: MAVLinkDecoder(MAVLinkProtocol* protocol, QObject *parent = 0); + void run(); + signals: void textMessageReceived(int uasid, int componentid, int severity, const QString& text); void valueChanged(const int uasId, const QString& name, const QString& unit, const QVariant& value, const quint64 msec); diff --git a/src/ui/MAVLinkSettingsWidget.cc b/src/ui/MAVLinkSettingsWidget.cc index 71e090fcce6674c34012195af406c23efe31460b..a630c92c97533322827063e00a2c2bf695dfc173 100644 --- a/src/ui/MAVLinkSettingsWidget.cc +++ b/src/ui/MAVLinkSettingsWidget.cc @@ -47,6 +47,12 @@ MAVLinkSettingsWidget::MAVLinkSettingsWidget(MAVLinkProtocol* protocol, QWidget m_ui->gridLayout->setAlignment(Qt::AlignTop); + // AUTH + m_ui->droneOSCheckBox->setChecked(protocol->getAuthEnabled()); + QSettings settings; + m_ui->droneOSComboBox->setCurrentIndex(m_ui->droneOSComboBox->findText(settings.value("DRONEOS_HOST", "droneos.com:14555").toString())); + m_ui->droneOSLineEdit->setText(protocol->getAuthKey()); + // Initialize state m_ui->heartbeatCheckBox->setChecked(protocol->heartbeatsEnabled()); m_ui->loggingCheckBox->setChecked(protocol->loggingEnabled()); @@ -61,12 +67,6 @@ MAVLinkSettingsWidget::MAVLinkSettingsWidget(MAVLinkProtocol* protocol, QWidget m_ui->actionGuardCheckBox->setChecked(protocol->actionGuardEnabled()); m_ui->actionRetransmissionSpinBox->setValue(protocol->getActionRetransmissionTimeout()); - // AUTH - m_ui->droneOSCheckBox->setChecked(protocol->getAuthEnabled()); - QSettings settings; - m_ui->droneOSComboBox->setCurrentIndex(m_ui->droneOSComboBox->findText(settings.value("DRONEOS_HOST", "droneos.com:14555").toString())); - m_ui->droneOSLineEdit->setText(protocol->getAuthKey()); - // Connect actions // Heartbeat connect(protocol, SIGNAL(heartbeatChanged(bool)), m_ui->heartbeatCheckBox, SLOT(setChecked(bool))); @@ -144,11 +144,6 @@ MAVLinkSettingsWidget::MAVLinkSettingsWidget(MAVLinkProtocol* protocol, QWidget // and then remove these two lines m_ui->multiplexingFilterCheckBox->setVisible(false); m_ui->multiplexingFilterLineEdit->setVisible(false); - -// // Update settings -// m_ui->loggingCheckBox->setChecked(protocol->loggingEnabled()); -// m_ui->heartbeatCheckBox->setChecked(protocol->heartbeatsEnabled()); -// m_ui->versionCheckBox->setChecked(protocol->versionCheckEnabled()); } void MAVLinkSettingsWidget::updateLogfileName(const QString& fileName) diff --git a/src/ui/MainWindow.cc b/src/ui/MainWindow.cc index 2d22446c12667dc137df74cd3192afb29e64f958..c631202b49d45025514312982a34bb27b5ac579b 100644 --- a/src/ui/MainWindow.cc +++ b/src/ui/MainWindow.cc @@ -188,7 +188,7 @@ void MainWindow::init() ui.setupUi(this); hide(); menuActionHelper->setMenu(ui.menuTools); - + // Qt 4 on Ubuntu does place the native menubar correctly so on Linux we revert back to in-window menu bar. #ifdef Q_OS_LINUX menuBar()->setNativeMenuBar(false); @@ -224,6 +224,7 @@ void MainWindow::init() actions << ui.actionFlightView; actions << ui.actionMissionView; actions << ui.actionHardwareConfig; + toolBar->setPerspectiveChangeActions(actions); // Add actions for advanced users (displayed in dropdown under "advanced") @@ -347,6 +348,27 @@ void MainWindow::init() } + // Set OS dependent keyboard shortcuts for the main window, non OS dependent shortcuts are set in MainWindow.ui +#ifdef Q_OS_MACX + ui.actionFlightView->setShortcut(QApplication::translate("MainWindow", "Meta+1", 0, QApplication::UnicodeUTF8)); + ui.actionMissionView->setShortcut(QApplication::translate("MainWindow", "Meta+2", 0, QApplication::UnicodeUTF8)); + ui.actionHardwareConfig->setShortcut(QApplication::translate("MainWindow", "Meta+3", 0, QApplication::UnicodeUTF8)); + ui.actionSimulationView->setShortcut(QApplication::translate("MainWindow", "Meta+4", 0, QApplication::UnicodeUTF8)); + ui.actionEngineersView->setShortcut(QApplication::translate("MainWindow", "Meta+5", 0, QApplication::UnicodeUTF8)); + ui.actionMavlinkView->setShortcut(QApplication::translate("MainWindow", "Meta+M", 0, QApplication::UnicodeUTF8)); + ui.actionUnconnectedView->setShortcut(QApplication::translate("MainWindow", "Meta+U", 0, QApplication::UnicodeUTF8)); + ui.actionFullscreen->setShortcut(QApplication::translate("MainWindow", "Meta+Return", 0, QApplication::UnicodeUTF8)); +#else + ui.actionFlightView->setShortcut(QApplication::translate("MainWindow", "Ctrl+1", 0, QApplication::UnicodeUTF8)); + ui.actionMissionView->setShortcut(QApplication::translate("MainWindow", "Ctrl+2", 0, QApplication::UnicodeUTF8)); + ui.actionHardwareConfig->setShortcut(QApplication::translate("MainWindow", "Ctrl+3", 0, QApplication::UnicodeUTF8)); + ui.actionSimulationView->setShortcut(QApplication::translate("MainWindow", "Ctrl+4", 0, QApplication::UnicodeUTF8)); + ui.actionEngineersView->setShortcut(QApplication::translate("MainWindow", "Ctrl+5", 0, QApplication::UnicodeUTF8)); + ui.actionMavlinkView->setShortcut(QApplication::translate("MainWindow", "Ctrl+M", 0, QApplication::UnicodeUTF8)); + ui.actionUnconnectedView->setShortcut(QApplication::translate("MainWindow", "Ctrl+U", 0, QApplication::UnicodeUTF8)); + ui.actionFullscreen->setShortcut(QApplication::translate("MainWindow", "Ctrl+Return", 0, QApplication::UnicodeUTF8)); +#endif + connect(&windowNameUpdateTimer, SIGNAL(timeout()), this, SLOT(configureWindowName())); windowNameUpdateTimer.start(15000); emit initStatusChanged(tr("Done"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141)); @@ -740,6 +762,7 @@ void MainWindow::loadDockWidget(const QString& name) { if(menuActionHelper->containsDockWidget(currentView, name)) return; + if (name.startsWith("HIL_CONFIG")) { //It's a HIL widget. @@ -806,7 +829,7 @@ void MainWindow::loadDockWidget(const QString& name) } else if (name == "HEAD_UP_DISPLAY_DOCKWIDGET") { - createDockWidget(centerStack->currentWidget(),new HUD(320,240,this),tr("Head Up Display"),"HEAD_UP_DISPLAY_DOCKWIDGET",currentView,Qt::RightDockWidgetArea); + createDockWidget(centerStack->currentWidget(),new HUD(320,240,this),tr("Video Downlink"),"HEAD_UP_DISPLAY_DOCKWIDGET",currentView,Qt::RightDockWidgetArea); } else if (name == "UAS_INFO_QUICKVIEW_DOCKWIDGET") { @@ -1344,6 +1367,8 @@ void MainWindow::connectCommonActions() connect(ui.actionHardwareConfig,SIGNAL(triggered()),this,SLOT(loadHardwareConfigView())); connect(ui.actionGoogleEarthView, SIGNAL(triggered()), this, SLOT(loadGoogleEarthView())); connect(ui.actionLocal3DView, SIGNAL(triggered()), this, SLOT(loadLocal3DView())); + connect(ui.actionSimulationView, SIGNAL(triggered()), this, SLOT(loadSimulationView())); + connect(ui.actionHardwareConfig, SIGNAL(triggered()), this, SLOT(loadHardwareConfigView())); if (getCustomMode() == CUSTOM_MODE_APM) { connect(ui.actionSoftwareConfig,SIGNAL(triggered()),this,SLOT(loadSoftwareConfigView())); @@ -1494,21 +1519,11 @@ bool MainWindow::configLink(LinkInterface *link) void MainWindow::addLink(LinkInterface *link) { - - qDebug() << "ADD LINK CALLED FROM SOMEWHERE"; - // IMPORTANT! KEEP THESE TWO LINES // THEY MAKE SURE THE LINK IS PROPERLY REGISTERED // BEFORE LINKING THE UI AGAINST IT // Register (does nothing if already registered) LinkManager::instance()->add(link); - - if (mavlink) { - qDebug() << "MAVLINK OK"; - } else { - qDebug() << "MAVLINK FAIL"; - } - LinkManager::instance()->addProtocol(link, mavlink); // Go fishing for this link's configuration window diff --git a/src/ui/MainWindow.ui b/src/ui/MainWindow.ui index 523cbfd9a0930cf927674ab08f944a4c2c276183..3503841f65354c8a18259590a606994bd2f574a0 100644 --- a/src/ui/MainWindow.ui +++ b/src/ui/MainWindow.ui @@ -12,8 +12,8 @@ - 1024 - 600 + 640 + 400 @@ -162,7 +162,7 @@ Emergency Land - Ctrl+E + Ctrl+L @@ -284,9 +284,6 @@ Mission - - Meta+O - @@ -299,9 +296,6 @@ Plot - - Meta+E - @@ -314,9 +308,6 @@ Mavlink - - Meta+M - @@ -329,9 +320,6 @@ Flight - - Meta+P - @@ -369,9 +357,6 @@ Unconnected - - Meta+U - @@ -397,9 +382,6 @@ Fullscreen - - Meta+Return - diff --git a/src/ui/PrimaryFlightDisplay.cc b/src/ui/PrimaryFlightDisplay.cc index 35063a38065519e3fb6f17b92fc0e236fee8e756..c22fbf30efa2d396ed3c958fea20155c5a57ffa1 100644 --- a/src/ui/PrimaryFlightDisplay.cc +++ b/src/ui/PrimaryFlightDisplay.cc @@ -110,6 +110,9 @@ const QString PrimaryFlightDisplay::compassWindNames[] = { PrimaryFlightDisplay::PrimaryFlightDisplay(int width, int height, QWidget *parent) : QWidget(parent), + _valuesChanged(false), + _valuesLastPainted(QGC::groundTimeMilliseconds()), + uas(NULL), roll(0), @@ -159,7 +162,7 @@ PrimaryFlightDisplay::PrimaryFlightDisplay(int width, int height, QWidget *paren // Refresh timer refreshTimer->setInterval(updateInterval); // connect(refreshTimer, SIGNAL(timeout()), this, SLOT(paintHUD())); - connect(refreshTimer, SIGNAL(timeout()), this, SLOT(update())); + connect(refreshTimer, SIGNAL(timeout()), this, SLOT(checkUpdate())); } PrimaryFlightDisplay::~PrimaryFlightDisplay() @@ -224,6 +227,15 @@ void PrimaryFlightDisplay::paintEvent(QPaintEvent *event) doPaint(); } +void PrimaryFlightDisplay::checkUpdate() +{ + if (uas && (_valuesChanged || (QGC::groundTimeMilliseconds() - _valuesLastPainted) > 260)) { + update(); + _valuesChanged = false; + _valuesLastPainted = QGC::groundTimeMilliseconds(); + } +} + ///* // * Interface towards qgroundcontrol // */ @@ -280,24 +292,45 @@ void PrimaryFlightDisplay::updateAttitude(UASInterface* uas, double roll, double { Q_UNUSED(uas); Q_UNUSED(timestamp); + // Called from UAS.cc l. 616 if (isinf(roll)) { this->roll = std::numeric_limits::quiet_NaN(); } else { - this->roll = roll * (180.0 / M_PI); + + float rolldeg = roll * (180.0 / M_PI); + + if (fabsf(roll - rolldeg) > 2.5f) { + _valuesChanged = true; + } + + this->roll = rolldeg; } if (isinf(pitch)) { this->pitch = std::numeric_limits::quiet_NaN(); } else { - this->pitch = pitch * (180.0 / M_PI); + + float pitchdeg = pitch * (180.0 / M_PI); + + if (fabsf(pitch - pitchdeg) > 2.5f) { + _valuesChanged = true; + } + + this->pitch = pitchdeg; } if (isinf(yaw)) { this->heading = std::numeric_limits::quiet_NaN(); } else { + yaw = yaw * (180.0 / M_PI); if (yaw<0) yaw+=360; + + if (fabsf(heading - yaw) > 10.0f) { + _valuesChanged = true; + } + this->heading = yaw; } @@ -314,6 +347,14 @@ void PrimaryFlightDisplay::updateSpeed(UASInterface* uas, double _groundSpeed, d Q_UNUSED(uas); Q_UNUSED(timestamp); + if (fabsf(groundSpeed - _groundSpeed) > 0.5f) { + _valuesChanged = true; + } + + if (fabsf(airSpeed - _airSpeed) > 1.0f) { + _valuesChanged = true; + } + groundSpeed = _groundSpeed; airSpeed = _airSpeed; } @@ -321,6 +362,19 @@ void PrimaryFlightDisplay::updateSpeed(UASInterface* uas, double _groundSpeed, d void PrimaryFlightDisplay::updateAltitude(UASInterface* uas, double _altitudeAMSL, double _altitudeRelative, double _climbRate, quint64 timestamp) { Q_UNUSED(uas); Q_UNUSED(timestamp); + + if (fabsf(altitudeAMSL - _altitudeAMSL) > 0.5f) { + _valuesChanged = true; + } + + if (fabsf(altitudeRelative - _altitudeRelative) > 0.5f) { + _valuesChanged = true; + } + + if (fabsf(climbRate - _climbRate) > 0.5f) { + _valuesChanged = true; + } + altitudeAMSL = _altitudeAMSL; altitudeRelative = _altitudeRelative; climbRate = _climbRate; diff --git a/src/ui/PrimaryFlightDisplay.h b/src/ui/PrimaryFlightDisplay.h index 9dfb8c3ecf2f6c9b9931d1701b39618f758a0a1b..b4236e339a400cc994d7de0613d2025a3be7f16e 100644 --- a/src/ui/PrimaryFlightDisplay.h +++ b/src/ui/PrimaryFlightDisplay.h @@ -27,7 +27,13 @@ public slots: void forgetUAS(UASInterface* uas); void setActiveUAS(UASInterface* uas); + void checkUpdate(); + protected: + + bool _valuesChanged; + quint64 _valuesLastPainted; + enum Layout { COMPASS_INTEGRATED, COMPASS_SEPARATED // For a very high container. Feature panels are at bottom. diff --git a/src/ui/QGCHilFlightGearConfiguration.ui b/src/ui/QGCHilFlightGearConfiguration.ui index c91f992ac7de984ff0d31588d051ebdbf450b112..0bac42142b42670f0fdd8f1bdc3b3d50a75ba128 100644 --- a/src/ui/QGCHilFlightGearConfiguration.ui +++ b/src/ui/QGCHilFlightGearConfiguration.ui @@ -68,7 +68,7 @@ - --roll=0 --pitch=0 --vc=0 --heading=300 --timeofday=noon --disable-hud-3d --disable-fullscreen --geometry=400x300 --disable-anti-alias-hud --wind=0@0 --turbulence=0.0 --prop:/sim/frame-rate-throttle-hz=30 --control=mouse --disable-sound --disable-random-objects --disable-ai-models --shading-flat --fog-disable --disable-specular-highlight --disable-random-objects --disable-panel --disable-clouds --fdm=jsb --units-meters --prop:/engines/engine/running=true + --roll=0 --pitch=0 --vc=0 --heading=300 --timeofday=noon --disable-hud-3d --disable-fullscreen --geometry=400x300 --disable-anti-alias-hud --wind=0@0 --turbulence=0.0 --control=mouse --disable-sound --disable-random-objects --disable-ai-models --shading-flat --fog-disable --disable-specular-highlight --disable-random-objects --disable-panel --disable-clouds --fdm=jsb --units-meters --prop:/engines/engine/running=true diff --git a/src/ui/QGCHilXPlaneConfiguration.cc b/src/ui/QGCHilXPlaneConfiguration.cc index 4166d7e662c04d5cd449580303676953691b4165..dc1cd52b6ac278818cec038382119fe5272e3171 100644 --- a/src/ui/QGCHilXPlaneConfiguration.cc +++ b/src/ui/QGCHilXPlaneConfiguration.cc @@ -25,8 +25,9 @@ QGCHilXPlaneConfiguration::QGCHilXPlaneConfiguration(QGCHilLink* link, QWidget * { // connect(ui->randomAttitudeButton, SIGNAL(clicked()), link, SLOT(setRandomAttitude())); // connect(ui->randomPositionButton, SIGNAL(clicked()), link, SLOT(setRandomPosition())); - connect(ui->airframeComboBox, SIGNAL(activated(QString)), link, SLOT(selectAirframe(QString))); + ui->airframeComboBox->setCurrentIndex(link->getAirFrameIndex()); + connect(ui->airframeComboBox, SIGNAL(activated(QString)), link, SLOT(selectAirframe(QString))); // XXX not implemented yet ui->airframeComboBox->hide(); ui->sensorHilCheckBox->setChecked(xplane->sensorHilEnabled()); diff --git a/src/ui/QGCMAVLinkInspector.cc b/src/ui/QGCMAVLinkInspector.cc index 25bb8c1bbb6798b8c9d7db5246d04973b796599e..82c6464afa787f5fe870b2bfc0dcbc43db40865b 100644 --- a/src/ui/QGCMAVLinkInspector.cc +++ b/src/ui/QGCMAVLinkInspector.cc @@ -12,6 +12,7 @@ const unsigned int QGCMAVLinkInspector::updateInterval = 1000U; QGCMAVLinkInspector::QGCMAVLinkInspector(MAVLinkProtocol* protocol, QWidget *parent) : QWidget(parent), + _protocol(protocol), selectedSystemID(0), selectedComponentID(0), ui(new Ui::QGCMAVLinkInspector) @@ -36,13 +37,23 @@ QGCMAVLinkInspector::QGCMAVLinkInspector(MAVLinkProtocol* protocol, QWidget *par header << tr("Type"); ui->treeWidget->setHeaderLabels(header); + // Set up the column headers for the rate listing + QStringList rateHeader; + rateHeader << tr("Name"); + rateHeader << tr("#ID"); + rateHeader << tr("Rate"); + ui->rateTreeWidget->setHeaderLabels(rateHeader); + connect(ui->rateTreeWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)), + this, SLOT(rateTreeItemChanged(QTreeWidgetItem*,int))); + ui->rateTreeWidget->hide(); + // Connect the UI connect(ui->systemComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(selectDropDownMenuSystem(int))); connect(ui->componentComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(selectDropDownMenuComponent(int))); connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clearView())); // Connect external connections - connect(UASManager::instance(), SIGNAL(UASCreated(UASInterface*)), this, SLOT(addSystem(UASInterface*))); +// connect(UASManager::instance(), SIGNAL(UASCreated(UASInterface*)), this, SLOT(addSystem(UASInterface*))); connect(protocol, SIGNAL(messageReceived(LinkInterface*,mavlink_message_t)), this, SLOT(receiveMessage(LinkInterface*,mavlink_message_t))); // Attach the UI's refresh rate to a timer. @@ -59,29 +70,31 @@ void QGCMAVLinkInspector::selectDropDownMenuSystem(int dropdownid) { selectedSystemID = ui->systemComboBox->itemData(dropdownid).toInt(); rebuildComponentList(); + + if (selectedSystemID != 0 && selectedComponentID != 0) { + ui->rateTreeWidget->show(); + } else { + ui->rateTreeWidget->hide(); + } } void QGCMAVLinkInspector::selectDropDownMenuComponent(int dropdownid) { selectedComponentID = ui->componentComboBox->itemData(dropdownid).toInt(); + + if (selectedSystemID != 0 && selectedComponentID != 0) { + ui->rateTreeWidget->show(); + } else { + ui->rateTreeWidget->hide(); + } } void QGCMAVLinkInspector::rebuildComponentList() { ui->componentComboBox->clear(); + components.clear(); - // Fill - UASInterface* uas = UASManager::instance()->getUASForId(selectedSystemID); - if (uas) - { - QMap components = uas->getComponents(); - - foreach (int id, components.keys()) - { - QString name = components.value(id); - ui->componentComboBox->addItem(name, id); - } - } + ui->componentComboBox->addItem(tr("All"), 0); } void QGCMAVLinkInspector::addComponent(int uas, int component, const QString& name) @@ -100,10 +113,12 @@ void QGCMAVLinkInspector::addComponent(int uas, int component, const QString& na void QGCMAVLinkInspector::clearView() { memset(receivedMessages, 0xFF, sizeof(mavlink_message_t)*256); + onboardMessageInterval.clear(); lastMessageUpdate.clear(); messagesHz.clear(); treeWidgetItems.clear(); ui->treeWidget->clear(); + ui->rateTreeWidget->clear(); } void QGCMAVLinkInspector::refreshView() @@ -145,6 +160,45 @@ void QGCMAVLinkInspector::refreshView() updateField(msg->msgid, i, message->child(i)); } } + + if (selectedSystemID == 0 || selectedComponentID == 0) + { + return; + } + + for (int i = 0; i < 256; ++i)//mavlink_message_t msg, receivedMessages) + { + const char* msgname = messageInfo[i].name; + + int namelen = strnlen(msgname, 5); + + if (namelen < 3) { + continue; + } + + if (!strcmp(msgname, "EMPTY")) { + continue; + } + + // Update the tree view + QString messageName("%1"); + messageName = messageName.arg(msgname); + if (!rateTreeWidgetItems.contains(i)) + { + QStringList fields; + fields << messageName; + fields << QString("%1").arg(i); + fields << "OFF / --- Hz"; + QTreeWidgetItem* widget = new QTreeWidgetItem(fields); + widget->setFlags(widget->flags() | Qt::ItemIsEditable); + rateTreeWidgetItems.insert(i, widget); + ui->rateTreeWidget->addTopLevelItem(widget); + } + + // Set Hz + //QTreeWidgetItem* message = rateTreeWidgetItems.value(i); + //message->setData(0, Qt::DisplayRole, QVariant(messageName)); + } } void QGCMAVLinkInspector::receiveMessage(LinkInterface* link,mavlink_message_t message) @@ -155,6 +209,17 @@ void QGCMAVLinkInspector::receiveMessage(LinkInterface* link,mavlink_message_t m // Only overwrite if system filter is set memcpy(receivedMessages+message.msgid, &message, sizeof(mavlink_message_t)); + // Add not yet seen systems / components + if (!systems.contains(message.sysid)) { + systems.insert(message.sysid, message.sysid); + ui->systemComboBox->addItem(tr("MAV%1").arg(message.sysid), message.sysid); + } + + if (!components.contains(message.compid)) { + components.insert(message.compid, message.compid); + ui->componentComboBox->addItem(tr("COMP%1").arg(message.compid), message.compid); + } + quint64 receiveTime = QGC::groundTimeMilliseconds(); if (lastMessageUpdate.contains(message.msgid)) { @@ -163,6 +228,54 @@ void QGCMAVLinkInspector::receiveMessage(LinkInterface* link,mavlink_message_t m } lastMessageUpdate.insert(message.msgid, receiveTime); + + if (selectedSystemID == 0 || selectedComponentID == 0) { + return; + } + + switch (message.msgid) { + case MAVLINK_MSG_ID_DATA_STREAM: + { + mavlink_data_stream_t stream; + mavlink_msg_data_stream_decode(&message, &stream); + onboardMessageInterval.insert(stream.stream_id, stream.message_rate); + } + break; + + } +} + +void QGCMAVLinkInspector::changeStreamInterval(int msgid, int interval) { + //REQUEST_DATA_STREAM + if (selectedSystemID == 0 || selectedComponentID == 0) { + return; + } + + mavlink_request_data_stream_t stream; + stream.target_system = selectedSystemID; + stream.target_component = selectedComponentID; + stream.req_stream_id = msgid; + stream.req_message_rate = interval; + stream.start_stop = (interval > 0); + + mavlink_message_t msg; + mavlink_msg_request_data_stream_encode(_protocol->getSystemId(), _protocol->getComponentId(), &msg, &stream); + + _protocol->sendMessage(msg); +} + +void QGCMAVLinkInspector::rateTreeItemChanged(QTreeWidgetItem* paramItem, int column) +{ + if (paramItem && column > 0) { + + int key = paramItem->data(1, Qt::DisplayRole).toInt(); + QVariant value = paramItem->data(2, Qt::DisplayRole); + float interval = 1000 / value.toFloat(); + + qDebug() << "Stream " << key << "interval" << interval; + + changeStreamInterval(key, interval); + } } QGCMAVLinkInspector::~QGCMAVLinkInspector() diff --git a/src/ui/QGCMAVLinkInspector.h b/src/ui/QGCMAVLinkInspector.h index 300c88ceb56dffa4cfa5f988071b42ce0297a622..e4e7820e813b13d134547880adcb7a82193acaee 100644 --- a/src/ui/QGCMAVLinkInspector.h +++ b/src/ui/QGCMAVLinkInspector.h @@ -35,14 +35,21 @@ public slots: /** @Brief Select a component through the drop down menu */ void selectDropDownMenuComponent(int dropdownid); + void rateTreeItemChanged(QTreeWidgetItem* paramItem, int column); + protected: + MAVLinkProtocol *_protocol; ///< MAVLink instance int selectedSystemID; ///< Currently selected system int selectedComponentID; ///< Currently selected component + QMap systems; ///< Already observed systems + QMap components; ///< Already observed components QMap lastMessageUpdate; ///< Used to switch between highlight and non-highlighting color QMap messagesHz; ///< Used to store update rate in Hz + QMap onboardMessageInterval; ///< Stores the onboard selected data rate QMap messageCount; ///< Used to store the message count mavlink_message_t receivedMessages[256]; ///< Available / known messages QMap treeWidgetItems; ///< Available tree widget items + QMap rateTreeWidgetItems; ///< Available rate tree widget items QTimer updateTimer; ///< Only update at 1 Hz to not overload the GUI mavlink_message_info_t messageInfo[256]; // Store the metadata for all available MAVLink messages. @@ -50,6 +57,8 @@ protected: void updateField(int msgid, int fieldid, QTreeWidgetItem* item); /** @brief Rebuild the list of components */ void rebuildComponentList(); + /** @brief Change the stream interval */ + void changeStreamInterval(int msgid, int interval); static const unsigned int updateInterval; static const float updateHzLowpass; diff --git a/src/ui/QGCMAVLinkInspector.ui b/src/ui/QGCMAVLinkInspector.ui index 54526512c6649e6946d211f0ea83be83357aa0bc..acff603eaa3d89c05d5252fe6f133807ff879eab 100644 --- a/src/ui/QGCMAVLinkInspector.ui +++ b/src/ui/QGCMAVLinkInspector.ui @@ -6,30 +6,33 @@ 0 0 - 400 + 658 300 Form - - + + 6 - - + + 6 + + + 6 + + + 6 + + + - System + Clear - - - - - - @@ -37,10 +40,10 @@ - - + + - Clear + System @@ -53,6 +56,21 @@ + + + + + 1 + + + + + + + + + + diff --git a/src/ui/QGCMAVLinkLogPlayer.cc b/src/ui/QGCMAVLinkLogPlayer.cc index 20f7649e71a0b61d1a1effbce2342b24a10a302f..3e7aa2f63963b9e0749ee15773a88ec0e8ec00bf 100644 --- a/src/ui/QGCMAVLinkLogPlayer.cc +++ b/src/ui/QGCMAVLinkLogPlayer.cc @@ -1,6 +1,7 @@ #include #include #include +#include #include "MainWindow.h" #include "SerialLink.h" @@ -10,17 +11,15 @@ QGCMAVLinkLogPlayer::QGCMAVLinkLogPlayer(MAVLinkProtocol* mavlink, QWidget *parent) : QWidget(parent), - lineCounter(0), - totalLines(0), - startTime(0), - endTime(0), - currentStartTime(0), + playbackStartTime(0), + logStartTime(0), + logEndTime(0), accelerationFactor(1.0f), mavlink(mavlink), logLink(NULL), loopCounter(0), mavlinkLogFormat(true), - binaryBaudRate(57600), + binaryBaudRate(defaultBinaryBaudRate), isPlaying(false), currPacketCount(0), lastLogDirectory(QDesktopServices::storageLocation(QDesktopServices::DesktopLocation)), @@ -44,7 +43,7 @@ QGCMAVLinkLogPlayer::QGCMAVLinkLogPlayer(MAVLinkProtocol* mavlink, QWidget *pare setAccelerationFactorInt(49); ui->speedSlider->setValue(49); - ui->positionSlider->setValue(ui->positionSlider->minimum()); + updatePositionSliderUi(0.0); ui->playButton->setEnabled(false); ui->speedSlider->setEnabled(false); @@ -53,6 +52,9 @@ QGCMAVLinkLogPlayer::QGCMAVLinkLogPlayer(MAVLinkProtocol* mavlink, QWidget *pare ui->logFileNameLabel->setEnabled(false); ui->logStatsLabel->setEnabled(false); + // Monitor for when the end of the log file is reached. This is done using signals because the main work is in a timer. + connect(this, SIGNAL(logFileEndReached()), &loopTimer, SLOT(stop())); + loadSettings(); } @@ -90,14 +92,18 @@ void QGCMAVLinkLogPlayer::play() { if (logFile.isOpen()) { + // Disable the log file selector button ui->selectFileButton->setEnabled(false); - if (logLink) + + // Make sure we aren't at the end of the file, if we are, reset to the beginning and play from there. + if (logFile.atEnd()) { - logLink->disconnect(); - LinkManager::instance()->removeLink(logLink); - delete logLink; + reset(); } - logLink = new MAVLinkSimulationLink(""); + + // Always correct the current start time such that the next message will play immediately at playback. + // We do this by subtracting the current file playback offset from now() + playbackStartTime = (quint64)QDateTime::currentMSecsSinceEpoch() - (logCurrentTime - logStartTime) / 1000; // Start timer if (mavlinkLogFormat) @@ -112,10 +118,10 @@ void QGCMAVLinkLogPlayer::play() // to guarantee the baud rate, then divide 1000 by the number of read // operations to obtain the interval in milliseconds int interval = 1000 / ((binaryBaudRate / 10) / len); - loopTimer.start(interval*accelerationFactor); + loopTimer.start(interval / accelerationFactor); } isPlaying = true; - ui->logStatsLabel->setText(tr("Started playing..")); + ui->playButton->setChecked(true); ui->playButton->setIcon(QIcon(":files/images/actions/media-playback-pause.svg")); } else @@ -133,44 +139,97 @@ void QGCMAVLinkLogPlayer::play() void QGCMAVLinkLogPlayer::pause() { - isPlaying = false; loopTimer.stop(); + isPlaying = false; ui->playButton->setIcon(QIcon(":files/images/actions/media-playback-start.svg")); + ui->playButton->setChecked(false); ui->selectFileButton->setEnabled(true); - if (logLink) - { - logLink->disconnect(); - LinkManager::instance()->removeLink(logLink); - delete logLink; - logLink = NULL; - } } -bool QGCMAVLinkLogPlayer::reset(int packetIndex) +void QGCMAVLinkLogPlayer::reset() +{ + pause(); + loopCounter = 0; + logFile.reset(); + + // Now update the position slider to its default location + updatePositionSliderUi(0.0); + + // And since we haven't starting playback, clear the time of initial playback and the current timestamp. + playbackStartTime = 0; + logCurrentTime = logStartTime; +} + +bool QGCMAVLinkLogPlayer::jumpToPlaybackLocation(float percentage) { // Reset only for valid values - const unsigned int packetSize = timeLen + packetLen; - if (packetIndex >= 0 && packetIndex*packetSize <= logFile.size() - packetSize) + if (percentage <= 100.0f && percentage >= 0.0f) { bool result = true; - pause(); - loopCounter = 0; - logFile.reset(); + if (mavlinkLogFormat) + { + // But if we have a timestamped MAVLink log, then actually aim to hit that percentage in terms of + // time through the file. + qint64 newFilePos = (qint64)(percentage * (float)logFile.size()); + + // Now seek to the appropriate position, failing gracefully if we can't. + if (!logFile.seek(newFilePos)) + { + // Fallback: Start from scratch + logFile.reset(); + ui->logStatsLabel->setText(tr("Changing packet index failed, back to start.")); + result = false; + } + + // But we do align to the next MAVLink message for consistency. + mavlink_message_t dummy; + logCurrentTime = findNextMavlinkMessage(&dummy); - if (!logFile.seek(packetIndex*packetSize)) + // Now calculate the current file location based on time. + float newRelativeTime = (float)(logCurrentTime - logStartTime); + + // Calculate the effective baud rate of the file in bytes/s. + float logDuration = (logEndTime - logStartTime); + float baudRate = logFile.size() / logDuration / 1e6; + + // And the desired time is: + float desiredTime = percentage * logDuration; + + // And now jump the necessary number of bytes in the proper direction + qint64 offset = (newRelativeTime - desiredTime) * baudRate; + logFile.seek(logFile.pos() + offset); + + // And scan until we reach the start of a MAVLink message. We make sure to record this timestamp for + // smooth jumping around the file. + logCurrentTime = findNextMavlinkMessage(&dummy); + + // Now update the UI with our actual final position. + newRelativeTime = (float)(logCurrentTime - logStartTime); + percentage = newRelativeTime / logDuration; + updatePositionSliderUi(percentage); + } + else { - // Fallback: Start from scratch - logFile.reset(); - ui->logStatsLabel->setText(tr("Changing packet index failed, back to start.")); - result = false; + // If we're working with a non-timestamped file, we just jump to that percentage of the file, + // align to the next MAVLink message and roll with it. No reason to do anything more complicated. + qint64 newFilePos = (qint64)(percentage * (float)logFile.size()); + + // Now seek to the appropriate position, failing gracefully if we can't. + if (!logFile.seek(newFilePos)) + { + // Fallback: Start from scratch + logFile.reset(); + ui->logStatsLabel->setText(tr("Changing packet index failed, back to start.")); + result = false; + } + + // But we do align to the next MAVLink message for consistency. + mavlink_message_t dummy; + findNextMavlinkMessage(&dummy); } - ui->playButton->setIcon(QIcon(":files/images/actions/media-playback-start.svg")); - ui->positionSlider->blockSignals(true); - int sliderVal = (packetIndex / (double)(logFile.size()/packetSize)) * (ui->positionSlider->maximum() - ui->positionSlider->minimum()); - ui->positionSlider->setValue(sliderVal); - ui->positionSlider->blockSignals(false); - startTime = 0; + // Now update the UI. This is necessary because stop() is called when loading a new logfile + return result; } else @@ -179,6 +238,26 @@ bool QGCMAVLinkLogPlayer::reset(int packetIndex) } } +void QGCMAVLinkLogPlayer::updatePositionSliderUi(float percent) +{ + ui->positionSlider->blockSignals(true); + int sliderVal = ui->positionSlider->minimum() + (int)(percent * (float)(ui->positionSlider->maximum() - ui->positionSlider->minimum())); + ui->positionSlider->setValue(sliderVal); + + // Calculate the runtime in hours:minutes:seconds + // WARNING: Order matters in this computation + quint32 seconds = percent * (logEndTime - logStartTime) / 1e6; + quint32 minutes = seconds / 60; + quint32 hours = minutes / 60; + seconds -= 60*minutes; + minutes -= 60*hours; + + // And show the user the details we found about this file. + QString timeLabel = tr("%1h:%2m:%3s").arg(hours, 2).arg(minutes, 2).arg(seconds, 2); + ui->positionSlider->setToolTip(timeLabel); + ui->positionSlider->blockSignals(false); +} + void QGCMAVLinkLogPlayer::loadSettings() { QSettings settings; @@ -203,6 +282,7 @@ void QGCMAVLinkLogPlayer::storeSettings() */ bool QGCMAVLinkLogPlayer::selectLogFile() { + // Prompt the user for a new file using the last directory they searched. return selectLogFile(lastLogDirectory); } @@ -253,11 +333,9 @@ void QGCMAVLinkLogPlayer::setAccelerationFactorInt(int factor) // operations to obtain the interval in milliseconds int interval = 1000 / ((binaryBaudRate / 10) / len); loopTimer.stop(); - loopTimer.start(interval/accelerationFactor); + loopTimer.start(interval / accelerationFactor); } - //qDebug() << "FACTOR:" << accelerationFactor; - ui->speedLabel->setText(tr("Speed: %1X").arg(accelerationFactor, 5, 'f', 2, '0')); } @@ -271,21 +349,24 @@ bool QGCMAVLinkLogPlayer::loadLogFile(const QString& file) ui->logFileNameLabel->setEnabled(true); ui->logStatsLabel->setEnabled(true); - // Check if logging is still enabled + // Disable logging while replaying a log file. if (mavlink->loggingEnabled()) { mavlink->enableLogging(false); MainWindow::instance()->showInfoMessage(tr("MAVLink Logging Stopped during Replay"), tr("MAVLink logging has been stopped during the log replay. To re-enable logging, use the link properties in the communication menu.")); } - // Ensure that the playback process is stopped + // Make sure to stop the logging process and reset everything. + reset(); + + // And that the old file is closed nicely. if (logFile.isOpen()) { - pause(); logFile.close(); } - logFile.setFileName(file); + // Now load the new file. + logFile.setFileName(file); if (!logFile.open(QFile::ReadOnly)) { MainWindow::instance()->showCriticalMessage(tr("The selected logfile is unreadable"), tr("Please make sure that the file %1 is readable or select a different file").arg(file)); @@ -296,47 +377,81 @@ bool QGCMAVLinkLogPlayer::loadLogFile(const QString& file) { QFileInfo logFileInfo(file); logFile.reset(); - startTime = 0; - ui->logFileNameLabel->setText(tr("%1").arg(logFileInfo.baseName())); + ui->logFileNameLabel->setText(tr("Logfile: %1").arg(logFileInfo.fileName())); + + // If there's an existing MAVLinkSimulationLink() being used for an old file, + // we replace it. + if (logLink) + { + logLink->disconnect(); + LinkManager::instance()->removeLink(logLink); + delete logLink; + } + logLink = new MAVLinkSimulationLink(""); + // Select if binary or MAVLink log format is used mavlinkLogFormat = file.endsWith(".mavlink"); if (mavlinkLogFormat) { - // Get the time interval from the logfile + // Get the first timestamp from the logfile + // This should be a big-endian uint64. QByteArray timestamp = logFile.read(timeLen); + quint64 starttime = parseTimestamp(timestamp); + + // Now find the last timestamp by scanning for the last MAVLink packet and + // find the timestamp before it. To do this we start searchin a little before + // the end of the file, specifically the maximum MAVLink packet size + the + // timestamp size. This guarantees that we will hit a MAVLink packet before + // the end of the file. Unfortunately, it basically guarantees that we will + // hit more than one. This is why we have to search for a bit. + qint64 fileLoc = logFile.size() - MAVLINK_MAX_PACKET_LEN - timeLen; + logFile.seek(fileLoc); + quint64 endtime = starttime; // Set a sane default for the endtime + mavlink_message_t msg; + quint64 newTimestamp; + while ((newTimestamp = findNextMavlinkMessage(&msg)) > endtime) { + endtime = newTimestamp; + } + + if (endtime == starttime) { + MainWindow::instance()->showCriticalMessage(tr("The selected logfile cannot be processed"), tr("No valid timestamps were found at the end of the logfile.").arg(file)); + logFile.setFileName(""); + ui->logFileNameLabel->setText(tr("No logfile selected")); + return false; + } - // First timestamp - quint64 starttime = *((quint64*)(timestamp.constData())); + // Remember the start and end time so we can move around this logfile with the slider. + logEndTime = endtime; + logStartTime = starttime; + logCurrentTime = logStartTime; - // Last timestamp - logFile.seek(logFile.size()-packetLen-timeLen); - QByteArray timestamp2 = logFile.read(timeLen); - quint64 endtime = *((quint64*)(timestamp2.constData())); - // Reset everything + // Reset our log file so when we go to read it for the first time, we start at the beginning. logFile.reset(); - qDebug() << "Starttime:" << starttime << "End:" << endtime; - + // Calculate the runtime in hours:minutes:seconds // WARNING: Order matters in this computation - int seconds = (endtime - starttime)/1000000; - int minutes = seconds / 60; - int hours = minutes / 60; + quint32 seconds = (endtime - starttime)/1000000; + quint32 minutes = seconds / 60; + quint32 hours = minutes / 60; seconds -= 60*minutes; minutes -= 60*hours; + // And show the user the details we found about this file. QString timelabel = tr("%1h:%2m:%3s").arg(hours, 2).arg(minutes, 2).arg(seconds, 2); - currPacketCount = logFileInfo.size()/(MAVLINK_MAX_PACKET_LEN+sizeof(quint64)); - ui->logStatsLabel->setText(tr("%2 MB, %3 packets, %4").arg(logFileInfo.size()/1000000.0f, 0, 'f', 2).arg(currPacketCount).arg(timelabel)); + currPacketCount = logFileInfo.size()/(32 + MAVLINK_NUM_NON_PAYLOAD_BYTES + sizeof(quint64)); // Count packets by assuming an average payload size of 32 bytes + ui->logStatsLabel->setText(tr("%2 MB, ~%3 packets, %4").arg(logFileInfo.size()/1000000.0f, 0, 'f', 2).arg(currPacketCount).arg(timelabel)); } else { - // Load in binary mode + // Load in binary mode. In this mode, files should be have a filename postfix + // of the baud rate they were recorded at, like `test_run_115200.bin`. Then on + // playback, the datarate is equal to set to this value. - // Set baud rate if any present + // Set baud rate if any present. Otherwise we default to 57600. QStringList parts = logFileInfo.baseName().split("_"); - + binaryBaudRate = defaultBinaryBaudRate; if (parts.count() > 1) { bool ok; @@ -359,9 +474,6 @@ bool QGCMAVLinkLogPlayer::loadLogFile(const QString& file) ui->logStatsLabel->setText(tr("%2 MB, %4 at %5 KB/s").arg(logFileInfo.size()/1000000.0f, 0, 'f', 2).arg(timelabel).arg(binaryBaudRate/10.0f/1024.0f, 0, 'f', 2)); } - // Reset current state - reset(0); - // Check if a serial link is connected bool linkWarning = false; @@ -382,24 +494,66 @@ bool QGCMAVLinkLogPlayer::loadLogFile(const QString& file) } } +quint64 QGCMAVLinkLogPlayer::parseTimestamp(const QByteArray &data) +{ + // Retrieve the timestamp from the ByteArray assuming a proper BigEndian quint64 timestamp in microseconds. + quint64 timestamp = qFromBigEndian(*((quint64*)(data.constData()))); + + // And get the current time in microseconds + quint64 currentTimestamp = ((quint64)QDateTime::currentMSecsSinceEpoch()) * 1000; + + // Now if the parsed timestamp is in the future, it must be an old file where the timestamp was stored as + // little endian, so switch it. + if (timestamp > currentTimestamp) { + timestamp = qbswap(timestamp); + } + + return timestamp; +} + /** - * Jumps to the current percentage of the position slider + * Jumps to the current percentage of the position slider. When this is called, the LogPlayer should already + * have been paused, so it just jumps to the proper location in the file and resumes playing. */ void QGCMAVLinkLogPlayer::jumpToSliderVal(int slidervalue) { - loopTimer.stop(); - // Set the logfile to the correct percentage and - // align to the timestamp values - int packetCount = logFile.size() / (packetLen + timeLen); - int packetIndex = (packetCount - 1) * (slidervalue / (double)(ui->positionSlider->maximum() - ui->positionSlider->minimum())); + // Determine what percentage through the file we should be (time or packet number depending). + float newLocation = slidervalue / (float)(ui->positionSlider->maximum() - ui->positionSlider->minimum()); + + // And clamp our calculated values to the valid range of [0,100] + if (newLocation > 100.0f) + { + newLocation = 100.0f; + } + if (newLocation < 0.0f) + { + newLocation = 0.0f; + } - // Do only accept valid jumps - if (reset(packetIndex)) + // Do only valid jumps + if (jumpToPlaybackLocation(newLocation)) { if (mavlinkLogFormat) { - ui->logStatsLabel->setText(tr("Jumped to packet %1").arg(packetIndex)); + // Grab the total seconds of this file (1e6 is due to microsecond -> second conversion) + int seconds = newLocation * (logEndTime - logStartTime) / 1e6; + int minutes = seconds / 60; + int hours = minutes / 60; + seconds -= 60*minutes; + minutes -= 60*hours; + + ui->logStatsLabel->setText(tr("Jumped to time %1h:%2m:%3s").arg(hours, 2).arg(minutes, 2).arg(seconds, 2)); + } + else + { + ui->logStatsLabel->setText(tr("Jumped to %1").arg(newLocation)); } + + play(); + } + else + { + reset(); } } @@ -413,103 +567,51 @@ void QGCMAVLinkLogPlayer::jumpToSliderVal(int slidervalue) */ void QGCMAVLinkLogPlayer::logLoop() { + // If we have a file with timestamps, try and pace this out following the time differences + // between the timestamps and the current playback speed. if (mavlinkLogFormat) { - bool ok; + // Now parse MAVLink messages, grabbing their timestamps as we go. We stop once we + // have at least 3ms until the next one. + int nextExecutionTime = 0; + mavlink_message_t msg; + msg.len = 0; // FIXME: Hack, remove once Issue #647 is fixed + while (nextExecutionTime < 3) { - // First check initialization - if (startTime == 0) - { - QByteArray startBytes = logFile.read(timeLen); + // Now we're sitting at the start of a MAVLink message, so read it all into a byte array for feeding to our parser. + QByteArray message = logFile.read(msg.len + MAVLINK_NUM_NON_PAYLOAD_BYTES); - // Check if the correct number of bytes could be read - if (startBytes.length() != timeLen) - { - ui->logStatsLabel->setText(tr("Error reading first %1 bytes").arg(timeLen)); - MainWindow::instance()->showCriticalMessage(tr("Failed loading MAVLink Logfile"), tr("Error reading first %1 bytes from logfile. Got %2 instead of %1 bytes. Is the logfile readable?").arg(timeLen).arg(startBytes.length())); - reset(); - return; - } + // Emit this message to our MAVLink parser. + emit bytesReady(logLink, message); - // Convert data to timestamp - startTime = *((quint64*)(startBytes.constData())); - currentStartTime = QGC::groundTimeUsecs(); - ok = true; - - //qDebug() << "START TIME: " << startTime; - - // Check if these bytes could be correctly decoded - // TODO - if (!ok) + // If we've reached the end of the of the file, make sure we handle that well + if (logFile.atEnd()) { - ui->logStatsLabel->setText(tr("Error decoding first timestamp, aborting.")); - MainWindow::instance()->showCriticalMessage(tr("Failed loading MAVLink Logfile"), tr("Could not load initial timestamp from file %1. Is the file corrupted?").arg(logFile.fileName())); - reset(); + // For some reason calling pause() here doesn't work, so we update the UI manually here. + isPlaying = false; + ui->playButton->setIcon(QIcon(":files/images/actions/media-playback-start.svg")); + ui->playButton->setChecked(false); + ui->selectFileButton->setEnabled(true); + + // Note that we explicitly set the slider to 100%, as it may not hit that by itself depending on log file size. + updatePositionSliderUi(100.0f); + emit logFileEndReached(); return; } - } - - // Initialization seems fine, load next chunk - //this is ok because before we already read the timestamp of this paket before - QByteArray chunk = logFile.read(timeLen+packetLen); - QByteArray packet = chunk.left(packetLen); + // Run our parser to find the next timestamp and leave us at the start of the next MAVLink message. + logCurrentTime = findNextMavlinkMessage(&msg); - // Emit this packet - emit bytesReady(logLink, packet); - - // Check if reached end of file before reading next timestamp - if (chunk.length() < (timeLen + packetLen) || logFile.atEnd()) - { - // Reached end of file - reset(); - - QString status = tr("Reached end of MAVLink log file."); - ui->logStatsLabel->setText(status); - MainWindow::instance()->showStatusMessage(status); - return; + // Calculate how long we should wait in real time until parsing this message. + // We pace ourselves relative to the start time of playback to fix any drift (initially set in play()) + qint64 timediff = (logCurrentTime - logStartTime) / accelerationFactor; + quint64 desiredPacedTime = playbackStartTime + ((quint64)timediff) / 1000; + quint64 currentTime = (quint64)QDateTime::currentMSecsSinceEpoch(); + nextExecutionTime = desiredPacedTime - currentTime; } - // End of file not reached, read next timestamp - // which is located after current packet - QByteArray rawTime = chunk.mid(packetLen); - - // This is the timestamp of the next packet - quint64 time = *((quint64*)(rawTime.constData())); - ok = true; - if (!ok) - { - // Convert it to 64bit number - QString status = tr("Time conversion error during log replay. Continuing.."); - ui->logStatsLabel->setText(status); - MainWindow::instance()->showStatusMessage(status); - } - else - { - // Normal processing, passed all checks - // start timer to match time offset between - // this and next packet - - - // Offset in ms - qint64 timediff = (time - startTime)/accelerationFactor; - - // Immediately load any data within - // a 3 ms interval - - int nextExecutionTime = (((qint64)currentStartTime + (qint64)timediff) - (qint64)QGC::groundTimeUsecs())/1000; - - //qDebug() << "nextExecutionTime:" << nextExecutionTime << "QGC START TIME:" << currentStartTime << "LOG START TIME:" << startTime; - - if (nextExecutionTime < 2) - { - logLoop(); - } - else - { - loopTimer.start(nextExecutionTime); - } - } + // And schedule the next execution of this function. + loopTimer.start(nextExecutionTime); } else { @@ -532,23 +634,48 @@ void QGCMAVLinkLogPlayer::logLoop() return; } } - // Ui update: Only every 20 messages - // to prevent flickering and high CPU load - // Update status label - // Update progress bar - if (loopCounter % 40 == 0 || currPacketCount < 500) + // Update the UI every 2^5=32 times, or when there isn't much data to be played back. + // Reduces flickering and minimizes CPU load. + if ((loopCounter & 0x1F) == 0 || currPacketCount < 2000) { QFileInfo logFileInfo(logFile); - int progress = (ui->positionSlider->maximum()-ui->positionSlider->minimum())*(logFile.pos()/static_cast(logFileInfo.size())); - //qDebug() << "Progress:" << progress; - ui->positionSlider->blockSignals(true); - ui->positionSlider->setValue(progress); - ui->positionSlider->blockSignals(false); + updatePositionSliderUi(logFile.pos() / static_cast(logFileInfo.size())); } loopCounter++; } +/** + * This function parses out the next MAVLink message and its corresponding timestamp. + * + * It makes no assumptions about where in the file we currently are. It leaves the file right + * at the beginning of the successfully parsed message. Note that this function will not attempt to + * correct for any MAVLink parsing failures, so it always returns the next successfully-parsed + * message. + * + * @param msg[output] Where the final parsed message output will go. + * @return A Unix timestamp in microseconds UTC or 0 if parsing failed + */ +quint64 QGCMAVLinkLogPlayer::findNextMavlinkMessage(mavlink_message_t *msg) +{ + char nextByte; + mavlink_status_t comm; + while (logFile.getChar(&nextByte)) { // Loop over every byte + bool messageFound = mavlink_parse_char(logLink->getId(), nextByte, msg, &comm); + + // If we've found a message, jump back to the start of the message, grab the timestamp, + // and go back to the end of this file. + if (messageFound) { + logFile.seek(logFile.pos() - (msg->len + MAVLINK_NUM_NON_PAYLOAD_BYTES + timeLen)); + QByteArray rawTime = logFile.read(timeLen); + return parseTimestamp(rawTime); + } + } + + // Otherwise, if we never find a message, return a failure code of 0. + return 0; +} + void QGCMAVLinkLogPlayer::changeEvent(QEvent *e) { QWidget::changeEvent(e); @@ -571,4 +698,4 @@ void QGCMAVLinkLogPlayer::paintEvent(QPaintEvent *) opt.init(this); QPainter p(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} \ No newline at end of file +} diff --git a/src/ui/QGCMAVLinkLogPlayer.h b/src/ui/QGCMAVLinkLogPlayer.h index 647461ecf096f8e4b80a329be101ea5c345e277a..05887b7b2cf227f7105c8fb46f24818b3e37a533 100644 --- a/src/ui/QGCMAVLinkLogPlayer.h +++ b/src/ui/QGCMAVLinkLogPlayer.h @@ -52,10 +52,10 @@ public slots: void playPause(bool play); /** @brief Replay the logfile */ void play(); - /** @brief Pause the logfile */ + /** @brief Pause the log player. */ void pause(); - /** @brief Reset the logfile */ - bool reset(int packetIndex=0); + /** @brief Reset the internal log player state, including the UI */ + void reset(); /** @brief Select logfile */ bool selectLogFile(const QString startDirectory); /** @brief Select logfile */ @@ -72,21 +72,22 @@ public slots: signals: /** @brief Send ready bytes */ void bytesReady(LinkInterface* link, const QByteArray& bytes); + void logFileEndReached(); protected: - int lineCounter; - int totalLines; - quint64 startTime; - quint64 endTime; - quint64 currentStartTime; + quint64 playbackStartTime; ///< The time when the logfile was first played back. This is used to pace out replaying the messages to fix long-term drift/skew. 0 indicates that the player hasn't initiated playback of this log file. In units of milliseconds since epoch UTC. + quint64 logCurrentTime; ///< The timestamp of the next message in the log file. In units of microseconds since epoch UTC. + quint64 logStartTime; ///< The first timestamp in the current log file. In units of microseconds since epoch UTC. + quint64 logEndTime; ///< The last timestamp in the current log file. In units of microseconds since epoch UTC. float accelerationFactor; MAVLinkProtocol* mavlink; MAVLinkSimulationLink* logLink; QFile logFile; QTimer loopTimer; int loopCounter; - bool mavlinkLogFormat; + bool mavlinkLogFormat; ///< If the logfile is stored in the timestamped MAVLink log format int binaryBaudRate; + static const int defaultBinaryBaudRate = 57600; bool isPlaying; unsigned int currPacketCount; static const int packetLen = MAVLINK_MAX_PACKET_LEN; @@ -100,6 +101,35 @@ protected: private: Ui::QGCMAVLinkLogPlayer *ui; virtual void paintEvent(QPaintEvent *); + + /** @brief Parse out a quint64 timestamp in microseconds in the proper endianness. */ + quint64 parseTimestamp(const QByteArray &data); + + /** + * This function parses out the next MAVLink message and its corresponding timestamp. + * + * It makes no assumptions about where in the file we currently are. It leaves the file right + * at the beginning of the successfully parsed message. Note that this function will not attempt to + * correct for any MAVLink parsing failures, so it always returns the next successfully-parsed + * message. + * + * @param msg[output] Where the final parsed message output will go. + * @return A Unix timestamp in microseconds UTC or 0 if parsing failed + */ + quint64 findNextMavlinkMessage(mavlink_message_t *msg); + + /** + * Updates the QSlider UI to be at the given percentage. + * @param percent A percentage value between 0.0% and 100.0%. + */ + void updatePositionSliderUi(float percent); + + /** + * Jumps to a new position in the current playback file as a percentage. + * @param percentage The position of the file to jump to as a percentage. + * @return True if the new file position was successfully jumped to, false otherwise + */ + bool jumpToPlaybackLocation(float percentage); }; #endif // QGCMAVLINKLOGPLAYER_H diff --git a/src/ui/QGCMAVLinkLogPlayer.ui b/src/ui/QGCMAVLinkLogPlayer.ui index f79503765f1700a7d7683a2786cc4f53eef647b9..a94f120fab1ad21ac8f3ca22855164b75e57a568 100644 --- a/src/ui/QGCMAVLinkLogPlayer.ui +++ b/src/ui/QGCMAVLinkLogPlayer.ui @@ -29,7 +29,7 @@ - No logfile selected.. + @@ -54,6 +54,16 @@ true + + false + + + + + + + Time + @@ -119,7 +129,7 @@ - - + No logfile selected.. diff --git a/src/ui/QGCPX4VehicleConfig.cc b/src/ui/QGCPX4VehicleConfig.cc index 10b1a85960c3aaba778248edfc7abc9a6bcd959d..0268b9c7db81473bc97d797ad73eb1b0ccc1fa24 100644 --- a/src/ui/QGCPX4VehicleConfig.cc +++ b/src/ui/QGCPX4VehicleConfig.cc @@ -71,7 +71,7 @@ QGCPX4VehicleConfig::QGCPX4VehicleConfig(QWidget *parent) : channelNames << "Yaw / Rudder"; channelNames << "Throttle"; channelNames << "Main Mode Switch"; - channelNames << "Assist Switch"; + channelNames << "Posctl Switch"; channelNames << "Loiter Switch"; channelNames << "Return Switch"; channelNames << "Flaps"; @@ -202,8 +202,8 @@ QGCPX4VehicleConfig::QGCPX4VehicleConfig(QWidget *parent) : connect(ui->yawSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setYawChan(int))); connect(ui->throttleSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setThrottleChan(int))); connect(ui->modeSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setModeChan(int))); - connect(ui->assistSwSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setAssistChan(int))); - connect(ui->missionSwSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setMissionChan(int))); + connect(ui->posctlSwSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setAssistChan(int))); + connect(ui->loiterSwSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setMissionChan(int))); connect(ui->returnSwSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setReturnChan(int))); connect(ui->flapsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setFlapsChan(int))); connect(ui->aux1SpinBox, SIGNAL(valueChanged(int)), this, SLOT(setAux1Chan(int))); @@ -215,8 +215,8 @@ QGCPX4VehicleConfig::QGCPX4VehicleConfig(QWidget *parent) : connect(ui->invertCheckBox_3, SIGNAL(clicked(bool)), this, SLOT(setYawInverted(bool))); connect(ui->invertCheckBox_4, SIGNAL(clicked(bool)), this, SLOT(setThrottleInverted(bool))); connect(ui->invertCheckBox_5, SIGNAL(clicked(bool)), this, SLOT(setModeInverted(bool))); - connect(ui->assistSwInvertCheckBox, SIGNAL(clicked(bool)), this, SLOT(setAssistInverted(bool))); - connect(ui->missionSwInvertCheckBox, SIGNAL(clicked(bool)), this, SLOT(setMissionInverted(bool))); + connect(ui->posctlSwInvertCheckBox, SIGNAL(clicked(bool)), this, SLOT(setAssistInverted(bool))); + connect(ui->loiterSwInvertCheckBox, SIGNAL(clicked(bool)), this, SLOT(setMissionInverted(bool))); connect(ui->returnSwInvertCheckBox, SIGNAL(clicked(bool)), this, SLOT(setReturnInverted(bool))); connect(ui->flapsInvertCheckBox, SIGNAL(clicked(bool)), this, SLOT(setFlapsInverted(bool))); connect(ui->aux1InvertCheckBox, SIGNAL(clicked(bool)), this, SLOT(setAux1Inverted(bool))); @@ -227,8 +227,8 @@ QGCPX4VehicleConfig::QGCPX4VehicleConfig(QWidget *parent) : connect(ui->yawButton, SIGNAL(clicked()), this, SLOT(identifyYawChannel())); connect(ui->throttleButton, SIGNAL(clicked()), this, SLOT(identifyThrottleChannel())); connect(ui->modeButton, SIGNAL(clicked()), this, SLOT(identifyModeChannel())); - connect(ui->assistSwButton, SIGNAL(clicked()), this, SLOT(identifyAssistChannel())); - connect(ui->missionSwButton, SIGNAL(clicked()), this, SLOT(identifyMissionChannel())); + connect(ui->posctlSwButton, SIGNAL(clicked()), this, SLOT(identifyAssistChannel())); + connect(ui->loiterSwButton, SIGNAL(clicked()), this, SLOT(identifyMissionChannel())); connect(ui->returnSwButton, SIGNAL(clicked()), this, SLOT(identifyReturnChannel())); connect(ui->flapsButton, SIGNAL(clicked()), this, SLOT(identifyFlapsChannel())); connect(ui->aux1Button, SIGNAL(clicked()), this, SLOT(identifyAux1Channel())); @@ -430,12 +430,12 @@ void QGCPX4VehicleConfig::setTrimPositions() while (!throttleDone) { // Set trim to min if stick is close to min - if (abs(rcValue[throttleMap] - rcMin[throttleMap]) < 100) { + if (abs(rcValue[throttleMap] - rcMin[throttleMap]) < 200) { rcTrim[throttleMap] = rcMin[throttleMap]; // throttle throttleDone = true; } // Set trim to max if stick is close to max - else if (abs(rcValue[throttleMap] - rcMax[throttleMap]) < 100) { + else if (abs(rcValue[throttleMap] - rcMax[throttleMap]) < 200) { rcTrim[throttleMap] = rcMax[throttleMap]; // throttle throttleDone = true; } @@ -445,9 +445,11 @@ void QGCPX4VehicleConfig::setTrimPositions() QMessageBox warnMsgBox; warnMsgBox.setText(tr("Throttle Stick Trim Position Invalid")); warnMsgBox.setInformativeText(tr("The throttle stick is not in the min position. Please set it to the zero throttle position and then click OK.")); - warnMsgBox.setStandardButtons(QMessageBox::Ok); + warnMsgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Abort); warnMsgBox.setDefaultButton(QMessageBox::Ok); - (void)warnMsgBox.exec(); + if (warnMsgBox.exec() == QMessageBox::Abort) { + return; + } // wait long enough to get some data QGC::SLEEP::msleep(500); } @@ -492,8 +494,8 @@ void QGCPX4VehicleConfig::detectChannelInversion(int aert_index) instructions << "YAW: Move stick left"; instructions << "THROTTLE: Move stick down"; instructions << "MODE SWITCH: Push down / towards you"; - instructions << "ASSISTED SWITCH: Push down / towards you"; - instructions << "MISSION SWITCH: Push down / towards you"; + instructions << "POSITION CONTROL SWITCH: Push down / towards you"; + instructions << "LOITER SWITCH: Push down / towards you"; instructions << "RETURN SWITCH: Push down / towards you"; instructions << "FLAPS: Push down / towards you or turn dial to the leftmost position"; instructions << "AUX1: Push down / towards you or turn dial to the leftmost position"; @@ -534,7 +536,7 @@ void QGCPX4VehicleConfig::startCalibrationRC() configEnabled = true; QMessageBox::warning(0,tr("Safety Warning"), - tr("Starting RC calibration.\n\nEnsure that motor power is disconnected, all props are removed, RC transmitter and receiver are powered and connected.\n\nReset transmitter trims to center, then click OK to continue")); + tr("Starting RC calibration.\n\nEnsure RC transmitter and receiver are powered and connected. It is recommended to disconnect all motors for additional safety, however, the system is designed to not arm during the calibration.\n\nReset transmitter trims to center, then click OK to continue")); //go ahead and try to map first 8 channels, now that user can skip channels for (int i = 0; i < 8; i++) { @@ -581,12 +583,25 @@ void QGCPX4VehicleConfig::stopCalibrationRC() if (!calibrationEnabled) return; + // Check where the throttle is + while (rcValue[rcMapping[3]] < 1300 || rcValue[rcMapping[3]] > 1700) { + // Force user to center the throttle + msgBox.setText(tr("Please center the throttle stick")); + msgBox.setInformativeText(tr("The stick should be roughly centered - the exact position is not relevant.")); + msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);//allow user to cancel upload after reviewing values + int msgBoxResult = msgBox.exec(); + + if (QMessageBox::Cancel == msgBoxResult) { + return; // abort + } + } + // Try to identify inverted channels, but only for R/P/Y/T for (int i = 0; i < 4; i++) { detectChannelInversion(i); } - QMessageBox::information(0,"Trims","Ensure THROTTLE is in the LOWEST position and roll / pitch / yaw are CENTERED. Click OK to continue"); + QMessageBox::information(0,"Trims","Ensure THROTTLE is in the LOW THROTTLE / MOTOR OFF position and roll / pitch / yaw are CENTERED. Click OK to continue"); calibrationEnabled = false; configEnabled = false; @@ -1315,8 +1330,8 @@ void QGCPX4VehicleConfig::writeCalibrationRC() paramMgr->setPendingParam(0, "RC_MAP_YAW", (int32_t)(rcMapping[2]+1)); paramMgr->setPendingParam(0, "RC_MAP_THROTTLE", (int32_t)(rcMapping[3]+1)); paramMgr->setPendingParam(0, "RC_MAP_MODE_SW", (int32_t)(rcMapping[4]+1)); - paramMgr->setPendingParam(0, "RC_MAP_ASSIST_SW", (int32_t)(rcMapping[5]+1)); - paramMgr->setPendingParam(0, "RC_MAP_MISSIO_SW", (int32_t)(rcMapping[6]+1)); + paramMgr->setPendingParam(0, "RC_MAP_POSCTL_SW", (int32_t)(rcMapping[5]+1)); + paramMgr->setPendingParam(0, "RC_MAP_LOITER_SW", (int32_t)(rcMapping[6]+1)); paramMgr->setPendingParam(0, "RC_MAP_RETURN_SW", (int32_t)(rcMapping[7]+1)); paramMgr->setPendingParam(0, "RC_MAP_FLAPS", (int32_t)(rcMapping[8]+1)); paramMgr->setPendingParam(0, "RC_MAP_AUX1", (int32_t)(rcMapping[9]+1)); @@ -1409,10 +1424,10 @@ void QGCPX4VehicleConfig::remoteControlChannelRawChanged(int chan, float fval) ui->modeSpinBox->setValue(chan + 1); break; case 5: - ui->assistSwSpinBox->setValue(chan + 1); + ui->posctlSwSpinBox->setValue(chan + 1); break; case 6: - ui->missionSwSpinBox->setValue(chan + 1); + ui->loiterSwSpinBox->setValue(chan + 1); break; case 7: ui->returnSwSpinBox->setValue(chan + 1); @@ -1565,10 +1580,10 @@ void QGCPX4VehicleConfig::updateAllInvertedCheckboxes() //ui->radio5Widget->setName(tr("Mode Switch (#%1)").arg(rcMapping[4] + 1)); break; case 5: - ui->assistSwInvertCheckBox->setChecked(rcRev[rc_input_index]); + ui->posctlSwInvertCheckBox->setChecked(rcRev[rc_input_index]); break; case 6: - ui->missionSwInvertCheckBox->setChecked(rcRev[rc_input_index]); + ui->loiterSwInvertCheckBox->setChecked(rcRev[rc_input_index]); break; case 7: ui->returnSwInvertCheckBox->setChecked(rcRev[rc_input_index]); @@ -1690,15 +1705,15 @@ void QGCPX4VehicleConfig::handleRcParameterChange(QString parameterName, QVarian ui->modeSpinBox->setValue(rcMapping[4]+1); ui->modeSpinBox->setEnabled(true); } - else if (parameterName.startsWith("RC_MAP_ASSIST_SW")) { + else if (parameterName.startsWith("RC_MAP_POSCTL_SW")) { setChannelToFunctionMapping(5, intValue); - ui->assistSwSpinBox->setValue(rcMapping[5]+1); - ui->assistSwSpinBox->setEnabled(true); + ui->posctlSwSpinBox->setValue(rcMapping[5]+1); + ui->posctlSwSpinBox->setEnabled(true); } - else if (parameterName.startsWith("RC_MAP_MISSIO_SW")) { + else if (parameterName.startsWith("RC_MAP_LOITER_SW")) { setChannelToFunctionMapping(6, intValue); - ui->missionSwSpinBox->setValue(rcMapping[6]+1); - ui->missionSwSpinBox->setEnabled(true); + ui->loiterSwSpinBox->setValue(rcMapping[6]+1); + ui->loiterSwSpinBox->setEnabled(true); } else if (parameterName.startsWith("RC_MAP_RETURN_SW")) { setChannelToFunctionMapping(7, intValue); @@ -1941,17 +1956,17 @@ void QGCPX4VehicleConfig::updateRcChanLabels() } if (rcValue[rcMapping[5]] != UINT16_MAX) { - ui->assistSwChanLabel->setText(labelForRcValue(rcAssist)); + ui->posctlSwChanLabel->setText(labelForRcValue(rcAssist)); } else { - ui->assistSwChanLabel->setText(blankLabel); + ui->posctlSwChanLabel->setText(blankLabel); } if (rcValue[rcMapping[6]] != UINT16_MAX) { - ui->missionSwChanLabel->setText(labelForRcValue(rcLoiter)); + ui->loiterSwChanLabel->setText(labelForRcValue(rcLoiter)); } else { - ui->missionSwChanLabel->setText(blankLabel); + ui->loiterSwChanLabel->setText(blankLabel); } if (rcValue[rcMapping[7]] != UINT16_MAX) { diff --git a/src/ui/QGCPX4VehicleConfig.ui b/src/ui/QGCPX4VehicleConfig.ui index afe1571a55dc7a4a61729752763e16950a1fe0a9..858e4fe55dbe05c39d9b7d12a3cb804820650726 100644 --- a/src/ui/QGCPX4VehicleConfig.ui +++ b/src/ui/QGCPX4VehicleConfig.ui @@ -67,9 +67,9 @@ - + - Assist Switch + Posctl Switch Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -121,7 +121,7 @@ - + Return Switch @@ -141,7 +141,7 @@ - + Aux 1 @@ -188,7 +188,7 @@ - + Pitch / Elevator @@ -205,7 +205,7 @@ - + Yaw / Rudder @@ -288,7 +288,7 @@ - + 0000 @@ -298,7 +298,7 @@ - + Mode Switch @@ -328,7 +328,7 @@ - + Roll / Ailerons @@ -355,7 +355,7 @@ - + Reverse @@ -372,14 +372,14 @@ - + - Identify Assist Switch + Identify Posctl Switch - + Aux 2 @@ -396,7 +396,7 @@ - + false @@ -457,7 +457,7 @@ - + 0000 @@ -487,9 +487,9 @@ - + - Mission Switch + Loiter Switch Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -507,7 +507,7 @@ - + Throttle @@ -517,7 +517,7 @@ - + Flaps @@ -537,7 +537,7 @@ - + Reverse @@ -558,7 +558,7 @@ - + false @@ -582,9 +582,9 @@ - + - Identify Mission Switch + Identify Loiter Switch @@ -1027,8 +1027,8 @@ 0 0 - 98 - 28 + 21 + 16 @@ -1082,8 +1082,8 @@ 0 0 - 98 - 28 + 21 + 16 @@ -1151,8 +1151,8 @@ 0 0 - 98 - 28 + 16 + 16 @@ -1319,26 +1319,14 @@ Upgrade - - - - 100 - 75 - - - - - 16777215 - 16777215 - - + - Radio -Calibration + Airframe +Config - :/files/images/px4/menu/remote.png:/files/images/px4/menu/remote.png + :/files/images/px4/menu/plane.png:/files/images/px4/menu/plane.png @@ -1373,14 +1361,26 @@ Calibration - + + + + 100 + 75 + + + + + 16777215 + 16777215 + + - Airframe -Config + Radio +Calibration - :/files/images/px4/menu/plane.png:/files/images/px4/menu/plane.png + :/files/images/px4/menu/remote.png:/files/images/px4/menu/remote.png diff --git a/src/ui/QGCSettingsWidget.cc b/src/ui/QGCSettingsWidget.cc index 0e1d56b7e6a92e3dddd560f7ef80c36ccc9657eb..fa61cc75db88499ca2e3299ef212940e594f8ddb 100644 --- a/src/ui/QGCSettingsWidget.cc +++ b/src/ui/QGCSettingsWidget.cc @@ -35,6 +35,9 @@ QGCSettingsWidget::QGCSettingsWidget(QWidget *parent, Qt::WindowFlags flags) : this->window()->setWindowTitle(tr("QGroundControl Settings")); + // Settings reset + connect(ui->resetSettingsButton, SIGNAL(clicked()), this, SLOT(resetSettings())); + // Audio preferences ui->audioMuteCheckBox->setChecked(GAudioOutput::instance()->isMuted()); connect(ui->audioMuteCheckBox, SIGNAL(toggled(bool)), GAudioOutput::instance(), SLOT(mute(bool))); @@ -193,3 +196,13 @@ void QGCSettingsWidget::selectCustomMode(int mode) MainWindow::instance()->setCustomMode(static_cast(ui->customModeComboBox->itemData(mode).toInt())); MainWindow::instance()->showInfoMessage(tr("Please restart QGroundControl"), tr("The optimization selection was changed. The application needs to be closed and restarted to put all optimizations into effect.")); } + +void QGCSettingsWidget::resetSettings() +{ + QSettings settings; + settings.sync(); + settings.clear(); + // Write current application version + settings.setValue("QGC_APPLICATION_VERSION", QGC_APPLICATION_VERSION); + settings.sync(); +} diff --git a/src/ui/QGCSettingsWidget.h b/src/ui/QGCSettingsWidget.h index e77bbec17002a4b2a1f882995a87e15c5a7e6158..b9fa70d7eda4157306f252281e5f7a11af39450c 100644 --- a/src/ui/QGCSettingsWidget.h +++ b/src/ui/QGCSettingsWidget.h @@ -23,6 +23,7 @@ public slots: void setDefaultStyle(); void selectStylesheet(); void selectCustomMode(int mode); + void resetSettings(); private: MainWindow* mainWindow; diff --git a/src/ui/QGCSettingsWidget.ui b/src/ui/QGCSettingsWidget.ui index e5ba63d43a0671c5d634d15cde5cc39397168252..4b0536d7dad8c545da6337642e10c7ba1d26f879 100644 --- a/src/ui/QGCSettingsWidget.ui +++ b/src/ui/QGCSettingsWidget.ui @@ -6,8 +6,8 @@ 0 0 - 528 - 455 + 534 + 517 @@ -159,11 +159,34 @@ 20 - 0 + 20 + + + + Danger Zone + + + + + + Delete all settings, layouts and restore defaults + + + + + + + Reset Settings + + + + + + diff --git a/src/ui/QGCStatusBar.cc b/src/ui/QGCStatusBar.cc index 9e2fbacf1586079259a00721c01838cad52077dc..aecee8d30cc5e9e0b7797380ddfddce57c9a0d2d 100644 --- a/src/ui/QGCStatusBar.cc +++ b/src/ui/QGCStatusBar.cc @@ -37,7 +37,7 @@ QGCStatusBar::QGCStatusBar(QWidget *parent) : { setObjectName("QGC_STATUSBAR"); - toggleLoggingButton = new QPushButton("Logging", this); + toggleLoggingButton = new QPushButton(tr("Log to file"), this); toggleLoggingButton->setCheckable(true); addPermanentWidget(toggleLoggingButton); diff --git a/src/ui/QGCToolBar.cc b/src/ui/QGCToolBar.cc index 8bda720b1abb8d7567a953e13404ef54250ae61d..e589d042b25bbc946934f06508336c7b7543264a 100644 --- a/src/ui/QGCToolBar.cc +++ b/src/ui/QGCToolBar.cc @@ -202,7 +202,6 @@ void QGCToolBar::createUI() // Configure the toolbar for the current default UAS setActiveUAS(UASManager::instance()->getActiveUAS()); connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*))); - qDebug() << "LINK COUNT" << LinkManager::instance()->getLinks().count(); // Update label if required if (LinkManager::instance()->getSerialLinks().count() < 1) { connectButton->setText(tr("New Serial Link")); @@ -471,7 +470,9 @@ void QGCToolBar::updateView() // toolBarStateLabel->setText(QString("%1").arg(state)); - toolBarModeLabel->setText(QString("%1").arg(mode)); + if (mode.size() > 0) { + toolBarModeLabel->setText(QString("%1").arg(mode)); + } toolBarNameLabel->setText(systemName); // expire after 15 seconds @@ -542,8 +543,16 @@ void QGCToolBar::updateMode(int system, QString name, QString description) { Q_UNUSED(system); Q_UNUSED(description); - if (mode != name) changed = true; - mode = name; + if (name.size() == 0) { + qDebug() << "EMPTY MODE, RETURN"; + } + + QString shortMode = name; + shortMode = shortMode.replace("D|", ""); + shortMode = shortMode.replace("A|", ""); + + if (mode != shortMode) changed = true; + mode = shortMode; /* important, immediately update */ updateView(); } diff --git a/src/ui/SerialConfigurationWindow.cc b/src/ui/SerialConfigurationWindow.cc index 338e2d3283f7ce66995857d72bdc7df6fd5f011d..a6fd2cfa169ef2db847800c61de10c5b9b783de1 100644 --- a/src/ui/SerialConfigurationWindow.cc +++ b/src/ui/SerialConfigurationWindow.cc @@ -52,7 +52,7 @@ SerialConfigurationWindow::SerialConfigurationWindow(LinkInterface* link, QWidge // Create action to open this menu // Create configuration action for this link // Connect the current UAS - action = new QAction(QIcon(":/files/images/devices/network-wireless.svg"), "", link); + action = new QAction(QIcon(":/files/images/devices/network-wireless.svg"), "", this); setLinkName(link->getName()); setupPortList(); @@ -170,7 +170,6 @@ SerialConfigurationWindow::SerialConfigurationWindow(LinkInterface* link, QWidge ui.dataBitsSpinBox->setValue(this->link->getDataBits()); ui.stopBitsSpinBox->setValue(this->link->getStopBits()); - portCheckTimer = new QTimer(this); portCheckTimer->setInterval(1000); connect(portCheckTimer, SIGNAL(timeout()), this, SLOT(setupPortList())); diff --git a/src/ui/WaypointEditableView.cc b/src/ui/WaypointEditableView.cc index 8bb0c6cff828fae0ddcc0eb9f50fc6a98b9987b9..9c9e17cf89e3cbffc4e6b1a11e39620e08b2ca2c 100644 --- a/src/ui/WaypointEditableView.cc +++ b/src/ui/WaypointEditableView.cc @@ -38,12 +38,11 @@ WaypointEditableView::WaypointEditableView(Waypoint* wp, QWidget* parent) : QWidget(parent), + wp(wp), viewMode(QGC_WAYPOINTEDITABLEVIEW_MODE_DEFAULT), m_ui(new Ui::WaypointEditableView) { m_ui->setupUi(this); - - this->wp = wp; connect(wp, SIGNAL(destroyed(QObject*)), this, SLOT(deleted(QObject*))); // CUSTOM COMMAND WIDGET @@ -370,7 +369,10 @@ void WaypointEditableView::changedCurrent(int state) else { wp->setCurrent(true); - emit changeCurrentWaypoint(wp->getId()); //the slot changeCurrentWaypoint() in WaypointList sets all other current flags to false + // At this point we do not consider this signal + // to be valid / the edit check boxes should not change the view state + //emit changeCurrentWaypoint(wp->getId()); + //the slot changeCurrentWaypoint() in WaypointList sets all other current flags to false } } @@ -486,7 +488,10 @@ void WaypointEditableView::updateValues() if (m_ui->selectedBox->isChecked() != wp->getCurrent()) { + // This is never a reason to emit a changed signal + m_ui->selectedBox->blockSignals(true); m_ui->selectedBox->setChecked(wp->getCurrent()); + m_ui->selectedBox->blockSignals(false); } if (m_ui->autoContinue->isChecked() != wp->getAutoContinue()) { @@ -579,9 +584,12 @@ void WaypointEditableView::updateValues() void WaypointEditableView::setCurrent(bool state) { - m_ui->selectedBox->blockSignals(true); - m_ui->selectedBox->setChecked(state); - m_ui->selectedBox->blockSignals(false); + if (m_ui->selectedBox->isChecked() != state) + { + m_ui->selectedBox->blockSignals(true); + m_ui->selectedBox->setChecked(state); + m_ui->selectedBox->blockSignals(false); + } } diff --git a/src/ui/WaypointList.cc b/src/ui/WaypointList.cc index 44702dd5aac7fa272e782fd870cce886d6ec9198..fddc4b91519ecae4df97700fd064fe68a7e72fda 100644 --- a/src/ui/WaypointList.cc +++ b/src/ui/WaypointList.cc @@ -382,21 +382,23 @@ void WaypointList::changeCurrentWaypoint(quint16 seq) void WaypointList::currentWaypointEditableChanged(quint16 seq) { WPM->setCurrentEditable(seq); - const QList &waypoints = WPM->getWaypointEditableList(); + const QList waypoints = WPM->getWaypointEditableList(); if (seq < waypoints.count()) { for(int i = 0; i < waypoints.count(); i++) { - WaypointEditableView* widget = wpEditableViews.find(waypoints[i]).value(); + WaypointEditableView* widget = wpEditableViews.value(waypoints[i], NULL); - if (waypoints[i]->getId() == seq) - { - widget->setCurrent(true); - } - else - { - widget->setCurrent(false); + if (widget) { + if (waypoints[i]->getId() == seq) + { + widget->setCurrent(true); + } + else + { + widget->setCurrent(false); + } } } } @@ -408,21 +410,23 @@ void WaypointList::currentWaypointViewOnlyChanged(quint16 seq) // First update the edit list currentWaypointEditableChanged(seq); - const QList &waypoints = WPM->getWaypointViewOnlyList(); + const QList waypoints = WPM->getWaypointViewOnlyList(); if (seq < waypoints.count()) { for(int i = 0; i < waypoints.count(); i++) { - WaypointViewOnlyView* widget = wpViewOnlyViews.find(waypoints[i]).value(); + WaypointViewOnlyView* widget = wpViewOnlyViews.value(waypoints[i], NULL); - if (waypoints[i]->getId() == seq) - { - widget->setCurrent(true); - } - else - { - widget->setCurrent(false); + if (widget) { + if (waypoints[i]->getId() == seq) + { + widget->setCurrent(true); + } + else + { + widget->setCurrent(false); + } } } } @@ -431,17 +435,21 @@ void WaypointList::currentWaypointViewOnlyChanged(quint16 seq) void WaypointList::updateWaypointEditable(int uas, Waypoint* wp) { Q_UNUSED(uas); - WaypointEditableView *wpv = wpEditableViews.value(wp); - wpv->updateValues(); - m_ui->tabWidget->setCurrentIndex(0); // XXX magic number + WaypointEditableView *wpv = wpEditableViews.value(wp, NULL); + if (wpv) { + wpv->updateValues(); + } + m_ui->tabWidget->setCurrentIndex(0); // XXX magic number } void WaypointList::updateWaypointViewOnly(int uas, Waypoint* wp) { Q_UNUSED(uas); - WaypointViewOnlyView *wpv = wpViewOnlyViews.value(wp); - wpv->updateValues(); - m_ui->tabWidget->setCurrentIndex(1); // XXX magic number + WaypointViewOnlyView *wpv = wpViewOnlyViews.value(wp, NULL); + if (wpv) { + wpv->updateValues(); + } + m_ui->tabWidget->setCurrentIndex(1); // XXX magic number } void WaypointList::waypointViewOnlyListChanged() @@ -463,10 +471,12 @@ void WaypointList::waypointViewOnlyListChanged() } } if (i == waypoints.count()) { - WaypointViewOnlyView* widget = wpViewOnlyViews.find(cur).value(); - widget->hide(); - viewOnlyListLayout->removeWidget(widget); - wpViewOnlyViews.remove(cur); + WaypointViewOnlyView* widget = wpViewOnlyViews.value(cur, NULL); + if (widget) { + widget->hide(); + viewOnlyListLayout->removeWidget(widget); + wpViewOnlyViews.remove(cur); + } } } } @@ -517,10 +527,13 @@ void WaypointList::waypointEditableListChanged() } } if (i == waypoints.count()) { - WaypointEditableView* widget = wpEditableViews.find(cur).value(); - widget->hide(); - editableListLayout->removeWidget(widget); - wpEditableViews.remove(cur); + WaypointEditableView* widget = wpEditableViews.value(cur, NULL); + + if (widget) { + widget->hide(); + editableListLayout->removeWidget(widget); + wpEditableViews.remove(cur); + } } } } @@ -611,8 +624,10 @@ void WaypointList::on_clearWPListButton_clicked() emit clearPathclicked(); const QList &waypoints = WPM->getWaypointEditableList(); while(!waypoints.isEmpty()) { - WaypointEditableView* widget = wpEditableViews.find(waypoints[0]).value(); - widget->remove(); + WaypointEditableView* widget = wpEditableViews.value(waypoints[0], NULL); + if (widget) { + widget->remove(); + } } } } @@ -620,14 +635,16 @@ void WaypointList::on_clearWPListButton_clicked() void WaypointList::clearWPWidget() { // Get list - const QList &waypoints = WPM->getWaypointEditableList(); + const QList waypoints = WPM->getWaypointEditableList(); // XXX delete wps as well // Clear UI elements while(!waypoints.isEmpty()) { - WaypointEditableView* widget = wpEditableViews.find(waypoints[0]).value(); - widget->remove(); + WaypointEditableView* widget = wpEditableViews.value(waypoints[0], NULL); + if (widget) { + widget->remove(); + } } } diff --git a/src/ui/WaypointViewOnlyView.cc b/src/ui/WaypointViewOnlyView.cc index 8688b3fa2e0402ffcf0506fbb75c8174d8ace0aa..32f3b078065b844c3f5d77c60c4e39eae4ad848d 100644 --- a/src/ui/WaypointViewOnlyView.cc +++ b/src/ui/WaypointViewOnlyView.cc @@ -6,10 +6,10 @@ WaypointViewOnlyView::WaypointViewOnlyView(Waypoint* wp, QWidget *parent) : QWidget(parent), + wp(wp), m_ui(new Ui::WaypointViewOnlyView) { m_ui->setupUi(this); - this->wp = wp; updateValues(); connect(m_ui->current, SIGNAL(stateChanged(int)), this, SLOT(changedCurrent(int))); @@ -60,6 +60,10 @@ void WaypointViewOnlyView::changedCurrent(int state) void WaypointViewOnlyView::setCurrent(bool state) //This is a slot receiving signals from UASWaypointManager. The state given here is the true representation of what the "current" waypoint on UAV is. { + if (!wp) { + return; + } + m_ui->current->blockSignals(true); if (state == true) { diff --git a/src/ui/designer/QGCComboBox.cc b/src/ui/designer/QGCComboBox.cc index a8804e39ba0aac2cb3365089e89d3b56a480d6cc..d034fca66aad4315f58b4318d7d90a39a9c0ce99 100644 --- a/src/ui/designer/QGCComboBox.cc +++ b/src/ui/designer/QGCComboBox.cc @@ -23,7 +23,6 @@ QGCComboBox::QGCComboBox(QWidget *parent) : ui->setupUi(this); uas = NULL; - ui->editInfoCheckBox->hide(); ui->editDoneButton->hide(); ui->editNameLabel->hide(); @@ -60,10 +59,8 @@ QGCComboBox::QGCComboBox(QWidget *parent) : connect(ui->editInfoCheckBox, SIGNAL(clicked(bool)), this, SLOT(showInfo(bool))); // connect to self connect(ui->infoLabel, SIGNAL(released()), this, SLOT(showTooltip())); - // Set the current UAS if present - - connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*))); + init(); } QGCComboBox::~QGCComboBox() diff --git a/src/ui/designer/QGCCommandButton.cc b/src/ui/designer/QGCCommandButton.cc index 69efc00607f7efc6ef897206c3d5e12624353cae..8d8c3be3b04434551c5d8bf03c2d3e0e78d44a94 100644 --- a/src/ui/designer/QGCCommandButton.cc +++ b/src/ui/designer/QGCCommandButton.cc @@ -84,6 +84,8 @@ QGCCommandButton::QGCCommandButton(QWidget *parent) : ui->editCommandComboBox->addItem("MAV_CMD_MISSION_START", MAV_CMD_MISSION_START); ui->editCommandComboBox->addItem("MAV_CMD_COMPONENT_ARM_DISARM", MAV_CMD_COMPONENT_ARM_DISARM); ui->editCommandComboBox->setEditable(true); + + init(); } QGCCommandButton::~QGCCommandButton() diff --git a/src/ui/designer/QGCParamSlider.cc b/src/ui/designer/QGCParamSlider.cc index c5f2da52d903d5f7522f13d74111178f749a48dc..9750fe4cad37cc62572998d45d36c1514c999e4f 100644 --- a/src/ui/designer/QGCParamSlider.cc +++ b/src/ui/designer/QGCParamSlider.cc @@ -69,9 +69,9 @@ QGCParamSlider::QGCParamSlider(QWidget *parent) : // connect to self connect(ui->infoLabel, SIGNAL(released()), this, SLOT(showTooltip())); - // Set the current UAS if present - connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), - this, SLOT(setActiveUAS(UASInterface*))); + + init(); + requestParameter(); } QGCParamSlider::~QGCParamSlider() @@ -220,6 +220,8 @@ void QGCParamSlider::setEditMode(bool editMode) parameterMin = ui->editMinSpinBox->value(); parameterMax = ui->editMaxSpinBox->value(); + requestParameter(); + switch ((int)parameterValue.type()) { case QVariant::Char: @@ -264,6 +266,7 @@ void QGCParamSlider::setParamPending() { if (uas) { uas->getParamManager()->setPendingParam(componentId, parameterName, parameterValue); + uas->getParamManager()->sendPendingParameters(true, true); } else { qWarning() << __FILE__ << __LINE__ << "NO UAS SET, DOING NOTHING"; diff --git a/src/ui/designer/QGCParamSlider.ui b/src/ui/designer/QGCParamSlider.ui index e38c1f28f368285923838cc9753e5759da02f2fa..7a4c3806f6dd211f522360ff9eaffcdfeae59261 100644 --- a/src/ui/designer/QGCParamSlider.ui +++ b/src/ui/designer/QGCParamSlider.ui @@ -143,19 +143,6 @@ - - - - Qt::Vertical - - - - 20 - 40 - - - - @@ -286,6 +273,19 @@ + + + + Qt::Vertical + + + + 20 + 40 + + + + diff --git a/src/ui/designer/QGCTextLabel.cc b/src/ui/designer/QGCTextLabel.cc index 0a74c9d7f4b689b98b78dcf3df9cd32749d8420f..8654b33d0cc633b5cc28853f574d3e99f72cba55 100644 --- a/src/ui/designer/QGCTextLabel.cc +++ b/src/ui/designer/QGCTextLabel.cc @@ -24,6 +24,8 @@ QGCTextLabel::QGCTextLabel(QWidget *parent) : ui->editLine2->hide(); ui->isMavCommand->hide(); ui->textLabel->setText(QString()); + + init(); } QGCTextLabel::~QGCTextLabel() diff --git a/src/ui/designer/QGCToolWidgetItem.cc b/src/ui/designer/QGCToolWidgetItem.cc index 236ae6e486835f4a7af7829e99a14b7cebb46564..c9f162ec45b936ee03bca50cefc1990d48043409 100644 --- a/src/ui/designer/QGCToolWidgetItem.cc +++ b/src/ui/designer/QGCToolWidgetItem.cc @@ -15,14 +15,19 @@ QGCToolWidgetItem::QGCToolWidgetItem(const QString& name, QWidget *parent) : _component(-1) { startEditAction = new QAction(tr("Edit %1").arg(qgcToolWidgetItemName), this); - connect(startEditAction, SIGNAL(triggered()), this, SLOT(startEditMode())); stopEditAction = new QAction(tr("Finish Editing %1").arg(qgcToolWidgetItemName), this); - connect(stopEditAction, SIGNAL(triggered()), this, SLOT(endEditMode())); deleteAction = new QAction(tr("Delete %1").arg(qgcToolWidgetItemName), this); +} + +void QGCToolWidgetItem::init() +{ + connect(startEditAction, SIGNAL(triggered()), this, SLOT(startEditMode())); + connect(stopEditAction, SIGNAL(triggered()), this, SLOT(endEditMode())); connect(deleteAction, SIGNAL(triggered()), this, SLOT(deleteLater())); connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*))); + // Set first UAS if it exists setActiveUAS(UASManager::instance()->getActiveUAS()); } diff --git a/src/ui/designer/QGCToolWidgetItem.h b/src/ui/designer/QGCToolWidgetItem.h index a3b96861090809f709bd0b7024f1c4cfbae3e250..69a133add6beea2b82581f142640fe860053058d 100644 --- a/src/ui/designer/QGCToolWidgetItem.h +++ b/src/ui/designer/QGCToolWidgetItem.h @@ -37,6 +37,7 @@ signals: protected: void contextMenuEvent (QContextMenuEvent* event); + void init(); UASInterface* uas; private: diff --git a/src/ui/map/QGCMapToolBar.cc b/src/ui/map/QGCMapToolBar.cc index 16616a7455d78cca18963561d7b5df464e45af0a..97c972a775bfcdb82f21124a25ff1564d8f52ba8 100644 --- a/src/ui/map/QGCMapToolBar.cc +++ b/src/ui/map/QGCMapToolBar.cc @@ -12,7 +12,8 @@ QGCMapToolBar::QGCMapToolBar(QWidget *parent) : mapTypesMenu(this), trailSettingsGroup(new QActionGroup(this)), updateTimesGroup(new QActionGroup(this)), - mapTypesGroup(new QActionGroup(this)) + mapTypesGroup(new QActionGroup(this)), + statusMaxLen(15) { ui->setupUi(this); } @@ -27,6 +28,7 @@ void QGCMapToolBar::setMap(QGCMapWidget* map) connect(ui->goHomeButton, SIGNAL(clicked()), map, SLOT(goHome())); connect(ui->lastPosButton, SIGNAL(clicked()), map, SLOT(loadSettings())); connect(ui->clearTrailsButton, SIGNAL(clicked()), map, SLOT(deleteTrails())); + connect(ui->lockCheckBox, SIGNAL(clicked(bool)), map, SLOT(setZoomBlocked(bool))); connect(map, SIGNAL(OnTileLoadStart()), this, SLOT(tileLoadStart())); connect(map, SIGNAL(OnTileLoadComplete()), this, SLOT(tileLoadEnd())); connect(map, SIGNAL(OnTilesStillToLoad(int)), this, SLOT(tileLoadProgress(int))); @@ -168,11 +170,16 @@ void QGCMapToolBar::setUAVTrailTime() if (ok) { (map->setTrailModeTimed(trailTime)); - ui->posLabel->setText(tr("Trail mode: Every %1 second%2").arg(trailTime).arg((trailTime > 1) ? "s" : "")); + setStatusLabelText(tr("Trail mode: Every %1 second%2").arg(trailTime).arg((trailTime > 1) ? "s" : "")); } } } +void QGCMapToolBar::setStatusLabelText(const QString &text) +{ + ui->posLabel->setText(text.leftJustified(statusMaxLen, QChar('.'), true)); +} + void QGCMapToolBar::setUAVTrailDistance() { QObject* sender = QObject::sender(); @@ -185,7 +192,7 @@ void QGCMapToolBar::setUAVTrailDistance() if (ok) { map->setTrailModeDistance(trailDistance); - ui->posLabel->setText(tr("Trail mode: Every %1 meter%2").arg(trailDistance).arg((trailDistance == 1) ? "s" : "")); + setStatusLabelText(tr("Trail mode: Every %1 meter%2").arg(trailDistance).arg((trailDistance == 1) ? "s" : "")); } } } @@ -202,7 +209,7 @@ void QGCMapToolBar::setUpdateInterval() if (ok) { map->setUpdateRateLimit(time); - ui->posLabel->setText(tr("Map update rate limit: %1 second%2").arg(time).arg((time != 1.0f) ? "s" : "")); + setStatusLabelText(tr("Limit: %1 second%2").arg(time).arg((time != 1.0f) ? "s" : "")); } } } @@ -219,30 +226,30 @@ void QGCMapToolBar::setMapType() if (ok) { map->SetMapType((MapType::Types)mapType); - ui->posLabel->setText(tr("Map type: %1").arg(mapType)); + setStatusLabelText(tr("Map: %1").arg(mapType)); } } } void QGCMapToolBar::tileLoadStart() { - ui->posLabel->setText(tr("Starting to load tiles..")); + setStatusLabelText(tr("Loading")); } void QGCMapToolBar::tileLoadEnd() { - ui->posLabel->setText(tr("Finished")); + setStatusLabelText(tr("Finished")); } void QGCMapToolBar::tileLoadProgress(int progress) { if (progress == 1) { - ui->posLabel->setText(tr("1 tile to load..")); + setStatusLabelText(tr("1 tile")); } else if (progress > 0) { - ui->posLabel->setText(tr("%1 tiles to load..").arg(progress)); + setStatusLabelText(tr("%1 tile").arg(progress)); } else { diff --git a/src/ui/map/QGCMapToolBar.h b/src/ui/map/QGCMapToolBar.h index b03d2b9fdb6864e003a98a9fb019971e1cab54f1..e93e1e817bae6636b7e83e1dc1ae10d56a72a0da 100644 --- a/src/ui/map/QGCMapToolBar.h +++ b/src/ui/map/QGCMapToolBar.h @@ -29,6 +29,7 @@ public slots: void setUAVTrailDistance(); void setUpdateInterval(); void setMapType(); + void setStatusLabelText(const QString &text); private: Ui::QGCMapToolBar *ui; @@ -43,6 +44,8 @@ protected: QActionGroup* trailSettingsGroup; QActionGroup* updateTimesGroup; QActionGroup* mapTypesGroup; + + unsigned statusMaxLen; }; #endif // QGCMAPTOOLBAR_H diff --git a/src/ui/map/QGCMapToolBar.ui b/src/ui/map/QGCMapToolBar.ui index 91840d452413b657b9ff211c98e08d2c8934ab69..6ad334a823eec3e421540534747d489b38333cb0 100644 --- a/src/ui/map/QGCMapToolBar.ui +++ b/src/ui/map/QGCMapToolBar.ui @@ -13,11 +13,20 @@ Form - + 2 - + + 4 + + + 4 + + + 4 + + 4 @@ -62,6 +71,13 @@ + + + + Lock + + + diff --git a/src/ui/map/QGCMapWidget.cc b/src/ui/map/QGCMapWidget.cc index 4cb9098d032c9c9be7754b822266a23317769a02..b13849db84e77af49a622252bb3a37d3e57e71d4 100644 --- a/src/ui/map/QGCMapWidget.cc +++ b/src/ui/map/QGCMapWidget.cc @@ -16,7 +16,9 @@ QGCMapWidget::QGCMapWidget(QWidget *parent) : trailInterval(2.0f), followUAVID(0), mapInitialized(false), + mapPositionInitialized(false), homeAltitude(0), + zoomBlocked(false), uas(NULL) { currWPManager = UASManager::instance()->getActiveUASWaypointManager(); @@ -169,6 +171,12 @@ void QGCMapWidget::mouseReleaseEvent(QMouseEvent *event) { mousePressPos = event->pos(); mapcontrol::OPMapWidget::mouseReleaseEvent(event); + + // If the mouse is released, we can't be dragging + if (firingWaypointChange) { + firingWaypointChange->setChanged(); + firingWaypointChange = NULL; + } } QGCMapWidget::~QGCMapWidget() @@ -186,6 +194,9 @@ void QGCMapWidget::showEvent(QShowEvent* event) // Pass on to parent widget OPMapWidget::showEvent(event); + // Connect map updates to the adapter slots + connect(this, SIGNAL(WPValuesChanged(WayPointItem*)), this, SLOT(handleMapWaypointEdit(WayPointItem*))); + connect(UASManager::instance(), SIGNAL(UASCreated(UASInterface*)), this, SLOT(addUAS(UASInterface*)), Qt::UniqueConnection); connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(activeUASSet(UASInterface*)), Qt::UniqueConnection); connect(UASManager::instance(), SIGNAL(homePositionChanged(double,double,double)), this, SLOT(updateHomePosition(double,double,double))); @@ -211,16 +222,15 @@ void QGCMapWidget::showEvent(QShowEvent* event) setFrameStyle(QFrame::NoFrame); // no border frame setBackgroundBrush(QBrush(Qt::black)); // tile background - // Set current home position + if (!UASManager::instance()->getActiveUAS()) { + SetCurrentPosition(pos_lat_lon); // set the map position to default + } + + // Set home updateHomePosition(UASManager::instance()->getHomeLatitude(), UASManager::instance()->getHomeLongitude(), UASManager::instance()->getHomeAltitude()); // Set currently selected system activeUASSet(UASManager::instance()->getActiveUAS()); - - // Connect map updates to the adapter slots - connect(this, SIGNAL(WPValuesChanged(WayPointItem*)), this, SLOT(handleMapWaypointEdit(WayPointItem*))); - - SetCurrentPosition(pos_lat_lon); // set the map position setFocus(); // Start timer @@ -240,6 +250,13 @@ void QGCMapWidget::hideEvent(QHideEvent* event) OPMapWidget::hideEvent(event); } +void QGCMapWidget::wheelEvent ( QWheelEvent * event ) +{ + if (!zoomBlocked) { + OPMapWidget::wheelEvent(event); + } +} + /** * @param changePosition Load also the last position from settings and update the map position. */ @@ -319,14 +336,10 @@ void QGCMapWidget::mouseDoubleClickEvent(QMouseEvent* event) // Create new waypoint internals::PointLatLng pos = map->FromLocalToLatLng(event->pos().x(), event->pos().y()); Waypoint* wp = currWPManager->createWaypoint(); - // wp->blockSignals(true); - // wp->setFrame(MAV_FRAME_GLOBAL_RELATIVE_ALT); wp->setLatitude(pos.Lat()); wp->setLongitude(pos.Lng()); wp->setFrame((MAV_FRAME)currWPManager->getFrameRecommendation()); wp->setAltitude(currWPManager->getAltitudeRecommendation()); - // wp->blockSignals(false); - // currWPManager->notifyOfChangeEditable(wp); } OPMapWidget::mouseDoubleClickEvent(event); @@ -381,6 +394,16 @@ void QGCMapWidget::activeUASSet(UASInterface* uas) connect(currWPManager, SIGNAL(waypointEditableChanged(int, Waypoint*)), this, SLOT(updateWaypoint(int,Waypoint*))); connect(this, SIGNAL(waypointCreated(Waypoint*)), currWPManager, SLOT(addWaypointEditable(Waypoint*))); connect(this, SIGNAL(waypointChanged(Waypoint*)), currWPManager, SLOT(notifyOfChangeEditable(Waypoint*))); + + if (!mapPositionInitialized) { + internals::PointLatLng pos_lat_lon = internals::PointLatLng(uas->getLatitude(), uas->getLongitude()); + SetCurrentPosition(pos_lat_lon); + + // Zoom in + SetZoom(13); + + mapPositionInitialized = true; + } } else { @@ -562,6 +585,7 @@ void QGCMapWidget::showGoToDialog() void QGCMapWidget::updateHomePosition(double latitude, double longitude, double altitude) { + qDebug() << "HOME SET TO: " << latitude << longitude << altitude; Home->SetCoord(internals::PointLatLng(latitude, longitude)); Home->SetAltitude(altitude); homeAltitude = altitude; @@ -572,7 +596,7 @@ void QGCMapWidget::updateHomePosition(double latitude, double longitude, double void QGCMapWidget::goHome() { SetCurrentPosition(Home->Coord()); - SetZoom(18); //zoom to "large RC park" size + SetZoom(17); } /** @@ -619,12 +643,6 @@ void QGCMapWidget::handleMapWaypointEdit(mapcontrol::WayPointItem* waypoint) if (!wp) WPDelete(waypoint); - // Protect from vicious double update cycle - if (firingWaypointChange == wp) return; - // Not in cycle, block now from entering it - firingWaypointChange = wp; - // // qDebug() << "UPDATING WP FROM MAP"; - // Update WP values internals::PointLatLng pos = waypoint->Coord(); @@ -632,19 +650,21 @@ void QGCMapWidget::handleMapWaypointEdit(mapcontrol::WayPointItem* waypoint) wp->blockSignals(true); wp->setLatitude(pos.Lat()); wp->setLongitude(pos.Lng()); - // XXX Magic values -// wp->setAltitude(homeAltitude + 50.0f); -// wp->setAcceptanceRadius(10.0f); wp->blockSignals(false); - internals::PointLatLng coord = waypoint->Coord(); - QString coord_str = " " + QString::number(coord.Lat(), 'f', 6) + " " + QString::number(coord.Lng(), 'f', 6); - // // qDebug() << "MAP WP COORD (MAP):" << coord_str << __FILE__ << __LINE__; - QString wp_str = QString::number(wp->getLatitude(), 'f', 6) + " " + QString::number(wp->getLongitude(), 'f', 6); - // // qDebug() << "MAP WP COORD (WP):" << wp_str << __FILE__ << __LINE__; +// internals::PointLatLng coord = waypoint->Coord(); +// QString coord_str = " " + QString::number(coord.Lat(), 'f', 6) + " " + QString::number(coord.Lng(), 'f', 6); +// qDebug() << "MAP WP COORD (MAP):" << coord_str << __FILE__ << __LINE__; +// QString wp_str = QString::number(wp->getLatitude(), 'f', 6) + " " + QString::number(wp->getLongitude(), 'f', 6); +// qDebug() << "MAP WP COORD (WP):" << wp_str << __FILE__ << __LINE__; - firingWaypointChange = NULL; + // Protect from vicious double update cycle + if (firingWaypointChange == wp) { + return; + } + // Not in cycle, block now from entering it + firingWaypointChange = wp; emit waypointChanged(wp); } diff --git a/src/ui/map/QGCMapWidget.h b/src/ui/map/QGCMapWidget.h index 2f169a9ef427a9a5f8746d90a2f64ddeab1a854c..0f6e2859ff8906c873d84c4a5c00833e82ab936f 100644 --- a/src/ui/map/QGCMapWidget.h +++ b/src/ui/map/QGCMapWidget.h @@ -124,6 +124,11 @@ public slots: } } + void setZoomBlocked(bool blocked) + { + zoomBlocked = blocked; + } + /** @brief Load the settings for this widget from disk */ void loadSettings(bool changePosition=true); /** @brief Store the settings for this widget to disk */ @@ -139,6 +144,7 @@ protected: /** @brief Initialize */ void showEvent(QShowEvent* event); void hideEvent(QHideEvent* event); + void wheelEvent(QWheelEvent* event); void mousePressEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); void mouseDoubleClickEvent(QMouseEvent* event); @@ -167,10 +173,12 @@ protected: float trailInterval; ///< Time or distance between trail items int followUAVID; ///< Which UAV should be tracked? bool mapInitialized; ///< Map initialized? + bool mapPositionInitialized; ///< The position on the map has a reasonable value? float homeAltitude; ///< Home altitude QPoint mousePressPos; ///< Mouse position when the button is released. QPoint contextMousePressPos; ///< Mouse position when context menu activated. int defaultGuidedAlt; ///< Default altitude for guided mode + bool zoomBlocked; ///< Wether zooming is blocked UASInterface *uas; ///< Currently selected UAS. }; diff --git a/src/ui/map/Waypoint2DIcon.cc b/src/ui/map/Waypoint2DIcon.cc index 83aad5b51ffe6b33dba7ff27fbeb9b5694fead44..23d7eb74a9db000d0e5dd58dae88b2fc53e5a49e 100644 --- a/src/ui/map/Waypoint2DIcon.cc +++ b/src/ui/map/Waypoint2DIcon.cc @@ -303,7 +303,8 @@ void Waypoint2DIcon::paint(QPainter *painter, const QStyleOptionGraphicsItem *op QPen penDash(color); penDash.setWidth(1); //penDash.setStyle(Qt::DotLine); - const int loiter = map->metersToPixels(waypoint->getLoiterOrbit(), Coord()); + // A negative radius indicates counter-clockwise rotation, but we still want to draw it positive + const int loiter = map->metersToPixels(fabsf(waypoint->getLoiterOrbit()), Coord()); if (loiter > picture.width()/2) { painter->setPen(penBlack); diff --git a/src/ui/px4_configuration/QGCPX4AirframeConfig.cc b/src/ui/px4_configuration/QGCPX4AirframeConfig.cc index f77111754d23e725bd59b0c4e0e31067d53eeb12..65e59b1f0eaeb3f44a1f0c3dfd220eb8f6ba4acd 100644 --- a/src/ui/px4_configuration/QGCPX4AirframeConfig.cc +++ b/src/ui/px4_configuration/QGCPX4AirframeConfig.cc @@ -25,9 +25,8 @@ QGCPX4AirframeConfig::QGCPX4AirframeConfig(QWidget *parent) : // Fill the lists here manually in accordance with the list from: // https://github.com/PX4/Firmware/blob/master/ROMFS/px4fmu_common/init.d/rcS - ui->simComboBox->addItem(tr("Plane Sensor (HilStar, X-Plane)"), 1000); - ui->simComboBox->addItem(tr("Plane Sensor (Rascal, FlightGear)"), 1004); - //ui->simComboBox->addItem(tr("Plane State (HilStar, X-Plane)"), 1002); + ui->simComboBox->addItem(tr("Plane (HilStar, X-Plane)"), 1000); + ui->simComboBox->addItem(tr("Plane (Rascal, FlightGear)"), 1004); ui->simComboBox->addItem(tr("Quad X HIL"), 1001); ui->simComboBox->addItem(tr("Quad + HIL"), 1003); @@ -57,8 +56,7 @@ QGCPX4AirframeConfig::QGCPX4AirframeConfig(QWidget *parent) : ui->quadXComboBox->addItem(tr("DJI F330 8\" Quad"), 4010); ui->quadXComboBox->addItem(tr("DJI F450 10\" Quad"), 4011); ui->quadXComboBox->addItem(tr("Turnigy Talon v2 X550 Quad"), 4012); - //ui->quadXComboBox->addItem(tr("AR.Drone Frame Quad"), 4008); - //ui->quadXComboBox->addItem(tr("AR.Drone Quad (w. PX4FLOW)"), 4009); + ui->quadXComboBox->addItem(tr("AR.Drone Frame Quad"), 4008); ui->quadXComboBox->addItem(tr("DJI F330 with MK BLCTRL"), 4017); ui->quadXComboBox->addItem(tr("Mikrokopter X frame"), 4019); @@ -99,6 +97,7 @@ QGCPX4AirframeConfig::QGCPX4AirframeConfig(QWidget *parent) : ui->hComboBox->addItem(tr("3DR Iris"), 10016); ui->hComboBox->addItem(tr("TBS Discovery"), 10015); + ui->hComboBox->addItem(tr("SteadiDrone QU4D"), 10017); connect(ui->hPushButton, SIGNAL(clicked()), this, SLOT(hSelected())); connect(ui->hComboBox, SIGNAL(activated(int)), this, SLOT(hSelected(int))); diff --git a/src/ui/px4_configuration/QGCPX4SensorCalibration.cc b/src/ui/px4_configuration/QGCPX4SensorCalibration.cc index 077111f6a858d3017b5426f24c119c33e4c78b22..a17174f39540cb46913101c3f28002ab4d0d141b 100644 --- a/src/ui/px4_configuration/QGCPX4SensorCalibration.cc +++ b/src/ui/px4_configuration/QGCPX4SensorCalibration.cc @@ -337,6 +337,15 @@ void QGCPX4SensorCalibration::setActiveUAS(UASInterface* uas) connect(uas, SIGNAL(textMessageReceived(int,int,int,QString)), this, SLOT(handleTextMessage(int,int,int,QString))); connect(uas, SIGNAL(parameterChanged(int,int,QString,QVariant)), this, SLOT(parameterChanged(int,int,QString,QVariant))); activeUAS = uas; + + if (activeUAS->isRotaryWing()) { + // Users are confused by the config button + ui->diffPressureButton->hide(); + ui->diffPressureLabel->hide(); + } else { + ui->diffPressureButton->show(); + ui->diffPressureLabel->show(); + } } void QGCPX4SensorCalibration::handleTextMessage(int uasid, int compId, int severity, QString text) diff --git a/src/ui/uas/UASControlWidget.cc b/src/ui/uas/UASControlWidget.cc index bf26d918bea7978272f55b870e0db99e6e0e12c9..d8ccfd48b8b5e8f462db35bf86878777f6a7aa76 100644 --- a/src/ui/uas/UASControlWidget.cc +++ b/src/ui/uas/UASControlWidget.cc @@ -80,10 +80,10 @@ void UASControlWidget::updateModesList() px4_cm.main_mode = PX4_CUSTOM_MAIN_MODE_MANUAL; modes_list_px4[0].customMode = px4_cm.data; modes_list_px4[1].baseMode = MAV_MODE_FLAG_CUSTOM_MODE_ENABLED | MAV_MODE_FLAG_MANUAL_INPUT_ENABLED | MAV_MODE_FLAG_STABILIZE_ENABLED; - px4_cm.main_mode = PX4_CUSTOM_MAIN_MODE_SEATBELT; + px4_cm.main_mode = PX4_CUSTOM_MAIN_MODE_ALTCTL; modes_list_px4[1].customMode = px4_cm.data; modes_list_px4[2].baseMode = MAV_MODE_FLAG_CUSTOM_MODE_ENABLED | MAV_MODE_FLAG_MANUAL_INPUT_ENABLED | MAV_MODE_FLAG_STABILIZE_ENABLED | MAV_MODE_FLAG_GUIDED_ENABLED; - px4_cm.main_mode = PX4_CUSTOM_MAIN_MODE_EASY; + px4_cm.main_mode = PX4_CUSTOM_MAIN_MODE_POSCTL; modes_list_px4[2].customMode = px4_cm.data; modes_list_px4[3].baseMode = MAV_MODE_FLAG_CUSTOM_MODE_ENABLED | MAV_MODE_FLAG_AUTO_ENABLED | MAV_MODE_FLAG_STABILIZE_ENABLED | MAV_MODE_FLAG_GUIDED_ENABLED; px4_cm.main_mode = PX4_CUSTOM_MAIN_MODE_AUTO; diff --git a/src/ui/uas/UASView.cc b/src/ui/uas/UASView.cc index 61843f6092ed791adcb733bfd6367b856e834f3c..7affc73f143e323898f85deb6bb3c990b2d65758 100644 --- a/src/ui/uas/UASView.cc +++ b/src/ui/uas/UASView.cc @@ -634,16 +634,26 @@ void UASView::refresh() // Thrust m_ui->thrustBar->setValue(thrust * 100); + // Time Elapsed + //QDateTime time = MG::TIME::msecToQDateTime(uas->getUptime()); + + quint64 filterTime = uas->getUptime() / 1000; + int hours = static_cast(filterTime / 3600); + int min = static_cast((filterTime - 3600 * hours) / 60); + int sec = static_cast(filterTime - 60 * min - 3600 * hours); + QString timeText; + timeText = timeText.sprintf("%02d:%02d:%02d", hours, min, sec); + m_ui->timeElapsedLabel->setText(timeText); + if(this->timeRemaining > 1 && this->timeRemaining < QGC::MAX_FLIGHT_TIME) { // Filter output to get a higher stability filterTime = static_cast(this->timeRemaining); - filterTime = 0.8 * filterTime + 0.2 * static_cast(this->timeRemaining); - int sec = static_cast(filterTime - static_cast(filterTime / 60.0f) * 60); - int min = static_cast(filterTime / 60); - int hours = static_cast(filterTime - min * 60 - sec); + // filterTime = 0.8 * filterTime + 0.2 * static_cast(this->timeRemaining); + hours = static_cast(filterTime / 3600); + min = static_cast((filterTime - 3600 * hours) / 60); + sec = static_cast(filterTime - 60 * min - 3600 * hours); - QString timeText; timeText = timeText.sprintf("%02d:%02d:%02d", hours, min, sec); m_ui->timeRemainingLabel->setText(timeText); } @@ -652,16 +662,7 @@ void UASView::refresh() m_ui->timeRemainingLabel->setText(tr("Calc..")); } - // Time Elapsed - //QDateTime time = MG::TIME::msecToQDateTime(uas->getUptime()); - quint64 filterTime = uas->getUptime() / 1000; - int sec = static_cast(filterTime - static_cast(filterTime / 60) * 60); - int min = static_cast(filterTime / 60); - int hours = static_cast(filterTime - min * 60 - sec); - QString timeText; - timeText = timeText.sprintf("%02d:%02d:%02d", hours, min, sec); - m_ui->timeElapsedLabel->setText(timeText); } generalUpdateCount++;