diff --git a/HISTORY.txt b/HISTORY.txt index 2525b4736..4d22602df 100644 --- a/HISTORY.txt +++ b/HISTORY.txt @@ -1,5 +1,19 @@ Short summary of changes. For a complete list see the git log. +2012-06-04 +AeroSimRC support merged into next + +2012-05-26 +VirtualFlybar which allows a more aggressive flight mode than rate mode +support. Also PiroCompensation added. + +2012-05-26 +Revert some UI changes that didn't work consistently between OSX and Windows. + +2012-05-24 +Merged the updated firmware for the PipXtreme, thanks to Brian for a lot of +work on this. + 2012-05-04 Support for CC3D. This involved changes to various things such as the sensors being split from AttitudeRaw to Accels,Gyros,Magnetometer. A single firmware diff --git a/Makefile b/Makefile index 1e7df4211..67571d3f8 100644 --- a/Makefile +++ b/Makefile @@ -630,7 +630,7 @@ all_$(1)_clean: $$(addsuffix _clean, $$(filter bu_$(1), $$(BU_TARGETS))) all_$(1)_clean: $$(addsuffix _clean, $$(filter ef_$(1), $$(EF_TARGETS))) endef -ALL_BOARDS := coptercontrol pipxtreme revolution simposix +ALL_BOARDS := coptercontrol pipxtreme # Friendly names of each board (used to find source tree) coptercontrol_friendly := CopterControl diff --git a/flight/CopterControl/System/pios_board.c b/flight/CopterControl/System/pios_board.c index 2db478a07..42d5a4bfe 100644 --- a/flight/CopterControl/System/pios_board.c +++ b/flight/CopterControl/System/pios_board.c @@ -122,6 +122,7 @@ static const struct flashfs_cfg flashfs_w25x_cfg = { .obj_table_start = 0x00000010, .obj_table_end = 0x00001000, .sector_size = 0x00001000, + .chip_size = 0x00080000, }; static const struct pios_flash_jedec_cfg flash_w25x_cfg = { @@ -135,6 +136,7 @@ static const struct flashfs_cfg flashfs_m25p_cfg = { .obj_table_start = 0x00000010, .obj_table_end = 0x00010000, .sector_size = 0x00010000, + .chip_size = 0x00200000, }; static const struct pios_flash_jedec_cfg flash_m25p_cfg = { diff --git a/flight/Modules/Attitude/attitude.c b/flight/Modules/Attitude/attitude.c index 47604be34..02ba45744 100644 --- a/flight/Modules/Attitude/attitude.c +++ b/flight/Modules/Attitude/attitude.c @@ -234,17 +234,21 @@ static void AttitudeTask(void *parameters) AccelsData accels; GyrosData gyros; - int32_t retval; - if(cc3d) + int32_t retval = 0; + + if (cc3d) retval = updateSensorsCC3D(&accels, &gyros); else retval = updateSensors(&accels, &gyros); - if(retval != 0) + // Only update attitude when sensor data is good + if (retval != 0) AlarmsSet(SYSTEMALARMS_ALARM_ATTITUDE, SYSTEMALARMS_ALARM_ERROR); else { - // Only update attitude when sensor data is good - updateAttitude(&accels, &gyros); + // Do not update attitude data in simulation mode + if (!AttitudeActualReadOnly()) + updateAttitude(&accels, &gyros); + AlarmsClear(SYSTEMALARMS_ALARM_ATTITUDE); } } @@ -267,7 +271,11 @@ static int32_t updateSensors(AccelsData * accels, GyrosData * gyros) AlarmsSet(SYSTEMALARMS_ALARM_ATTITUDE, SYSTEMALARMS_ALARM_ERROR); return -1; } - + + // Do not read raw sensor data in simulation mode + if (GyrosReadOnly() || AccelsReadOnly()) + return 0; + // No accel data available if(PIOS_ADXL345_FifoElements() == 0) return -1; diff --git a/flight/Modules/ManualControl/manualcontrol.c b/flight/Modules/ManualControl/manualcontrol.c index 8ffe1a77f..cc188e602 100644 --- a/flight/Modules/ManualControl/manualcontrol.c +++ b/flight/Modules/ManualControl/manualcontrol.c @@ -586,6 +586,7 @@ static void updateStabilizationDesired(ManualControlCommandData * cmd, ManualCon (stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_WEAKLEVELING) ? cmd->Roll * stabSettings.ManualRate[STABILIZATIONSETTINGS_MANUALRATE_ROLL] : (stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE) ? cmd->Roll * stabSettings.RollMax : (stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_AXISLOCK) ? cmd->Roll * stabSettings.ManualRate[STABILIZATIONSETTINGS_MANUALRATE_ROLL] : + (stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_VIRTUALBAR) ? cmd->Roll : 0; // this is an invalid mode ; stabilization.Pitch = (stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_NONE) ? cmd->Pitch : @@ -593,6 +594,7 @@ static void updateStabilizationDesired(ManualControlCommandData * cmd, ManualCon (stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_WEAKLEVELING) ? cmd->Pitch * stabSettings.ManualRate[STABILIZATIONSETTINGS_MANUALRATE_PITCH] : (stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE) ? cmd->Pitch * stabSettings.PitchMax : (stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_AXISLOCK) ? cmd->Pitch * stabSettings.ManualRate[STABILIZATIONSETTINGS_MANUALRATE_PITCH] : + (stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_VIRTUALBAR) ? cmd->Pitch : 0; // this is an invalid mode stabilization.Yaw = (stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_NONE) ? cmd->Yaw : @@ -600,6 +602,7 @@ static void updateStabilizationDesired(ManualControlCommandData * cmd, ManualCon (stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_WEAKLEVELING) ? cmd->Yaw * stabSettings.ManualRate[STABILIZATIONSETTINGS_MANUALRATE_YAW] : (stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE) ? cmd->Yaw * stabSettings.YawMax : (stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_AXISLOCK) ? cmd->Yaw * stabSettings.ManualRate[STABILIZATIONSETTINGS_MANUALRATE_YAW] : + (stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_VIRTUALBAR) ? cmd->Yaw : 0; // this is an invalid mode stabilization.Throttle = (cmd->Throttle < 0) ? -1 : cmd->Throttle; diff --git a/flight/Modules/Stabilization/stabilization.c b/flight/Modules/Stabilization/stabilization.c index 571e6ac7a..b08a90076 100644 --- a/flight/Modules/Stabilization/stabilization.c +++ b/flight/Modules/Stabilization/stabilization.c @@ -55,7 +55,7 @@ #define TASK_PRIORITY (tskIDLE_PRIORITY+4) #define FAILSAFE_TIMEOUT_MS 30 -enum {PID_RATE_ROLL, PID_RATE_PITCH, PID_RATE_YAW, PID_ROLL, PID_PITCH, PID_YAW, PID_MAX}; +enum {PID_RATE_ROLL, PID_RATE_PITCH, PID_RATE_YAW, PID_ROLL, PID_PITCH, PID_YAW, PID_VBAR_ROLL, PID_VBAR_PITCH, PID_VBAR_YAW, PID_MAX}; enum {ROLL,PITCH,YAW,MAX_AXES}; @@ -74,21 +74,24 @@ typedef struct { static xTaskHandle taskHandle; static StabilizationSettingsData settings; static xQueueHandle queue; -float dT = 1; float gyro_alpha = 0; float gyro_filtered[3] = {0,0,0}; float axis_lock_accum[3] = {0,0,0}; +float vbar_sensitivity[3] = {1, 1, 1}; uint8_t max_axis_lock = 0; uint8_t max_axislock_rate = 0; float weak_leveling_kp = 0; uint8_t weak_leveling_max = 0; bool lowThrottleZeroIntegral; - +float vbar_integral[3] = {0, 0, 0}; +float vbar_decay = 0.991f; pid_type pids[PID_MAX]; +int8_t vbar_gyros_suppress; +bool vbar_piro_comp = false; // Private functions static void stabilizationTask(void* parameters); -static float ApplyPid(pid_type * pid, const float err); +static float ApplyPid(pid_type * pid, const float err, float dT); static float bound(float val); static void ZeroPids(void); static void SettingsUpdatedCb(UAVObjEvent * ev); @@ -154,6 +157,8 @@ static void stabilizationTask(void* parameters) // Main task loop ZeroPids(); while(1) { + float dT; + PIOS_WDG_UpdateFlag(PIOS_WDG_STABILIZATION); // Wait until the AttitudeRaw object is updated, if a timeout then go to failsafe @@ -227,6 +232,7 @@ static void stabilizationTask(void* parameters) switch(stabDesired.StabilizationMode[i]) { case STABILIZATIONDESIRED_STABILIZATIONMODE_RATE: + case STABILIZATIONDESIRED_STABILIZATIONMODE_VIRTUALBAR: rateDesiredAxis[i] = attitudeDesiredAxis[i]; // Zero attitude and axis lock accumulators @@ -251,7 +257,7 @@ static void stabilizationTask(void* parameters) break; } case STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE: - rateDesiredAxis[i] = ApplyPid(&pids[PID_ROLL + i], local_error[i]); + rateDesiredAxis[i] = ApplyPid(&pids[PID_ROLL + i], local_error[i], dT); if(rateDesiredAxis[i] > settings.MaximumRate[i]) rateDesiredAxis[i] = settings.MaximumRate[i]; @@ -275,7 +281,7 @@ static void stabilizationTask(void* parameters) else if(axis_lock_accum[i] < -max_axis_lock) axis_lock_accum[i] = -max_axis_lock; - rateDesiredAxis[i] = ApplyPid(&pids[PID_ROLL + i], axis_lock_accum[i]); + rateDesiredAxis[i] = ApplyPid(&pids[PID_ROLL + i], axis_lock_accum[i], dT); } if(rateDesiredAxis[i] > settings.MaximumRate[i]) @@ -287,42 +293,78 @@ static void stabilizationTask(void* parameters) } } + // Piro compensation rotates the virtual flybar by yaw step to keep it + // rotated to external world + if (vbar_piro_comp) { + const float F_PI = 3.14159f; + float cy = cosf(gyro_filtered[2] / 180.0f * F_PI * dT); + float sy = sinf(gyro_filtered[2] / 180.0f * F_PI * dT); + + float vbar_pitch = cy * vbar_integral[1] - sy * vbar_integral[0]; + float vbar_roll = sy * vbar_integral[1] + cy * vbar_integral[0]; + + vbar_integral[1] = vbar_pitch; + vbar_integral[0] = vbar_roll; + } + uint8_t shouldUpdate = 1; #if defined(DIAGNOSTICS) RateDesiredSet(&rateDesired); #endif ActuatorDesiredGet(&actuatorDesired); //Calculate desired command - for(int8_t ct=0; ct< MAX_AXES; ct++) + for(uint32_t i = 0; i < MAX_AXES; i++) { - switch(stabDesired.StabilizationMode[ct]) + switch(stabDesired.StabilizationMode[i]) { case STABILIZATIONDESIRED_STABILIZATIONMODE_RATE: case STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE: case STABILIZATIONDESIRED_STABILIZATIONMODE_AXISLOCK: case STABILIZATIONDESIRED_STABILIZATIONMODE_WEAKLEVELING: { - float command = ApplyPid(&pids[PID_RATE_ROLL + ct], rateDesiredAxis[ct] - gyro_filtered[ct]); - actuatorDesiredAxis[ct] = bound(command); + float command = ApplyPid(&pids[PID_RATE_ROLL + i], rateDesiredAxis[i] - gyro_filtered[i], dT); + actuatorDesiredAxis[i] = bound(command); + break; + } + case STABILIZATIONDESIRED_STABILIZATIONMODE_VIRTUALBAR: + { + // Track the angle of the virtual flybar which includes a slow decay + vbar_integral[i] = vbar_integral[i] * vbar_decay + gyro_filtered[i] * dT; + if (vbar_integral[i] > settings.VbarMaxAngle) + vbar_integral[i] = settings.VbarMaxAngle; + if (-vbar_integral[i] < -settings.VbarMaxAngle) + vbar_integral[i] = -settings.VbarMaxAngle; + + // Command signal is composed of stick input added to the gyro and virtual flybar + float gyro_gain = 1.0f; + if (vbar_gyros_suppress > 0) { + gyro_gain = (1.0f - fabs(rateDesiredAxis[i]) * vbar_gyros_suppress / 100.0f); + gyro_gain = (gyro_gain < 0) ? 0 : gyro_gain; + } + float command = rateDesiredAxis[i] * vbar_sensitivity[i] - gyro_gain * ( + vbar_integral[i] * pids[PID_VBAR_ROLL + i].i + + gyro_filtered[i] * pids[PID_VBAR_ROLL + i].p); + + actuatorDesiredAxis[i] = bound(command); break; } case STABILIZATIONDESIRED_STABILIZATIONMODE_NONE: - switch (ct) + switch (i) { case ROLL: - actuatorDesiredAxis[ct] = bound(attitudeDesiredAxis[ct]); + actuatorDesiredAxis[i] = bound(attitudeDesiredAxis[i]); shouldUpdate = 1; pids[PID_RATE_ROLL].iAccumulator = 0; pids[PID_ROLL].iAccumulator = 0; break; case PITCH: - actuatorDesiredAxis[ct] = bound(attitudeDesiredAxis[ct]); + actuatorDesiredAxis[i] = bound(attitudeDesiredAxis[i]); shouldUpdate = 1; pids[PID_RATE_PITCH].iAccumulator = 0; pids[PID_PITCH].iAccumulator = 0; break; case YAW: - actuatorDesiredAxis[ct] = bound(attitudeDesiredAxis[ct]); + actuatorDesiredAxis[i] = bound(attitudeDesiredAxis[i]); shouldUpdate = 1; pids[PID_RATE_YAW].iAccumulator = 0; pids[PID_YAW].iAccumulator = 0; @@ -360,7 +402,7 @@ static void stabilizationTask(void* parameters) } } -float ApplyPid(pid_type * pid, const float err) +float ApplyPid(pid_type * pid, const float err, float dT) { float diff = (err - pid->lastErr); pid->lastErr = err; @@ -400,44 +442,60 @@ static float bound(float val) return val; } - static void SettingsUpdatedCb(UAVObjEvent * ev) { memset(pids,0,sizeof (pid_type) * PID_MAX); StabilizationSettingsGet(&settings); // Set the roll rate PID constants - pids[0].p = settings.RollRatePID[STABILIZATIONSETTINGS_ROLLRATEPID_KP]; - pids[0].i = settings.RollRatePID[STABILIZATIONSETTINGS_ROLLRATEPID_KI]; - pids[0].d = settings.RollRatePID[STABILIZATIONSETTINGS_ROLLRATEPID_KD]; - pids[0].iLim = settings.RollRatePID[STABILIZATIONSETTINGS_ROLLRATEPID_ILIMIT]; + pids[PID_RATE_ROLL].p = settings.RollRatePID[STABILIZATIONSETTINGS_ROLLRATEPID_KP]; + pids[PID_RATE_ROLL].i = settings.RollRatePID[STABILIZATIONSETTINGS_ROLLRATEPID_KI]; + pids[PID_RATE_ROLL].d = settings.RollRatePID[STABILIZATIONSETTINGS_ROLLRATEPID_KD]; + pids[PID_RATE_ROLL].iLim = settings.RollRatePID[STABILIZATIONSETTINGS_ROLLRATEPID_ILIMIT]; // Set the pitch rate PID constants - pids[1].p = settings.PitchRatePID[STABILIZATIONSETTINGS_PITCHRATEPID_KP]; - pids[1].i = settings.PitchRatePID[STABILIZATIONSETTINGS_PITCHRATEPID_KI]; - pids[1].d = settings.PitchRatePID[STABILIZATIONSETTINGS_PITCHRATEPID_KD]; - pids[1].iLim = settings.PitchRatePID[STABILIZATIONSETTINGS_PITCHRATEPID_ILIMIT]; + pids[PID_RATE_PITCH].p = settings.PitchRatePID[STABILIZATIONSETTINGS_PITCHRATEPID_KP]; + pids[PID_RATE_PITCH].i = settings.PitchRatePID[STABILIZATIONSETTINGS_PITCHRATEPID_KI]; + pids[PID_RATE_PITCH].d = settings.PitchRatePID[STABILIZATIONSETTINGS_PITCHRATEPID_KD]; + pids[PID_RATE_PITCH].iLim = settings.PitchRatePID[STABILIZATIONSETTINGS_PITCHRATEPID_ILIMIT]; // Set the yaw rate PID constants - pids[2].p = settings.YawRatePID[STABILIZATIONSETTINGS_YAWRATEPID_KP]; - pids[2].i = settings.YawRatePID[STABILIZATIONSETTINGS_YAWRATEPID_KI]; - pids[2].d = settings.YawRatePID[STABILIZATIONSETTINGS_YAWRATEPID_KD]; - pids[2].iLim = settings.YawRatePID[STABILIZATIONSETTINGS_YAWRATEPID_ILIMIT]; + pids[PID_RATE_YAW].p = settings.YawRatePID[STABILIZATIONSETTINGS_YAWRATEPID_KP]; + pids[PID_RATE_YAW].i = settings.YawRatePID[STABILIZATIONSETTINGS_YAWRATEPID_KI]; + pids[PID_RATE_YAW].d = settings.YawRatePID[STABILIZATIONSETTINGS_YAWRATEPID_KD]; + pids[PID_RATE_YAW].iLim = settings.YawRatePID[STABILIZATIONSETTINGS_YAWRATEPID_ILIMIT]; // Set the roll attitude PI constants - pids[3].p = settings.RollPI[STABILIZATIONSETTINGS_ROLLPI_KP]; - pids[3].i = settings.RollPI[STABILIZATIONSETTINGS_ROLLPI_KI]; - pids[3].iLim = settings.RollPI[STABILIZATIONSETTINGS_ROLLPI_ILIMIT]; + pids[PID_ROLL].p = settings.RollPI[STABILIZATIONSETTINGS_ROLLPI_KP]; + pids[PID_ROLL].i = settings.RollPI[STABILIZATIONSETTINGS_ROLLPI_KI]; + pids[PID_ROLL].iLim = settings.RollPI[STABILIZATIONSETTINGS_ROLLPI_ILIMIT]; // Set the pitch attitude PI constants - pids[4].p = settings.PitchPI[STABILIZATIONSETTINGS_PITCHPI_KP]; - pids[4].i = settings.PitchPI[STABILIZATIONSETTINGS_PITCHPI_KI]; - pids[4].iLim = settings.PitchPI[STABILIZATIONSETTINGS_PITCHPI_ILIMIT]; + pids[PID_PITCH].p = settings.PitchPI[STABILIZATIONSETTINGS_PITCHPI_KP]; + pids[PID_PITCH].i = settings.PitchPI[STABILIZATIONSETTINGS_PITCHPI_KI]; + pids[PID_PITCH].iLim = settings.PitchPI[STABILIZATIONSETTINGS_PITCHPI_ILIMIT]; // Set the yaw attitude PI constants - pids[5].p = settings.YawPI[STABILIZATIONSETTINGS_YAWPI_KP]; - pids[5].i = settings.YawPI[STABILIZATIONSETTINGS_YAWPI_KI]; - pids[5].iLim = settings.YawPI[STABILIZATIONSETTINGS_YAWPI_ILIMIT]; + pids[PID_YAW].p = settings.YawPI[STABILIZATIONSETTINGS_YAWPI_KP]; + pids[PID_YAW].i = settings.YawPI[STABILIZATIONSETTINGS_YAWPI_KI]; + pids[PID_YAW].iLim = settings.YawPI[STABILIZATIONSETTINGS_YAWPI_ILIMIT]; + + // Set the roll attitude PI constants + pids[PID_VBAR_ROLL].p = settings.VbarRollPI[STABILIZATIONSETTINGS_VBARROLLPI_KP]; + pids[PID_VBAR_ROLL].i = settings.VbarRollPI[STABILIZATIONSETTINGS_VBARROLLPI_KI]; + + // Set the pitch attitude PI constants + pids[PID_VBAR_PITCH].p = settings.VbarPitchPI[STABILIZATIONSETTINGS_VBARPITCHPI_KP]; + pids[PID_VBAR_PITCH].i = settings.VbarPitchPI[STABILIZATIONSETTINGS_VBARPITCHPI_KI]; + + // Set the yaw attitude PI constants + pids[PID_VBAR_YAW].p = settings.VbarYawPI[STABILIZATIONSETTINGS_VBARYAWPI_KP]; + pids[PID_VBAR_YAW].i = settings.VbarYawPI[STABILIZATIONSETTINGS_VBARYAWPI_KI]; + + // Need to store the vbar sensitivity + vbar_sensitivity[0] = settings.VbarSensitivity[0]; + vbar_sensitivity[1] = settings.VbarSensitivity[1]; + vbar_sensitivity[2] = settings.VbarSensitivity[2]; // Maximum deviation to accumulate for axis lock max_axis_lock = settings.MaxAxisLock; @@ -460,6 +518,11 @@ static void SettingsUpdatedCb(UAVObjEvent * ev) gyro_alpha = 0; // not trusting this to resolve to 0 else gyro_alpha = expf(-fakeDt / settings.GyroTau); + + // Compute time constant for vbar decay term based on a tau + vbar_decay = expf(-fakeDt / settings.VbarTau); + vbar_gyros_suppress = settings.VbarGyroSuppress; + vbar_piro_comp = settings.VbarPiroComp == STABILIZATIONSETTINGS_VBARPIROCOMP_TRUE; } diff --git a/flight/Modules/System/systemmod.c b/flight/Modules/System/systemmod.c index bf3ae7b01..1217ea99f 100644 --- a/flight/Modules/System/systemmod.c +++ b/flight/Modules/System/systemmod.c @@ -215,7 +215,7 @@ static void objectUpdatedCb(UAVObjEvent * ev) // Get object data ObjectPersistenceGet(&objper); - int retval = -1; + int retval = 1; // Execute action if (objper.Operation == OBJECTPERSISTENCE_OPERATION_LOAD) { if (objper.Selection == OBJECTPERSISTENCE_SELECTION_SINGLEOBJECT) { @@ -242,6 +242,13 @@ static void objectUpdatedCb(UAVObjEvent * ev) } // Save selected instance retval = UAVObjSave(obj, objper.InstanceID); + + // Not sure why this is needed + vTaskDelay(10); + + // Verify saving worked + if (retval == 0) + retval = UAVObjLoad(obj, objper.InstanceID); } else if (objper.Selection == OBJECTPERSISTENCE_SELECTION_ALLSETTINGS || objper.Selection == OBJECTPERSISTENCE_SELECTION_ALLOBJECTS) { retval = UAVObjSaveSettings(); @@ -271,9 +278,17 @@ static void objectUpdatedCb(UAVObjEvent * ev) retval = PIOS_FLASHFS_Format(); #endif } - if(retval == 0) { - objper.Operation = OBJECTPERSISTENCE_OPERATION_COMPLETED; - ObjectPersistenceSet(&objper); + switch(retval) { + case 0: + objper.Operation = OBJECTPERSISTENCE_OPERATION_COMPLETED; + ObjectPersistenceSet(&objper); + break; + case -1: + objper.Operation = OBJECTPERSISTENCE_OPERATION_ERROR; + ObjectPersistenceSet(&objper); + break; + default: + break; } } } diff --git a/flight/Modules/TxPID/txpid.c b/flight/Modules/TxPID/txpid.c index cff9c1d9e..fd350c0d4 100644 --- a/flight/Modules/TxPID/txpid.c +++ b/flight/Modules/TxPID/txpid.c @@ -275,6 +275,9 @@ static void updatePIDs(UAVObjEvent* ev) case TXPIDSETTINGS_PIDS_YAWATTITUDEILIMIT: needsUpdate |= update(&stab.YawPI[STABILIZATIONSETTINGS_YAWPI_ILIMIT], value); break; + case TXPIDSETTINGS_PIDS_GYROTAU: + needsUpdate |= update(&stab.GyroTau, value); + break; default: PIOS_Assert(0); } diff --git a/flight/PiOS/Common/pios_flashfs_objlist.c b/flight/PiOS/Common/pios_flashfs_objlist.c index a11f6b14b..4111eb029 100644 --- a/flight/PiOS/Common/pios_flashfs_objlist.c +++ b/flight/PiOS/Common/pios_flashfs_objlist.c @@ -186,6 +186,7 @@ static int32_t PIOS_FLASHFS_GetObjAddress(uint32_t objId, uint16_t instId) * @retval -2 No room in object table * @retval -3 Unable to write entry into object table * @retval -4 FS not initialized + * @retval -5 */ int32_t PIOS_FLASHFS_GetNewAddress(uint32_t objId, uint16_t instId) { @@ -206,6 +207,10 @@ int32_t PIOS_FLASHFS_GetNewAddress(uint32_t objId, uint16_t instId) if((addr + sizeof(header)) > cfg->obj_table_end) return -2; + // Verify the address is within the chip + if((addr + cfg->sector_size) > cfg->chip_size) + return -5; + if(PIOS_Flash_Jedec_WriteData(addr, (uint8_t *) &header, sizeof(header)) != 0) return -3; diff --git a/flight/PiOS/inc/pios_flashfs_objlist.h b/flight/PiOS/inc/pios_flashfs_objlist.h index 33b0bec96..a330da230 100644 --- a/flight/PiOS/inc/pios_flashfs_objlist.h +++ b/flight/PiOS/inc/pios_flashfs_objlist.h @@ -37,6 +37,7 @@ struct flashfs_cfg { uint32_t obj_table_start; uint32_t obj_table_end; uint32_t sector_size; + uint32_t chip_size; }; int32_t PIOS_FLASHFS_Init(const struct flashfs_cfg * cfg); diff --git a/flight/Revolution/System/pios_board.c b/flight/Revolution/System/pios_board.c index 0d57da254..705463186 100644 --- a/flight/Revolution/System/pios_board.c +++ b/flight/Revolution/System/pios_board.c @@ -234,6 +234,7 @@ static const struct flashfs_cfg flashfs_m25p_cfg = { .obj_table_start = 0x00000010, .obj_table_end = 0x00010000, .sector_size = 0x00010000, + .chip_size = 0x00200000, }; static const struct pios_flash_jedec_cfg flash_m25p_cfg = { diff --git a/flight/UAVObjects/inc/uavobjectmanager.h b/flight/UAVObjects/inc/uavobjectmanager.h index 20f7b1f6e..bd1dc7f5f 100644 --- a/flight/UAVObjects/inc/uavobjectmanager.h +++ b/flight/UAVObjects/inc/uavobjectmanager.h @@ -74,8 +74,8 @@ typedef enum { * * Bit(s) Name Meaning * ------ ---- ------- - * 0 access Defines the access level for the local transactions (readonly=0 and readwrite=1) - * 1 gcsAccess Defines the access level for the local GCS transactions (readonly=0 and readwrite=1), not used in the flight s/w + * 0 access Defines the access level for the local transactions (readonly=1 and readwrite=0) + * 1 gcsAccess Defines the access level for the local GCS transactions (readonly=1 and readwrite=0), not used in the flight s/w * 2 telemetryAcked Defines if an ack is required for the transactions of this object (1:acked, 0:not acked) * 3 gcsTelemetryAcked Defines if an ack is required for the transactions of this object (1:acked, 0:not acked) * 4-5 telemetryUpdateMode Update mode used by the telemetry module (UAVObjUpdateMode) diff --git a/flight/UAVObjects/uavobjectmanager.c b/flight/UAVObjects/uavobjectmanager.c index d37b00312..8dc077967 100644 --- a/flight/UAVObjects/uavobjectmanager.c +++ b/flight/UAVObjects/uavobjectmanager.c @@ -721,10 +721,11 @@ int32_t UAVObjLoad(UAVObjHandle obj, uint16_t instId) return -1; // Fire event on success - if (PIOS_FLASHFS_ObjLoad(obj, instId, instEntry->data) == 0) + int32_t retval; + if ((retval = PIOS_FLASHFS_ObjLoad(obj, instId, instEntry->data)) == 0) sendEvent(objEntry, instId, EV_UNPACKED); else - return -1; + return retval; #endif #if defined(PIOS_INCLUDE_SDCARD) diff --git a/ground/openpilotgcs/src/plugins/config/camerastabilization.ui b/ground/openpilotgcs/src/plugins/config/camerastabilization.ui index 828cded66..e535faa50 100644 --- a/ground/openpilotgcs/src/plugins/config/camerastabilization.ui +++ b/ground/openpilotgcs/src/plugins/config/camerastabilization.ui @@ -1,894 +1,835 @@ - - - CameraStabilizationWidget - - - - 0 - 0 - 720 - 567 - - - - Form - - - - - - #groupBox_5,#groupBox{ -background-color: qlineargradient(spread:pad, x1:0.507, y1:0.869318, x2:0.507, y2:0.0965909, stop:0 rgba(243, 243, 243, 255), stop:1 rgba(250, 250, 250, 255)); -border: 1px outset #999; -border-radius: 3; -font:bold; -} - -QGroupBox::title { - subcontrol-origin: margin; - subcontrol-position: top center; /* position at the top center */ - padding: 0 3px; - background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, - stop: 0 #FFOECE, stop: 1 #FFFFFF); - top: 5px; - } - - - QFrame::NoFrame - - - true - - - - - 0 - 0 - 702 - 484 - - - - - - - Qt::StrongFocus - - - Enable CameraStabilization module - - - - - - - After enabling the module, you must power cycle before using and configuring. - - - - - - - Qt::Horizontal - - - - - - - Qt::Vertical - - - QSizePolicy::Preferred - - - - 20 - 10 - - - - - - - - - 0 - 0 - - - - - 0 - 100 - - - - Basic Settings (Stabilization) - - - - - - Qt::StrongFocus - - - Camera yaw angle for 100% output value, deg. - -This value should be tuned for particular gimbal and servo. You also -have to define channel output range using Output configuration tab. - - - 180 - - - 20 - - - - - - - Qt::StrongFocus - - - Camera pitch angle for 100% output value, deg. - -This value should be tuned for particular gimbal and servo. You also -have to define channel output range using Output configuration tab. - - - 180 - - - 20 - - - - - - - Qt::StrongFocus - - - Camera roll angle for 100% output value, deg. - -This value should be tuned for particular gimbal and servo. You also -have to define channel output range using Output configuration tab. - - - 180 - - - 20 - - - - - - - Qt::StrongFocus - - - Yaw output channel for camera gimbal - - - - None - - - - - - - - Qt::StrongFocus - - - Pitch output channel for camera gimbal - - - - None - - - - - - - - Qt::StrongFocus - - - Roll output channel for camera gimbal - - - - None - - - - - - - - Output Channel - - - - - - - Output Range - - - - - - - background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); -color: rgb(255, 255, 255); -border-radius: 5; -font: bold 12px; -margin:1px; - - - Yaw - - - Qt::AlignCenter - - - - - - - background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); -color: rgb(255, 255, 255); -border-radius: 5; -font: bold 12px; -margin:1px; - - - Pitch - - - Qt::AlignCenter - - - - - - - background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); -color: rgb(255, 255, 255); -border-radius: 5; -font: bold 12px; -margin:1px; - - - Roll - - - Qt::AlignCenter - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Preferred - - - - 20 - 10 - - - - - - - - - 0 - 0 - - - - - 0 - 204 - - - - Advanced Settings (Control) - - - - - - background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); -color: rgb(255, 255, 255); -border-radius: 5; -font: bold 12px; -margin:1px; - - - Yaw - - - Qt::AlignCenter - - - - - - - background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); -color: rgb(255, 255, 255); -border-radius: 5; -font: bold 12px; -margin:1px; - - - Pitch - - - Qt::AlignCenter - - - - - - - background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); -color: rgb(255, 255, 255); -border-radius: 5; -font: bold 12px; -margin:1px; - - - Roll - - - Qt::AlignCenter - - - - - - - Qt::StrongFocus - - - Input channel to control camera yaw - -Don't forget to map this channel using Input configuration tab. - - - - None - - - - - - - - Qt::StrongFocus - - - Input channel to control camera pitch - -Don't forget to map this channel using Input configuration tab. - - - - None - - - - - - - - Qt::StrongFocus - - - Input channel to control camera roll - -Don't forget to map this channel using Input configuration tab. - - - - None - - - - - - - - Input Channel - - - - - - - Qt::StrongFocus - - - Axis stabilization mode - -Attitude: camera tracks level for the axis. Input controls the deflection. -AxisLock: camera remembers tracking attitude. Input controls the rate of deflection. - - - - Attitude - - - - - - - - Qt::StrongFocus - - - Maximum camera yaw deflection for 100% input in Attitude mode, deg. - - - 180 - - - 20 - - - - - - - Qt::StrongFocus - - - Maximum camera yaw rate for 100% input in AxisLock mode, deg/s. - - - 180 - - - 50 - - - - - - - Qt::StrongFocus - - - Input low-pass filter response time for yaw axis, ms. - -This option smoothes the stick input. Zero value disables LPF. - - - 1000 - - - 150 - - - - - - - Qt::StrongFocus - - - Axis stabilization mode - -Attitude: camera tracks level for the axis. Input controls the deflection. -AxisLock: camera remembers tracking attitude. Input controls the rate of deflection. - - - - Attitude - - - - - - - - Qt::StrongFocus - - - Maximum camera pitch deflection for 100% input in Attitude mode, deg. - - - 180 - - - 20 - - - - - - - Qt::StrongFocus - - - Maximum camera pitch rate for 100% input in AxisLock mode, deg/s. - - - 180 - - - 50 - - - - - - - Qt::StrongFocus - - - Input low-pass filter response time for pitch axis, ms. - -This option smoothes the stick input. Zero value disables LPF. - - - 1000 - - - 150 - - - - - - - Qt::StrongFocus - - - Axis stabilization mode - -Attitude: camera tracks level for the axis. Input controls the deflection. -AxisLock: camera remembers tracking attitude. Input controls the rate of deflection. - - - - Attitude - - - - - - - - Qt::StrongFocus - - - Maximum camera roll deflection for 100% input in Attitude mode, deg. - - - 180 - - - 20 - - - - - - - Qt::StrongFocus - - - Maximum camera roll rate for 100% input in AxisLock mode, deg/s. - - - 180 - - - 50 - - - - - - - Qt::StrongFocus - - - Input low-pass filter response time for roll axis, ms. - -This option smoothes the stick input. Zero value disables LPF. - - - 1000 - - - 150 - - - - - - - MaxAxisLockRate - - - - - - - Response Time - - - - - - - Input Rate - - - - - - - Input Range - - - - - - - Stabilization Mode - - - - - - - (the same value for Roll, Pitch, Yaw) - - - - - - - Qt::StrongFocus - - - Stick input deadband for all axes in AxisLock mode, deg/s. - -When stick input is within the MaxAxisLockRate range, camera tracks -current attitude. Otherwise it starts moving according to input with -rate depending on input value. - -If you have drift in your Tx controls, you may want to increase this -value. - - - 1 - - - 0.100000000000000 - - - 1.000000000000000 - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - - - - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - - 32 - 32 - - - - - true - - - - - - - - :/core/images/helpicon.svg:/core/images/helpicon.svg - - - - 32 - 32 - - - - Ctrl+S - - - false - - - true - - - - - - - Load default CameraStabilization settings except output channels - -Loaded settings are not applied automatically. You have to click the -Apply or Save button afterwards. - - - Reset To Defaults - - - - - - - Send settings to the board but do not save to the non-volatile memory - - - Apply - - - - - - - Send settings to the board and save to the non-volatile memory - - - Save - - - false - - - - - - - - - - - enableCameraStabilization - rollChannel - pitchChannel - yawChannel - rollOutputRange - pitchOutputRange - yawOutputRange - rollInputChannel - pitchInputChannel - yawInputChannel - rollStabilizationMode - pitchStabilizationMode - yawStabilizationMode - rollInputRange - pitchInputRange - yawInputRange - rollInputRate - pitchInputRate - yawInputRate - rollResponseTime - pitchResponseTime - yawResponseTime - MaxAxisLockRate - camerastabilizationHelp - camerastabilizationResetToDefaults - camerastabilizationSaveRAM - camerastabilizationSaveSD - scrollArea - - - - - - + + + CameraStabilizationWidget + + + + 0 + 0 + 720 + 739 + + + + Form + + + + + + QFrame::NoFrame + + + true + + + + + 0 + 0 + 696 + 635 + + + + + + + Qt::StrongFocus + + + Enable CameraStabilization module + + + + + + + After enabling the module, you must power cycle before using and configuring. + + + + + + + Qt::Horizontal + + + + + + + Qt::Vertical + + + QSizePolicy::Preferred + + + + 20 + 10 + + + + + + + + + 0 + 0 + + + + + 0 + 100 + + + + Basic Settings (Stabilization) + + + + + + Qt::StrongFocus + + + Camera yaw angle for 100% output value, deg. + +This value should be tuned for particular gimbal and servo. You also +have to define channel output range using Output configuration tab. + + + 180 + + + 20 + + + + + + + Qt::StrongFocus + + + Camera pitch angle for 100% output value, deg. + +This value should be tuned for particular gimbal and servo. You also +have to define channel output range using Output configuration tab. + + + 180 + + + 20 + + + + + + + Qt::StrongFocus + + + Camera roll angle for 100% output value, deg. + +This value should be tuned for particular gimbal and servo. You also +have to define channel output range using Output configuration tab. + + + 180 + + + 20 + + + + + + + Qt::StrongFocus + + + Yaw output channel for camera gimbal + + + + None + + + + + + + + Qt::StrongFocus + + + Pitch output channel for camera gimbal + + + + None + + + + + + + + Qt::StrongFocus + + + Roll output channel for camera gimbal + + + + None + + + + + + + + Output Channel + + + + + + + Output Range + + + + + + + background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); +color: rgb(255, 255, 255); +border-radius: 5; +font: bold 12px; +margin:1px; + + + Yaw + + + Qt::AlignCenter + + + + + + + background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); +color: rgb(255, 255, 255); +border-radius: 5; +font: bold 12px; +margin:1px; + + + Pitch + + + Qt::AlignCenter + + + + + + + background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); +color: rgb(255, 255, 255); +border-radius: 5; +font: bold 12px; +margin:1px; + + + Roll + + + Qt::AlignCenter + + + + + + + + + + + 0 + 0 + + + + + 0 + 204 + + + + Advanced Settings (Control) + + + + + + background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); +color: rgb(255, 255, 255); +border-radius: 5; +font: bold 12px; +margin:1px; + + + Yaw + + + Qt::AlignCenter + + + + + + + background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); +color: rgb(255, 255, 255); +border-radius: 5; +font: bold 12px; +margin:1px; + + + Pitch + + + Qt::AlignCenter + + + + + + + background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); +color: rgb(255, 255, 255); +border-radius: 5; +font: bold 12px; +margin:1px; + + + Roll + + + Qt::AlignCenter + + + + + + + Qt::StrongFocus + + + Input channel to control camera yaw + +Don't forget to map this channel using Input configuration tab. + + + + None + + + + + + + + Qt::StrongFocus + + + Input channel to control camera pitch + +Don't forget to map this channel using Input configuration tab. + + + + None + + + + + + + + Qt::StrongFocus + + + Input channel to control camera roll + +Don't forget to map this channel using Input configuration tab. + + + + None + + + + + + + + Input Channel + + + + + + + Qt::StrongFocus + + + Axis stabilization mode + +Attitude: camera tracks level for the axis. Input controls the deflection. +AxisLock: camera remembers tracking attitude. Input controls the rate of deflection. + + + + Attitude + + + + + + + + Qt::StrongFocus + + + Maximum camera yaw deflection for 100% input in Attitude mode, deg. + + + 180 + + + 20 + + + + + + + Qt::StrongFocus + + + Maximum camera yaw rate for 100% input in AxisLock mode, deg/s. + + + 180 + + + 50 + + + + + + + Qt::StrongFocus + + + Input low-pass filter response time for yaw axis, ms. + +This option smoothes the stick input. Zero value disables LPF. + + + 1000 + + + 150 + + + + + + + Qt::StrongFocus + + + Axis stabilization mode + +Attitude: camera tracks level for the axis. Input controls the deflection. +AxisLock: camera remembers tracking attitude. Input controls the rate of deflection. + + + + Attitude + + + + + + + + Qt::StrongFocus + + + Maximum camera pitch deflection for 100% input in Attitude mode, deg. + + + 180 + + + 20 + + + + + + + Qt::StrongFocus + + + Maximum camera pitch rate for 100% input in AxisLock mode, deg/s. + + + 180 + + + 50 + + + + + + + Qt::StrongFocus + + + Input low-pass filter response time for pitch axis, ms. + +This option smoothes the stick input. Zero value disables LPF. + + + 1000 + + + 150 + + + + + + + Qt::StrongFocus + + + Axis stabilization mode + +Attitude: camera tracks level for the axis. Input controls the deflection. +AxisLock: camera remembers tracking attitude. Input controls the rate of deflection. + + + + Attitude + + + + + + + + Qt::StrongFocus + + + Maximum camera roll deflection for 100% input in Attitude mode, deg. + + + 180 + + + 20 + + + + + + + Qt::StrongFocus + + + Maximum camera roll rate for 100% input in AxisLock mode, deg/s. + + + 180 + + + 50 + + + + + + + Qt::StrongFocus + + + Input low-pass filter response time for roll axis, ms. + +This option smoothes the stick input. Zero value disables LPF. + + + 1000 + + + 150 + + + + + + + MaxAxisLockRate + + + + + + + Response Time + + + + + + + Input Rate + + + + + + + Input Range + + + + + + + Stabilization Mode + + + + + + + (the same value for Roll, Pitch, Yaw) + + + + + + + Qt::StrongFocus + + + Stick input deadband for all axes in AxisLock mode, deg/s. + +When stick input is within the MaxAxisLockRate range, camera tracks +current attitude. Otherwise it starts moving according to input with +rate depending on input value. + +If you have drift in your Tx controls, you may want to increase this +value. + + + 1 + + + 0.100000000000000 + + + 1.000000000000000 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 32 + 32 + + + + + true + + + + + + + + :/core/images/helpicon.svg:/core/images/helpicon.svg + + + + 32 + 32 + + + + Ctrl+S + + + false + + + true + + + + + + + Load default CameraStabilization settings except output channels + +Loaded settings are not applied automatically. You have to click the +Apply or Save button afterwards. + + + Reset To Defaults + + + + + + + Send settings to the board but do not save to the non-volatile memory + + + Apply + + + + + + + Send settings to the board and save to the non-volatile memory + + + Save + + + false + + + + + + + + + + + enableCameraStabilization + rollChannel + pitchChannel + yawChannel + rollOutputRange + pitchOutputRange + yawOutputRange + rollInputChannel + pitchInputChannel + yawInputChannel + rollStabilizationMode + pitchStabilizationMode + yawStabilizationMode + rollInputRange + pitchInputRange + yawInputRange + rollInputRate + pitchInputRate + yawInputRate + rollResponseTime + pitchResponseTime + yawResponseTime + MaxAxisLockRate + camerastabilizationHelp + camerastabilizationResetToDefaults + camerastabilizationSaveRAM + camerastabilizationSaveSD + scrollArea + + + + + + diff --git a/ground/openpilotgcs/src/plugins/config/config_pro_hw_widget.cpp b/ground/openpilotgcs/src/plugins/config/config_pro_hw_widget.cpp index c554cae31..0f050cbc2 100644 --- a/ground/openpilotgcs/src/plugins/config/config_pro_hw_widget.cpp +++ b/ground/openpilotgcs/src/plugins/config/config_pro_hw_widget.cpp @@ -43,7 +43,7 @@ ConfigProHWWidget::ConfigProHWWidget(QWidget *parent) : ConfigTaskWidget(parent) addUAVObjectToWidgetRelation("HwSettings","TelemetrySpeed",m_telemetry->telemetrySpeed); enableControls(false); populateWidgets(); - refreshWidgetsValues(); + refreshWidgetsValues(NULL); } ConfigProHWWidget::~ConfigProHWWidget() diff --git a/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp b/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp index c73a0b9dc..ca9a6dcc4 100644 --- a/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp @@ -53,8 +53,6 @@ ConfigOutputWidget::ConfigOutputWidget(QWidget *parent) : ConfigTaskWidget(paren m_config->setupUi(this); ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - addApplySaveButtons(m_config->saveRCOutputToRAM,m_config->saveRCOutputToSD); - addUAVObject("ActuatorSettings"); UAVSettingsImportExportFactory * importexportplugin = pm->getObject(); connect(importexportplugin,SIGNAL(importAboutToBegin()),this,SLOT(stopTests())); @@ -73,25 +71,37 @@ ConfigOutputWidget::ConfigOutputWidget(QWidget *parent) : ConfigTaskWidget(paren connect(m_config->channelOutTest, SIGNAL(toggled(bool)), this, SLOT(runChannelTests(bool))); - refreshWidgetsValues(); firstUpdate = true; - connect(m_config->spinningArmed, SIGNAL(toggled(bool)), this, SLOT(setSpinningArmed(bool))); - + // Configure the task widget // Connect the help button connect(m_config->outputHelp, SIGNAL(clicked()), this, SLOT(openHelp())); + + // Add custom handling of displaying things + connect(this,SIGNAL(refreshWidgetsValuesRequested()), this, SLOT(refreshOutputWidgetsValues())); + + addApplySaveButtons(m_config->saveRCOutputToRAM,m_config->saveRCOutputToSD); + + // Track the ActuatorSettings object + addUAVObject("ActuatorSettings"); + + // Associate the buttons with their UAVO fields addWidget(m_config->cb_outputRate4); addWidget(m_config->cb_outputRate3); addWidget(m_config->cb_outputRate2); addWidget(m_config->cb_outputRate1); addWidget(m_config->spinningArmed); + disconnect(this, SLOT(refreshWidgetsValues(UAVObject*))); + UAVObjectManager *objManager = pm->getObject(); UAVObject* obj = objManager->getObject(QString("ActuatorCommand")); if(UAVObject::GetGcsTelemetryUpdateMode(obj->getMetadata()) == UAVObject::UPDATEMODE_ONCHANGE) this->setEnabled(false); connect(obj,SIGNAL(objectUpdated(UAVObject*)),this,SLOT(disableIfNotMe(UAVObject*))); + + refreshWidgetsValues(); } void ConfigOutputWidget::enableControls(bool enable) { @@ -196,24 +206,6 @@ void ConfigOutputWidget::assignOutputChannel(UAVDataObject *obj, QString str) outputChannelForm->setAssignment(str); } -/** - * Set the "Spin motors at neutral when armed" flag in ActuatorSettings - */ -void ConfigOutputWidget::setSpinningArmed(bool val) -{ - ActuatorSettings *actuatorSettings = ActuatorSettings::GetInstance(getObjectManager()); - Q_ASSERT(actuatorSettings); - ActuatorSettings::DataFields actuatorSettingsData = actuatorSettings->getData(); - - if(val) - actuatorSettingsData.MotorsSpinWhileArmed = ActuatorSettings::MOTORSSPINWHILEARMED_TRUE; - else - actuatorSettingsData.MotorsSpinWhileArmed = ActuatorSettings::MOTORSSPINWHILEARMED_FALSE; - - // Apply settings - actuatorSettings->setData(actuatorSettingsData); -} - /** Sends the channel value to the UAV to move the servo. Returns immediately if we are not in testing mode @@ -328,7 +320,16 @@ void ConfigOutputWidget::refreshWidgetsValues(UAVObject * obj) } } - setDirty(dirty); + // Get Channel ranges: + foreach(OutputChannelForm *outputChannelForm, outputChannelForms) + { + int minValue = actuatorSettingsData.ChannelMin[outputChannelForm->index()]; + int maxValue = actuatorSettingsData.ChannelMax[outputChannelForm->index()]; + outputChannelForm->minmax(minValue, maxValue); + + int neutral = actuatorSettingsData.ChannelNeutral[outputChannelForm->index()]; + outputChannelForm->neutral(neutral); + } } /** @@ -336,26 +337,36 @@ void ConfigOutputWidget::refreshWidgetsValues(UAVObject * obj) */ void ConfigOutputWidget::updateObjectsFromWidgets() { + emit updateObjectsFromWidgetsRequested(); + ActuatorSettings *actuatorSettings = ActuatorSettings::GetInstance(getObjectManager()); Q_ASSERT(actuatorSettings); - ActuatorSettings::DataFields actuatorSettingsData = actuatorSettings->getData(); + if(actuatorSettings) { + ActuatorSettings::DataFields actuatorSettingsData = actuatorSettings->getData(); - // Set channel ranges - QList outputChannelForms = findChildren(); - foreach(OutputChannelForm *outputChannelForm, outputChannelForms) - { - actuatorSettingsData.ChannelMax[outputChannelForm->index()] = outputChannelForm->max(); - actuatorSettingsData.ChannelMin[outputChannelForm->index()] = outputChannelForm->min(); - actuatorSettingsData.ChannelNeutral[outputChannelForm->index()] = outputChannelForm->neutral(); + // Set channel ranges + QList outputChannelForms = findChildren(); + foreach(OutputChannelForm *outputChannelForm, outputChannelForms) + { + actuatorSettingsData.ChannelMax[outputChannelForm->index()] = outputChannelForm->max(); + actuatorSettingsData.ChannelMin[outputChannelForm->index()] = outputChannelForm->min(); + actuatorSettingsData.ChannelNeutral[outputChannelForm->index()] = outputChannelForm->neutral(); + } + + // Set update rates + actuatorSettingsData.ChannelUpdateFreq[0] = m_config->cb_outputRate1->currentText().toUInt(); + actuatorSettingsData.ChannelUpdateFreq[1] = m_config->cb_outputRate2->currentText().toUInt(); + actuatorSettingsData.ChannelUpdateFreq[2] = m_config->cb_outputRate3->currentText().toUInt(); + actuatorSettingsData.ChannelUpdateFreq[3] = m_config->cb_outputRate4->currentText().toUInt(); + + if(m_config->spinningArmed->isChecked() == true) + actuatorSettingsData.MotorsSpinWhileArmed = ActuatorSettings::MOTORSSPINWHILEARMED_TRUE; + else + actuatorSettingsData.MotorsSpinWhileArmed = ActuatorSettings::MOTORSSPINWHILEARMED_FALSE; + + // Apply settings + actuatorSettings->setData(actuatorSettingsData); } - - // Set update rates - actuatorSettingsData.ChannelUpdateFreq[0] = m_config->cb_outputRate1->currentText().toUInt(); - actuatorSettingsData.ChannelUpdateFreq[1] = m_config->cb_outputRate2->currentText().toUInt(); - actuatorSettingsData.ChannelUpdateFreq[2] = m_config->cb_outputRate3->currentText().toUInt(); - actuatorSettingsData.ChannelUpdateFreq[3] = m_config->cb_outputRate4->currentText().toUInt(); - // Apply settings - actuatorSettings->setData(actuatorSettingsData); } void ConfigOutputWidget::openHelp() diff --git a/ground/openpilotgcs/src/plugins/config/configoutputwidget.h b/ground/openpilotgcs/src/plugins/config/configoutputwidget.h index b4d3c99dd..5ccf58206 100644 --- a/ground/openpilotgcs/src/plugins/config/configoutputwidget.h +++ b/ground/openpilotgcs/src/plugins/config/configoutputwidget.h @@ -73,7 +73,6 @@ private slots: void updateObjectsFromWidgets(); void runChannelTests(bool state); void sendChannelTest(int index, int value); - void setSpinningArmed(bool val); void openHelp(); protected: void enableControls(bool enable); diff --git a/ground/openpilotgcs/src/plugins/config/configpipxtremewidget.cpp b/ground/openpilotgcs/src/plugins/config/configpipxtremewidget.cpp index f4d20fc5d..6b169a74f 100644 --- a/ground/openpilotgcs/src/plugins/config/configpipxtremewidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configpipxtremewidget.cpp @@ -89,9 +89,17 @@ ConfigPipXtremeWidget::ConfigPipXtremeWidget(QWidget *parent) : ConfigTaskWidget timeOut = new QTimer(this); connect(timeOut, SIGNAL(timeout()),this,SLOT(disconnected())); + //Add scroll bar when necessary + QScrollArea *scroll = new QScrollArea; + scroll->setWidget(m_pipx->frame_3); + m_pipx->verticalLayout_3->addWidget(scroll); + // Request and update of the setting object. settingsUpdated = false; pipxSettingsObj->requestUpdate(); + + disableMouseWheelEvents(); + } ConfigPipXtremeWidget::~ConfigPipXtremeWidget() diff --git a/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.cpp b/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.cpp index 3f2b4d216..331c39e23 100644 --- a/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.cpp @@ -40,6 +40,11 @@ ConfigStabilizationWidget::ConfigStabilizationWidget(QWidget *parent) : ConfigTa { m_stabilization = new Ui_StabilizationWidget(); m_stabilization->setupUi(this); + + // To bring old style sheet back without adding it manually do this: + // Alternatively apply a global stylesheet to the QGroupBox + // setStyleSheet("QGroupBox {background-color: qlineargradient(spread:pad, x1:0.507, y1:0.869318, x2:0.507, y2:0.0965909, stop:0 rgba(243, 243, 243, 255), stop:1 rgba(250, 250, 250, 255)); border: 1px outset #999; border-radius: 3; }"); + autoLoadWidgets(); realtimeUpdates=new QTimer(this); connect(m_stabilization->realTimeUpdates_6,SIGNAL(stateChanged(int)),this,SLOT(realtimeUpdatesSlot(int))); @@ -54,6 +59,24 @@ ConfigStabilizationWidget::ConfigStabilizationWidget(QWidget *parent) : ConfigTa connect(this,SIGNAL(widgetContentsChanged(QWidget*)),this,SLOT(processLinkedWidgets(QWidget*))); disableMouseWheelEvents(); + + // This is needed because new style tries to compact things as much as possible in grid + // and on OSX the widget sizes of PushButtons is reported incorrectly: + // https://bugreports.qt-project.org/browse/QTBUG-14591 + m_stabilization->saveStabilizationToRAM_6->setAttribute(Qt::WA_LayoutUsesWidgetRect); + m_stabilization->saveStabilizationToSD_6->setAttribute(Qt::WA_LayoutUsesWidgetRect); + m_stabilization->stabilizationReloadBoardData_6->setAttribute(Qt::WA_LayoutUsesWidgetRect); + m_stabilization->saveStabilizationToRAM_7->setAttribute(Qt::WA_LayoutUsesWidgetRect); + m_stabilization->saveStabilizationToSD_7->setAttribute(Qt::WA_LayoutUsesWidgetRect); + m_stabilization->pushButton_2->setAttribute(Qt::WA_LayoutUsesWidgetRect); + m_stabilization->pushButton_3->setAttribute(Qt::WA_LayoutUsesWidgetRect); + m_stabilization->pushButton_4->setAttribute(Qt::WA_LayoutUsesWidgetRect); + m_stabilization->pushButton_19->setAttribute(Qt::WA_LayoutUsesWidgetRect); + m_stabilization->pushButton_20->setAttribute(Qt::WA_LayoutUsesWidgetRect); + m_stabilization->pushButton_21->setAttribute(Qt::WA_LayoutUsesWidgetRect); + m_stabilization->pushButton_22->setAttribute(Qt::WA_LayoutUsesWidgetRect); + m_stabilization->pushButton_23->setAttribute(Qt::WA_LayoutUsesWidgetRect); + m_stabilization->pushButton_24->setAttribute(Qt::WA_LayoutUsesWidgetRect); } diff --git a/ground/openpilotgcs/src/plugins/config/input.ui b/ground/openpilotgcs/src/plugins/config/input.ui index da2a59ddd..422904bb5 100644 --- a/ground/openpilotgcs/src/plugins/config/input.ui +++ b/ground/openpilotgcs/src/plugins/config/input.ui @@ -16,23 +16,6 @@ - - #groupBox_2,#groupBox{ -background-color: qlineargradient(spread:pad, x1:0.507, y1:0.869318, x2:0.507, y2:0.0965909, stop:0 rgba(243, 243, 243, 255), stop:1 rgba(250, 250, 250, 255)); -border: 1px outset #999; -border-radius: 3; -font:bold; -} - -QGroupBox::title { - subcontrol-origin: margin; - subcontrol-position: top center; /* position at the top center */ - padding: 0 3px; - background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, - stop: 0 #FFOECE, stop: 1 #FFFFFF); - top: 5px; - } - 0 @@ -246,7 +229,7 @@ QGroupBox::title { 30 160 451 - 141 + 161 @@ -442,9 +425,6 @@ margin:1px; 121 - - - FlightMode Switch Positions diff --git a/ground/openpilotgcs/src/plugins/config/inputchannelform.cpp b/ground/openpilotgcs/src/plugins/config/inputchannelform.cpp index 212621d44..e80986399 100644 --- a/ground/openpilotgcs/src/plugins/config/inputchannelform.cpp +++ b/ground/openpilotgcs/src/plugins/config/inputchannelform.cpp @@ -2,6 +2,7 @@ #include "ui_inputchannelform.h" #include "manualcontrolsettings.h" +#include "gcsreceiver.h" inputChannelForm::inputChannelForm(QWidget *parent,bool showlegend) : ConfigTaskWidget(parent), @@ -115,7 +116,7 @@ void inputChannelForm::groupUpdated() count = 18; break; case ManualControlSettings::CHANNELGROUPS_GCS: - count = 5; + count = GCSReceiver::CHANNEL_NUMELEM; break; case ManualControlSettings::CHANNELGROUPS_NONE: count = 0; diff --git a/ground/openpilotgcs/src/plugins/config/pipxtreme.ui b/ground/openpilotgcs/src/plugins/config/pipxtreme.ui index 06662e450..0b4c8b10f 100644 --- a/ground/openpilotgcs/src/plugins/config/pipxtreme.ui +++ b/ground/openpilotgcs/src/plugins/config/pipxtreme.ui @@ -7,7 +7,7 @@ 0 0 840 - 724 + 834 @@ -23,6 +23,96 @@ QFrame::Raised + + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + true + + + + + + + + + + + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Send settings to the board but do not save to the non-volatile memory + + + Apply + + + + + + + Send settings to the board and save to the non-volatile memory + + + Save + + + false + + + + + + + @@ -165,6 +255,12 @@ + + + 400 + 0 + + 75 @@ -374,7 +470,7 @@ - Frequency Step Size + Freq. Step Size Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -779,7 +875,7 @@ - Telemetry Port Configuration + Telemetry Port Config. Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -1105,13 +1201,13 @@ true - 0 + 0 - 1000000000 + 1000000000 - 100000 + 100000 @@ -1213,98 +1309,51 @@ - - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - true - - - - - - - - - - - - - - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Send settings to the board but do not save to the non-volatile memory - - - Apply - - - - - - - Send settings to the board and save to the non-volatile memory - - - Save - - - false - - - - - - - + + PairSelect1 + PairID1 + PairSelect2 + PairID2 + PairSelect3 + PairID3 + PairSelect4 + PairID4 + FirmwareVersion + SerialNumber + DeviceID + MinFrequency + MaxFrequency + FrequencyStepSize + LinkState + RxAFC + Retries + Errors + UAVTalkErrors + Resets + TXRate + RXRate + TelemPortConfig + TelemPortSpeed + FlexiPortConfig + FlexiPortSpeed + VCPConfig + VCPSpeed + MaxRFDatarate + MaxRFTxPower + SendTimeout + MinPacketSize + FrequencyCalibration + Frequency + ScanSpectrum + AESKey + AESKeyRandom + AESEnable + graphicsView_Spectrum + Apply + Save + diff --git a/ground/openpilotgcs/src/plugins/config/stabilization.ui b/ground/openpilotgcs/src/plugins/config/stabilization.ui index ef0b52a15..fd6b01ca8 100755 --- a/ground/openpilotgcs/src/plugins/config/stabilization.ui +++ b/ground/openpilotgcs/src/plugins/config/stabilization.ui @@ -495,29 +495,13 @@ 0 - 0 + -114 673 - 880 + 790 - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 10 - - - - - + Qt::Horizontal @@ -533,7 +517,7 @@ - + @@ -541,19 +525,12 @@ 16 - - - 9 - 75 - true - - Rate Stabilization (Inner Loop) - + @@ -573,530 +550,6 @@ 181 - - - - - - - 0 - 0 - 0 - - - - - - - - - 243 - 243 - 243 - - - - - 250 - 250 - 250 - - - - - - - - - 255 - 255 - 255 - - - - - - - 251 - 251 - 251 - - - - - - - 124 - 124 - 124 - - - - - - - 165 - 165 - 165 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - - - 243 - 243 - 243 - - - - - 250 - 250 - 250 - - - - - - - - - - - 243 - 243 - 243 - - - - - 250 - 250 - 250 - - - - - - - - - 0 - 0 - 0 - - - - - - - 251 - 251 - 251 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 0 - 0 - 0 - - - - - - - - - 243 - 243 - 243 - - - - - 250 - 250 - 250 - - - - - - - - - 255 - 255 - 255 - - - - - - - 251 - 251 - 251 - - - - - - - 124 - 124 - 124 - - - - - - - 165 - 165 - 165 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - - - 243 - 243 - 243 - - - - - 250 - 250 - 250 - - - - - - - - - - - 243 - 243 - 243 - - - - - 250 - 250 - 250 - - - - - - - - - 0 - 0 - 0 - - - - - - - 251 - 251 - 251 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 124 - 124 - 124 - - - - - - - - - 243 - 243 - 243 - - - - - 250 - 250 - 250 - - - - - - - - - 255 - 255 - 255 - - - - - - - 251 - 251 - 251 - - - - - - - 124 - 124 - 124 - - - - - - - 165 - 165 - 165 - - - - - - - 124 - 124 - 124 - - - - - - - 255 - 255 - 255 - - - - - - - 124 - 124 - 124 - - - - - - - - - 243 - 243 - 243 - - - - - 250 - 250 - 250 - - - - - - - - - - - 243 - 243 - 243 - - - - - 250 - 250 - 250 - - - - - - - - - 0 - 0 - 0 - - - - - - - 248 - 248 - 248 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - false - - - #RateStabilizationGroup_15{background-color: qlineargradient(spread:pad, x1:0.507, y1:0.869318, x2:0.507, y2:0.0965909, stop:0 rgba(243, 243, 243, 255), stop:1 rgba(250, 250, 250, 255)); - -border: 1px outset #999; -border-radius: 3; -} - @@ -3966,23 +3419,7 @@ value as the Kp. - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 15 - - - - - + Qt::Horizontal @@ -3998,7 +3435,7 @@ value as the Kp. - + @@ -4006,19 +3443,12 @@ value as the Kp. 16 - - - 9 - 75 - true - - Attitude Stabilization (Outer Loop) - + @@ -4555,13 +3985,6 @@ value as the Kp. false - - #RateStabilizationGroup_17{background-color: qlineargradient(spread:pad, x1:0.507, y1:0.869318, x2:0.507, y2:0.0965909, stop:0 rgba(243, 243, 243, 255), stop:1 rgba(250, 250, 250, 255)); - -border: 1px outset #999; -border-radius: 3; -} - @@ -4604,26 +4027,14 @@ border-radius: 3; - + - - - 0 - 0 - - 81 28 - - - 81 - 28 - - QPushButton { border: 1px outset #999; @@ -4656,7 +4067,7 @@ border-radius: 4; - + @@ -7335,26 +6746,14 @@ border-radius: 5; - + - - - 0 - 0 - - 51 28 - - - 51 - 28 - - QPushButton { border: 1px outset #999; @@ -7387,42 +6786,23 @@ border-radius: 4; + + + + Qt::Horizontal + + + + 40 + 20 + + + + - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 2 - 10 - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 15 - - - - - + Qt::Horizontal @@ -7438,7 +6818,7 @@ border-radius: 4; - + @@ -7446,19 +6826,12 @@ border-radius: 4; 16 - - - 9 - 75 - true - - Stick Range and Limits - + @@ -7992,16 +7365,6 @@ border-radius: 4; - - false - - - #RateStabilizationGroup_19{background-color: qlineargradient(spread:pad, x1:0.507, y1:0.869318, x2:0.507, y2:0.0965909, stop:0 rgba(243, 243, 243, 255), stop:1 rgba(250, 250, 250, 255)); - -border: 1px outset #999; -border-radius: 3; -} - @@ -8019,7 +7382,7 @@ border-radius: 3; - 10 + 1000 10 @@ -8027,24 +7390,12 @@ border-radius: 3; - - - 0 - 0 - - 51 28 - - - 51 - 28 - - QPushButton { border: 1px outset #999; @@ -8091,12 +7442,6 @@ border-radius: 4; 28 - - - 81 - 28 - - QPushButton { border: 1px outset #999; @@ -11063,23 +10408,7 @@ Attitude - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 10 - - - - - + Qt::Vertical @@ -11095,23 +10424,7 @@ Attitude - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 2 - 10 - - - - - + @@ -11648,13 +10961,6 @@ Attitude false - - #RateStabilizationGroup_21{background-color: qlineargradient(spread:pad, x1:0.507, y1:0.869318, x2:0.507, y2:0.0965909, stop:0 rgba(243, 243, 243, 255), stop:1 rgba(250, 250, 250, 255)); - -border: 1px outset #999; -border-radius: 3; -} - @@ -11734,29 +11040,12 @@ automatically every 300ms, which will help for fast tuning. - - - 0 - 0 - - 120 28 - - - 120 - 28 - - - - - 8 - - Reloads the saved settings into GCS. Useful if you have accidentally changed some settings. @@ -11795,29 +11084,12 @@ border-radius: 4; - - - 0 - 0 - - 60 28 - - - 60 - 28 - - - - - 8 - - Send settings to the board but do not save to the non-volatile memory @@ -11854,29 +11126,12 @@ border-radius: 4; - - - 0 - 0 - - 60 28 - - - 60 - 28 - - - - - 8 - - Send settings to the board and save to the non-volatile memory @@ -11939,27 +11194,11 @@ border-radius: 4; 0 0 673 - 1079 + 981 - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 25 - 10 - - - - - + Qt::Horizontal @@ -11975,7 +11214,7 @@ border-radius: 4; - + @@ -11983,19 +11222,12 @@ border-radius: 4; 16 - - - 9 - 75 - true - - Rate Stabization Coefficients (Inner Loop) - + @@ -12529,16 +11761,6 @@ border-radius: 4; - - false - - - #RateStabilizationGroup_8{background-color: qlineargradient(spread:pad, x1:0.507, y1:0.869318, x2:0.507, y2:0.0965909, stop:0 rgba(243, 243, 243, 255), stop:1 rgba(250, 250, 250, 255)); - -border: 1px outset #999; -border-radius: 3; -} - @@ -15474,55 +14696,7 @@ value as the Kp. - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 2 - 10 - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 2 - 10 - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 15 - - - - - Qt::Horizontal @@ -15538,7 +14712,7 @@ value as the Kp. - + @@ -15546,19 +14720,12 @@ value as the Kp. 16 - - - 9 - 75 - true - - Attitude Stabization Coefficients (Outer Loop) - + @@ -16095,13 +15262,6 @@ value as the Kp. false - - #RateStabilizationGroup_4{background-color: qlineargradient(spread:pad, x1:0.507, y1:0.869318, x2:0.507, y2:0.0965909, stop:0 rgba(243, 243, 243, 255), stop:1 rgba(250, 250, 250, 255)); - -border: 1px outset #999; -border-radius: 3; -} - @@ -16112,85 +15272,6 @@ border-radius: 3; false - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 10 - 10 - - - - - - - - - - - Link Roll and Pitch - - - - - - - - 0 - 0 - - - - - 81 - 28 - - - - - 81 - 28 - - - - QPushButton { -border: 1px outset #999; -border-radius: 5; -background-color: qlineargradient(spread:pad, x1:0.507, y1:0.869318, x2:0.507, y2:0.0965909, stop:0.28 rgba(236, 236, 236, 255), stop:1 rgba(252, 252, 252, 255)); -} - -QPushButton:pressed { - - border-style: inset; - background-color: qlineargradient(spread:pad, x1:0.502, y1:0.664864, x2:0.502, y2:0.034, stop:0.358209 rgba(250, 250, 250, 255), stop:0.626866 rgba(235, 235, 235, 255)); - -} - - -QPushButton:hover { - border: 1px outset #999; -border-color: rgb(83, 83, 83); -border-radius: 4; - } - - - Default - - - - objname:StabilizationSettings - button:default - buttongroup:5 - - - - @@ -18839,26 +17920,89 @@ border-radius: 5; + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 10 + 10 + + + + + + + + + 0 + 0 + + + + + 81 + 28 + + + + + 81 + 28 + + + + QPushButton { +border: 1px outset #999; +border-radius: 5; +background-color: qlineargradient(spread:pad, x1:0.507, y1:0.869318, x2:0.507, y2:0.0965909, stop:0.28 rgba(236, 236, 236, 255), stop:1 rgba(252, 252, 252, 255)); +} + +QPushButton:pressed { + + border-style: inset; + background-color: qlineargradient(spread:pad, x1:0.502, y1:0.664864, x2:0.502, y2:0.034, stop:0.358209 rgba(250, 250, 250, 255), stop:0.626866 rgba(235, 235, 235, 255)); + +} + + +QPushButton:hover { + border: 1px outset #999; +border-color: rgb(83, 83, 83); +border-radius: 4; + } + + + Default + + + + objname:StabilizationSettings + button:default + buttongroup:5 + + + + + + + + + + + Link Roll and Pitch + + + - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 15 - - - - - + Qt::Horizontal @@ -18874,7 +18018,7 @@ border-radius: 5; - + @@ -18882,19 +18026,12 @@ border-radius: 5; 16 - - - 9 - 75 - true - - Stick Range and Limits - + @@ -19428,16 +18565,6 @@ border-radius: 5; - - false - - - #RateStabilizationGroup_6{background-color: qlineargradient(spread:pad, x1:0.507, y1:0.869318, x2:0.507, y2:0.0965909, stop:0 rgba(243, 243, 243, 255), stop:1 rgba(250, 250, 250, 255)); - -border: 1px outset #999; -border-radius: 3; -} - @@ -19455,7 +18582,7 @@ border-radius: 3; - 10 + 10000 10 @@ -19463,24 +18590,12 @@ border-radius: 3; - - - 0 - 0 - - 81 28 - - - 81 - 28 - - QPushButton { border: 1px outset #999; @@ -22192,23 +21307,7 @@ rate(deg/s) - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 10 - - - - - + Qt::Horizontal @@ -22224,7 +21323,7 @@ rate(deg/s) - + @@ -22232,26 +21331,13 @@ rate(deg/s) 16 - - - 9 - 75 - true - - Sensor Tunning - + - - - 0 - 0 - - 0 @@ -22781,13 +21867,6 @@ rate(deg/s) false - - #RateStabilizationGroup_23{background-color: qlineargradient(spread:pad, x1:0.507, y1:0.869318, x2:0.507, y2:0.0965909, stop:0 rgba(243, 243, 243, 255), stop:1 rgba(250, 250, 250, 255)); - -border: 1px outset #999; -border-radius: 3; -} - @@ -25118,23 +24197,7 @@ border-radius: 5; - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 10 - - - - - + @@ -25671,13 +24734,6 @@ border-radius: 5; false - - #RateStabilizationGroup_22{background-color: qlineargradient(spread:pad, x1:0.507, y1:0.869318, x2:0.507, y2:0.0965909, stop:0 rgba(243, 243, 243, 255), stop:1 rgba(250, 250, 250, 255)); - -border: 1px outset #999; -border-radius: 3; -} - @@ -25724,13 +24780,6 @@ border-radius: 3; 0 - - - 9 - 50 - false - - If you check this, the GCS will udpate the stabilization factors automatically every 300ms, which will help for fast tuning. @@ -25776,11 +24825,6 @@ automatically every 300ms, which will help for fast tuning. 28 - - - 8 - - Send settings to the board but do not save to the non-volatile memory @@ -25835,11 +24879,6 @@ border-radius: 4; 28 - - - 8 - - Send settings to the board and save to the non-volatile memory diff --git a/ground/openpilotgcs/src/plugins/config/txpid.ui b/ground/openpilotgcs/src/plugins/config/txpid.ui index 9862bfad1..6ffa2e62d 100644 --- a/ground/openpilotgcs/src/plugins/config/txpid.ui +++ b/ground/openpilotgcs/src/plugins/config/txpid.ui @@ -1,647 +1,620 @@ - - - TxPIDWidget - - - - 0 - 0 - 720 - 567 - - - - Form - - - - - - QFrame::NoFrame - - - true - - - - - 0 - 0 - 702 - 489 - - - - - - - Qt::StrongFocus - - - This module will periodically update values of stabilization PID settings -depending on configured input control channels. New values of stabilization -settings are not saved to flash, but updated in RAM. It is expected that the -module will be enabled only for tuning. When desired values are found, they -can be read via GCS and saved permanently. Then this module should be -disabled again. - -Up to 3 separate PID options (or option pairs) can be selected and updated. - - - Enable TxPID module - - - - - - - After enabling the module, you must power cycle before using and configuring. - - - - - - - Qt::Horizontal - - - - - - - Qt::Vertical - - - QSizePolicy::Preferred - - - - 20 - 10 - - - - - - - - - 0 - 0 - - - - - 0 - 100 - - - - #groupBox_6{ -background-color: qlineargradient(spread:pad, x1:0.507, y1:0.869318, x2:0.507, y2:0.0965909, stop:0 rgba(243, 243, 243, 255), stop:1 rgba(250, 250, 250, 255)); -border: 1px outset #999; -border-radius: 3; -font:bold; -} - -QGroupBox::title { - subcontrol-origin: margin; - subcontrol-position: top center; /* position at the top center */ - padding: 0 3px; - background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, - stop: 0 #FFOECE, stop: 1 #FFFFFF); - top: 5px; - } - - - Module Settings - - - - - - background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); -color: rgb(255, 255, 255); -border-radius: 5; -font: bold 12px; -margin:1px; - - - PID option - - - Qt::AlignCenter - - - - - - - background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); -color: rgb(255, 255, 255); -border-radius: 5; -font: bold 12px; -margin:1px; - - - Control Source - - - Qt::AlignCenter - - - - - - - background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); -color: rgb(255, 255, 255); -border-radius: 5; -font: bold 12px; -margin:1px; - - - Min - - - Qt::AlignCenter - - - - - - - background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); -color: rgb(255, 255, 255); -border-radius: 5; -font: bold 12px; -margin:1px; - - - Max - - - Qt::AlignCenter - - - - - - - Instance 1 - - - - - - - Qt::StrongFocus - - - Select PID option or option pair to update. -Set to Disabled if not used. - - - - - - - Qt::StrongFocus - - - Select input used as a control source for this instance. -It can be one of Accessory channels or Throttle channel. - -If Accessory channel is chosen then its range [0..1] will be mapped -to PID range [Min..Max] defined for this instance. - -If Throttle channel is chosen then Throttle range [Min..Max] will -be mapped to PID range [Min..Max] defined for this instance. If -Throttle is out of bounds then PID Min and Max values will be used -accordingly. - -Note that it is possible to set PID Min > Max. In that case increasing -control input value will decrease the PID option value. This can be -used, for instance, to decrease PID value when increasing Throttle. - - - - - - - Qt::StrongFocus - - - Minimum PID value mapped to Accessory channel = 0 or -Throttle channel lesser or equal to Throttle Min value. - - - 6 - - - 0.000100000000000 - - - - - - - Qt::StrongFocus - - - Maximum PID value mapped to Accessory channel = 1 or -Throttle channel greater or equal to Throttle Max value. - - - 6 - - - 0.000100000000000 - - - - - - - Instance 2 - - - - - - - Qt::StrongFocus - - - Select PID option or option pair to update. -Set to Disabled if not used. - - - - - - - Qt::StrongFocus - - - Select input used as a control source for this instance. -It can be one of Accessory channels or Throttle channel. - -If Accessory channel is chosen then its range [0..1] will be mapped -to PID range [Min..Max] defined for this instance. - -If Throttle channel is chosen then Throttle range [Min..Max] will -be mapped to PID range [Min..Max] defined for this instance. If -Throttle is out of bounds then PID Min and Max values will be used -accordingly. - -Note that it is possible to set PID Min > Max. In that case increasing -control input value will decrease the PID option value. This can be -used, for instance, to decrease PID value when increasing Throttle. - - - - - - - Qt::StrongFocus - - - Minimum PID value mapped to Accessory channel = 0 or -Throttle channel lesser or equal to Throttle Min value. - - - 6 - - - 0.000100000000000 - - - - - - - Qt::StrongFocus - - - Maximum PID value mapped to Accessory channel = 1 or -Throttle channel greater or equal to Throttle Max value. - - - 6 - - - 0.000100000000000 - - - - - - - Instance 3 - - - - - - - Qt::StrongFocus - - - Select PID option or option pair to update. -Set to Disabled if not used. - - - - - - - Qt::StrongFocus - - - Select input used as a control source for this instance. -It can be one of Accessory channels or Throttle channel. - -If Accessory channel is chosen then its range [0..1] will be mapped -to PID range [Min..Max] defined for this instance. - -If Throttle channel is chosen then Throttle range [Min..Max] will -be mapped to PID range [Min..Max] defined for this instance. If -Throttle is out of bounds then PID Min and Max values will be used -accordingly. - -Note that it is possible to set PID Min > Max. In that case increasing -control input value will decrease the PID option value. This can be -used, for instance, to decrease PID value when increasing Throttle. - - - - - - - Qt::StrongFocus - - - Minimum PID value mapped to Accessory channel = 0 or -Throttle channel lesser or equal to Throttle Min value. - - - 6 - - - 0.000100000000000 - - - - - - - Qt::StrongFocus - - - Maximum PID value mapped to Accessory channel = 1 or -Throttle channel greater or equal to Throttle Max value. - - - 6 - - - 0.000100000000000 - - - - - - - Update Mode - - - - - - - Qt::StrongFocus - - - PID values update mode which can be set to: -- Never: this disables PID updates (but module still will be run if enabled), -- When Armed: PID updated only when system is armed, -- Always: PID updated always regardless of arm state. - -Since the GCS updates GUI PID values in real time on change, could be -tricky to change other PID values from the GUI if the module is enabled -and constantly updates stabilization settings object. As a workaround, -this option can be used to temporarily disable updates or enable them -only when system is armed without disabling the module. - - - - - - - Throttle Range - - - - - - - Qt::StrongFocus - - - Throttle channel lower bound mapped to PID Min value - - - 1.000000000000000 - - - 0.010000000000000 - - - - - - - Qt::StrongFocus - - - Throttle channel upper bound mapped to PID Max value - - - 1.000000000000000 - - - 0.010000000000000 - - - - - - - background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); -color: rgb(255, 255, 255); -border-radius: 5; -font: bold 12px; -margin:1px; - - - Min - - - Qt::AlignCenter - - - - - - - background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); -color: rgb(255, 255, 255); -border-radius: 5; -font: bold 12px; -margin:1px; - - - Max - - - Qt::AlignCenter - - - - - - - Qt::Vertical - - - - 20 - 20 - - - - - - - - Qt::Vertical - - - QSizePolicy::Preferred - - - - 20 - 20 - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - - - - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Send settings to the board but do not save to the non-volatile memory - - - Apply - - - - - - - Send settings to the board and save to the non-volatile memory - - - Save - - - false - - - - - - - - - - - TxPIDEnable - Apply - Save - scrollArea - PID1 - Input1 - MinPID1 - MaxPID1 - PID2 - Input2 - MinPID2 - MaxPID2 - PID3 - Input3 - MinPID3 - MaxPID3 - ThrottleMin - ThrottleMax - UpdateMode - - - - + + + TxPIDWidget + + + + 0 + 0 + 720 + 567 + + + + Form + + + + + + QFrame::NoFrame + + + true + + + + + 0 + 0 + 696 + 475 + + + + + + + Qt::StrongFocus + + + This module will periodically update values of stabilization PID settings +depending on configured input control channels. New values of stabilization +settings are not saved to flash, but updated in RAM. It is expected that the +module will be enabled only for tuning. When desired values are found, they +can be read via GCS and saved permanently. Then this module should be +disabled again. + +Up to 3 separate PID options (or option pairs) can be selected and updated. + + + Enable TxPID module + + + + + + + After enabling the module, you must power cycle before using and configuring. + + + + + + + Qt::Horizontal + + + + + + + Qt::Vertical + + + QSizePolicy::Preferred + + + + 20 + 10 + + + + + + + + true + + + + 0 + 0 + + + + + 0 + 100 + + + + Module Settings + + + + + + background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); +color: rgb(255, 255, 255); +border-radius: 5; +font: bold 12px; +margin:1px; + + + PID option + + + Qt::AlignCenter + + + + + + + background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); +color: rgb(255, 255, 255); +border-radius: 5; +font: bold 12px; +margin:1px; + + + Control Source + + + Qt::AlignCenter + + + + + + + background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); +color: rgb(255, 255, 255); +border-radius: 5; +font: bold 12px; +margin:1px; + + + Min + + + Qt::AlignCenter + + + + + + + background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); +color: rgb(255, 255, 255); +border-radius: 5; +font: bold 12px; +margin:1px; + + + Max + + + Qt::AlignCenter + + + + + + + Instance 1 + + + + + + + Qt::StrongFocus + + + Select PID option or option pair to update. +Set to Disabled if not used. + + + + + + + Qt::StrongFocus + + + Select input used as a control source for this instance. +It can be one of Accessory channels or Throttle channel. + +If Accessory channel is chosen then its range [0..1] will be mapped +to PID range [Min..Max] defined for this instance. + +If Throttle channel is chosen then Throttle range [Min..Max] will +be mapped to PID range [Min..Max] defined for this instance. If +Throttle is out of bounds then PID Min and Max values will be used +accordingly. + +Note that it is possible to set PID Min > Max. In that case increasing +control input value will decrease the PID option value. This can be +used, for instance, to decrease PID value when increasing Throttle. + + + + + + + Qt::StrongFocus + + + Minimum PID value mapped to Accessory channel = 0 or +Throttle channel lesser or equal to Throttle Min value. + + + 6 + + + 0.000100000000000 + + + + + + + Qt::StrongFocus + + + Maximum PID value mapped to Accessory channel = 1 or +Throttle channel greater or equal to Throttle Max value. + + + 6 + + + 0.000100000000000 + + + + + + + Instance 2 + + + + + + + Qt::StrongFocus + + + Select PID option or option pair to update. +Set to Disabled if not used. + + + + + + + Qt::StrongFocus + + + Select input used as a control source for this instance. +It can be one of Accessory channels or Throttle channel. + +If Accessory channel is chosen then its range [0..1] will be mapped +to PID range [Min..Max] defined for this instance. + +If Throttle channel is chosen then Throttle range [Min..Max] will +be mapped to PID range [Min..Max] defined for this instance. If +Throttle is out of bounds then PID Min and Max values will be used +accordingly. + +Note that it is possible to set PID Min > Max. In that case increasing +control input value will decrease the PID option value. This can be +used, for instance, to decrease PID value when increasing Throttle. + + + + + + + Qt::StrongFocus + + + Minimum PID value mapped to Accessory channel = 0 or +Throttle channel lesser or equal to Throttle Min value. + + + 6 + + + 0.000100000000000 + + + + + + + Qt::StrongFocus + + + Maximum PID value mapped to Accessory channel = 1 or +Throttle channel greater or equal to Throttle Max value. + + + 6 + + + 0.000100000000000 + + + + + + + Instance 3 + + + + + + + Qt::StrongFocus + + + Select PID option or option pair to update. +Set to Disabled if not used. + + + + + + + Qt::StrongFocus + + + Select input used as a control source for this instance. +It can be one of Accessory channels or Throttle channel. + +If Accessory channel is chosen then its range [0..1] will be mapped +to PID range [Min..Max] defined for this instance. + +If Throttle channel is chosen then Throttle range [Min..Max] will +be mapped to PID range [Min..Max] defined for this instance. If +Throttle is out of bounds then PID Min and Max values will be used +accordingly. + +Note that it is possible to set PID Min > Max. In that case increasing +control input value will decrease the PID option value. This can be +used, for instance, to decrease PID value when increasing Throttle. + + + + + + + Qt::StrongFocus + + + Minimum PID value mapped to Accessory channel = 0 or +Throttle channel lesser or equal to Throttle Min value. + + + 6 + + + 0.000100000000000 + + + + + + + Qt::StrongFocus + + + Maximum PID value mapped to Accessory channel = 1 or +Throttle channel greater or equal to Throttle Max value. + + + 6 + + + 0.000100000000000 + + + + + + + Update Mode + + + + + + + Qt::StrongFocus + + + PID values update mode which can be set to: +- Never: this disables PID updates (but module still will be run if enabled), +- When Armed: PID updated only when system is armed, +- Always: PID updated always regardless of arm state. + +Since the GCS updates GUI PID values in real time on change, could be +tricky to change other PID values from the GUI if the module is enabled +and constantly updates stabilization settings object. As a workaround, +this option can be used to temporarily disable updates or enable them +only when system is armed without disabling the module. + + + + + + + Throttle Range + + + + + + + Qt::StrongFocus + + + Throttle channel lower bound mapped to PID Min value + + + 1.000000000000000 + + + 0.010000000000000 + + + + + + + Qt::StrongFocus + + + Throttle channel upper bound mapped to PID Max value + + + 1.000000000000000 + + + 0.010000000000000 + + + + + + + background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); +color: rgb(255, 255, 255); +border-radius: 5; +font: bold 12px; +margin:1px; + + + Min + + + Qt::AlignCenter + + + + + + + background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); +color: rgb(255, 255, 255); +border-radius: 5; +font: bold 12px; +margin:1px; + + + Max + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + QSizePolicy::Preferred + + + + 20 + 20 + + + + + + + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + + + + + + + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Send settings to the board but do not save to the non-volatile memory + + + Apply + + + + + + + Send settings to the board and save to the non-volatile memory + + + Save + + + false + + + + + + + + + + + TxPIDEnable + Apply + Save + scrollArea + PID1 + Input1 + MinPID1 + MaxPID1 + PID2 + Input2 + MinPID2 + MaxPID2 + PID3 + Input3 + MinPID3 + MaxPID3 + ThrottleMin + ThrottleMax + UpdateMode + + + + diff --git a/ground/openpilotgcs/src/plugins/coreplugin/modemanager.cpp b/ground/openpilotgcs/src/plugins/coreplugin/modemanager.cpp index ac3c4c224..a4479bae2 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/modemanager.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/modemanager.cpp @@ -124,6 +124,17 @@ void ModeManager::activateMode(const QString &id) m_modeStack->setCurrentIndex(index); } +void ModeManager::activateModeByWorkspaceName(const QString &id) +{ + for (int i = 0; i < m_modes.count(); ++i) { + if (m_modes.at(i)->name() == id) + { + m_modeStack->setCurrentIndex(i); + return; + } + } +} + void ModeManager::objectAdded(QObject *obj) { IMode *mode = Aggregation::query(obj); diff --git a/ground/openpilotgcs/src/plugins/coreplugin/modemanager.h b/ground/openpilotgcs/src/plugins/coreplugin/modemanager.h index 687ec0a51..ccaf50607 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/modemanager.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/modemanager.h @@ -80,6 +80,7 @@ signals: public slots: void activateMode(const QString &id); + void activateModeByWorkspaceName(const QString &id); void setFocusToCurrentMode(); private slots: diff --git a/ground/openpilotgcs/src/plugins/hitlnew/fgsimulator.cpp b/ground/openpilotgcs/src/plugins/hitlnew/fgsimulator.cpp index abfb9f75f..fec61c88d 100644 --- a/ground/openpilotgcs/src/plugins/hitlnew/fgsimulator.cpp +++ b/ground/openpilotgcs/src/plugins/hitlnew/fgsimulator.cpp @@ -308,13 +308,7 @@ void FGSimulator::processUpdate(const QByteArray& inp) double ECEF[3]; double RNE[9]; Utils::CoordinateConversions().RneFromLLA(LLA,(double (*)[3])RNE); - for (int t=0;t<9;t++) { - homeData.RNE[t]=RNE[t]; - } Utils::CoordinateConversions().LLA2ECEF(LLA,ECEF); - homeData.ECEF[0]=ECEF[0]*100; - homeData.ECEF[1]=ECEF[1]*100; - homeData.ECEF[2]=ECEF[2]*100; homeData.Be[0]=0; homeData.Be[1]=0; homeData.Be[2]=0; @@ -335,7 +329,7 @@ void FGSimulator::processUpdate(const QByteArray& inp) memset(&positionActualData, 0, sizeof(PositionActual::DataFields)); positionActualData.North = 0; //Currently hardcoded as there is no way of setting up a reference point to calculate distance positionActualData.East = 0; //Currently hardcoded as there is no way of setting up a reference point to calculate distance - positionActualData.Down = (altitude * 100); //Multiply by 100 because positionActual expects input in Centimeters. + positionActualData.Down = altitude ; //Multiply by 1 because positionActual expects input in meters. posActual->setData(positionActualData); // Update AltitudeActual object @@ -371,26 +365,39 @@ void FGSimulator::processUpdate(const QByteArray& inp) gpsPos->setData(gpsData); float NED[3]; - double LLA[3] = {(double) gpsData.Latitude / 1e7, (double) gpsData.Longitude / 1e7, (double) (gpsData.GeoidSeparation + gpsData.Altitude)}; // convert from cm back to meters - double ECEF[3] = {(double) (homeData.ECEF[0] / 100), (double) (homeData.ECEF[1] / 100), (double) (homeData.ECEF[2] / 100)}; - Utils::CoordinateConversions().LLA2Base(LLA, ECEF, (float (*)[3]) homeData.RNE, NED); - positionActualData.North = NED[0]*100; //Currently hardcoded as there is no way of setting up a reference point to calculate distance - positionActualData.East = NED[1]*100; //Currently hardcoded as there is no way of setting up a reference point to calculate distance - positionActualData.Down = NED[2]*100; //Multiply by 100 because positionActual expects input in Centimeters. + double hLLA[3] = {(double) homeData.Latitude / 1e7, (double) homeData.Longitude / 1e7, (double) (homeData.Altitude)}; + double ECEF[3]; + double RNE[9]; + Utils::CoordinateConversions().RneFromLLA(hLLA,(double (*)[3])RNE); + Utils::CoordinateConversions().LLA2ECEF(hLLA,ECEF); + Utils::CoordinateConversions().LLA2Base(hLLA, ECEF, (float (*)[3]) RNE, NED); + + positionActualData.North = NED[0]; //Currently hardcoded as there is no way of setting up a reference point to calculate distance + positionActualData.East = NED[1]; //Currently hardcoded as there is no way of setting up a reference point to calculate distance + positionActualData.Down = NED[2]; //Multiply by 1 because positionActual expects input in meters. posActual->setData(positionActualData); // Update AttitudeRaw object (filtered gyros only for now) - AttitudeRaw::DataFields rawData; - memset(&rawData, 0, sizeof(AttitudeRaw::DataFields)); - rawData = attRaw->getData(); - rawData.gyros[0] = rollRate; + //AttitudeRaw::DataFields rawData; + //AttitudeRaw::DataFields rawData; + Gyros::DataFields gyroData; + Accels::DataFields accelData; + memset(&gyroData, 0, sizeof(Gyros::DataFields)); + memset(&accelData, 0, sizeof(Accels::DataFields)); + gyroData = gyros->getData(); + accelData = accels->getData(); + //rawData.gyros[0] = rollRate; //rawData.gyros[1] = cos(DEG2RAD * roll) * pitchRate + sin(DEG2RAD * roll) * yawRate; //rawData.gyros[2] = cos(DEG2RAD * roll) * yawRate - sin(DEG2RAD * roll) * pitchRate; - rawData.gyros[1] = pitchRate; - rawData.gyros[2] = yawRate; - attRaw->setData(rawData); + //rawData.gyros[1] = pitchRate; + //rawData.gyros[2] = yawRate; + gyroData.x = rollRate; + gyroData.y = pitchRate; + gyroData.z = yawRate; + // TODO: Accels are still missing!!!! + gyros->setData(gyroData); // attRaw->updated(); } diff --git a/ground/openpilotgcs/src/plugins/hitlnew/il2simulator.cpp b/ground/openpilotgcs/src/plugins/hitlnew/il2simulator.cpp index 0d957afe4..78f78ffac 100644 --- a/ground/openpilotgcs/src/plugins/hitlnew/il2simulator.cpp +++ b/ground/openpilotgcs/src/plugins/hitlnew/il2simulator.cpp @@ -263,35 +263,45 @@ void IL2Simulator::processUpdate(const QByteArray& inp) // Update positionActual objects PositionActual::DataFields posData; memset(&posData, 0, sizeof(PositionActual::DataFields)); - posData.North = current.Y*100; - posData.East = current.X*100; - posData.Down = current.Z*-100; + posData.North = current.Y; + posData.East = current.X; + posData.Down = current.Z*-1.; // Update velocityActual objects VelocityActual::DataFields velData; memset(&velData, 0, sizeof(VelocityActual::DataFields)); - velData.North = current.dY*100; - velData.East = current.dX*100; - velData.Down = current.dZ*-100; + velData.North = current.dY; + velData.East = current.dX; + velData.Down = current.dZ*-1.; // Update AttitudeRaw object (filtered gyros and accels only for now) - AttitudeRaw::DataFields rawData; - memset(&rawData, 0, sizeof(AttitudeRaw::DataFields)); - rawData = attRaw->getData(); + //AttitudeRaw::DataFields rawData; + //memset(&rawData, 0, sizeof(AttitudeRaw::DataFields)); + //rawData = attRaw->getData(); + Gyros::DataFields gyroData; + Accels::DataFields accelData; + memset(&gyroData, 0, sizeof(Gyros::DataFields)); + memset(&accelData, 0, sizeof(Accels::DataFields)); + gyroData = gyros->getData(); + accelData = accels->getData(); + // rotate turn rates and accelerations into body frame // (note: rotation deltas are NOT in NED frame but in RPY - manual conversion!) - rawData.gyros[0] = current.dRoll; - rawData.gyros[1] = cos(DEG2RAD * current.roll) * current.dPitch + sin(DEG2RAD * current.roll) * current.dAzimuth; - rawData.gyros[2] = cos(DEG2RAD * current.roll) * current.dAzimuth - sin(DEG2RAD * current.roll) * current.dPitch; + gyroData.x = current.dRoll; + gyroData.y = cos(DEG2RAD * current.roll) * current.dPitch + sin(DEG2RAD * current.roll) * current.dAzimuth; + gyroData.z = cos(DEG2RAD * current.roll) * current.dAzimuth - sin(DEG2RAD * current.roll) * current.dPitch; // accels are in NED and can be converted using standard ned->local rotation matrix float Rbe[3][3]; Utils::CoordinateConversions().Quaternion2R(quat,Rbe); - for (int t=0;t<3;t++) { - rawData.accels[t]=current.ddX*Rbe[t][0] - +current.ddY*Rbe[t][1] - +(current.ddZ+GEE)*Rbe[t][2]; - } - rawData.accels[2]=-rawData.accels[2]; + accelData.x = current.ddX*Rbe[0][0] + +current.ddY*Rbe[0][1] + +(current.ddZ+GEE)*Rbe[0][2]; + accelData.y = current.ddX*Rbe[1][0] + +current.ddY*Rbe[1][1] + +(current.ddZ+GEE)*Rbe[1][2]; + accelData.z = - (current.ddX*Rbe[2][0] + +current.ddY*Rbe[2][1] + +(current.ddZ+GEE)*Rbe[2][2]); // Update homelocation HomeLocation::DataFields homeData; @@ -307,13 +317,7 @@ void IL2Simulator::processUpdate(const QByteArray& inp) double ECEF[3]; double RNE[9]; Utils::CoordinateConversions().RneFromLLA(LLA,(double (*)[3])RNE); - for (int t=0;t<9;t++) { - homeData.RNE[t]=RNE[t]; - } Utils::CoordinateConversions().LLA2ECEF(LLA,ECEF); - homeData.ECEF[0]=ECEF[0]*100; - homeData.ECEF[1]=ECEF[1]*100; - homeData.ECEF[2]=ECEF[2]*100; homeData.Be[0]=0; homeData.Be[1]=0; homeData.Be[2]=0; @@ -339,7 +343,9 @@ void IL2Simulator::processUpdate(const QByteArray& inp) // update every time (50ms) attActual->setData(attActualData); //attActual->updated(); - attRaw->setData(rawData); + //attRaw->setData(rawData); + gyros->setData(gyroData); + accels->setData(accelData); //attRaw->updated(); velActual->setData(velData); //velActual->updated(); diff --git a/ground/openpilotgcs/src/plugins/hitlnew/simulator.cpp b/ground/openpilotgcs/src/plugins/hitlnew/simulator.cpp index e701f0485..2cb7f9ae8 100644 --- a/ground/openpilotgcs/src/plugins/hitlnew/simulator.cpp +++ b/ground/openpilotgcs/src/plugins/hitlnew/simulator.cpp @@ -49,7 +49,7 @@ Simulator::Simulator(const SimulatorSettings& params) : outSocket(NULL), settings(params), updatePeriod(50), - simTimeout(2000), + simTimeout(8000), autopilotConnectionStatus(false), simConnectionStatus(false), txTimer(NULL), @@ -131,7 +131,8 @@ void Simulator::onStart() posActual = PositionActual::GetInstance(objManager); altActual = BaroAltitude::GetInstance(objManager); attActual = AttitudeActual::GetInstance(objManager); - attRaw = AttitudeRaw::GetInstance(objManager); + accels = Accels::GetInstance(objManager); + gyros = Gyros::GetInstance(objManager); gpsPos = GPSPosition::GetInstance(objManager); telStats = GCSTelemetryStats::GetInstance(objManager); @@ -225,7 +226,8 @@ void Simulator::setupObjects() setupOutputObject(posActual, 250); setupOutputObject(velActual, 250); setupOutputObject(posHome, 1000); - setupOutputObject(attRaw, 10); + setupOutputObject(accels, 10); + setupOutputObject(gyros, 10); //setupOutputObject(attRaw, 100); diff --git a/ground/openpilotgcs/src/plugins/hitlnew/simulator.h b/ground/openpilotgcs/src/plugins/hitlnew/simulator.h index 3f5f65355..b345f0a5e 100644 --- a/ground/openpilotgcs/src/plugins/hitlnew/simulator.h +++ b/ground/openpilotgcs/src/plugins/hitlnew/simulator.h @@ -44,7 +44,8 @@ #include "attitudeactual.h" #include "gpsposition.h" #include "homelocation.h" -#include "attituderaw.h" +#include "accels.h" +#include "gyros.h" #include "gcstelemetrystats.h" #include "flightstatus.h" @@ -177,7 +178,8 @@ protected: VelocityActual* velActual; PositionActual* posActual; HomeLocation* posHome; - AttitudeRaw* attRaw; + Accels* accels; + Gyros* gyros; GPSPosition* gpsPos; GCSTelemetryStats* telStats; diff --git a/ground/openpilotgcs/src/plugins/hitlnew/xplanesimulator.cpp b/ground/openpilotgcs/src/plugins/hitlnew/xplanesimulator.cpp index ab8e485f4..66dbfd1d6 100644 --- a/ground/openpilotgcs/src/plugins/hitlnew/xplanesimulator.cpp +++ b/ground/openpilotgcs/src/plugins/hitlnew/xplanesimulator.cpp @@ -306,13 +306,7 @@ void XplaneSimulator::processUpdate(const QByteArray& dataBuf) double ECEF[3]; double RNE[9]; Utils::CoordinateConversions().RneFromLLA(LLA,(double (*)[3])RNE); - for (int t=0;t<9;t++) { - homeData.RNE[t]=RNE[t]; - } Utils::CoordinateConversions().LLA2ECEF(LLA,ECEF); - homeData.ECEF[0]=ECEF[0]*100; - homeData.ECEF[1]=ECEF[1]*100; - homeData.ECEF[2]=ECEF[2]*100; homeData.Be[0]=0; homeData.Be[1]=0; homeData.Be[2]=0; @@ -368,33 +362,45 @@ void XplaneSimulator::processUpdate(const QByteArray& dataBuf) // Update VelocityActual.{Nort,East,Down} VelocityActual::DataFields velocityActualData; memset(&velocityActualData, 0, sizeof(VelocityActual::DataFields)); - velocityActualData.North = velY*100; - velocityActualData.East = velX*100; - velocityActualData.Down = -velZ*100; + velocityActualData.North = velY; + velocityActualData.East = velX; + velocityActualData.Down = -velZ; velActual->setData(velocityActualData); // Update PositionActual.{Nort,East,Down} PositionActual::DataFields positionActualData; memset(&positionActualData, 0, sizeof(PositionActual::DataFields)); - positionActualData.North = (dstY-initY)*100; - positionActualData.East = (dstX-initX)*100; - positionActualData.Down = -(dstZ-initZ)*100; + positionActualData.North = (dstY-initY); + positionActualData.East = (dstX-initX); + positionActualData.Down = -(dstZ-initZ); posActual->setData(positionActualData); // Update AttitudeRaw object (filtered gyros only for now) - AttitudeRaw::DataFields rawData; - memset(&rawData, 0, sizeof(AttitudeRaw::DataFields)); - rawData = attRaw->getData(); - rawData.gyros[0] = rollRate; + //AttitudeRaw::DataFields rawData; + //memset(&rawData, 0, sizeof(AttitudeRaw::DataFields)); + //rawData = attRaw->getData(); + //rawData.gyros[0] = rollRate; //rawData.gyros_filtered[1] = cos(DEG2RAD * roll) * pitchRate + sin(DEG2RAD * roll) * yawRate; //rawData.gyros_filtered[2] = cos(DEG2RAD * roll) * yawRate - sin(DEG2RAD * roll) * pitchRate; - rawData.gyros[1] = pitchRate; - rawData.gyros[2] = yawRate; - rawData.accels[0] = accX; - rawData.accels[1] = accY; - rawData.accels[2] = -accZ; - attRaw->setData(rawData); + //rawData.gyros[1] = pitchRate; + //rawData.gyros[2] = yawRate; + //rawData.accels[0] = accX; + //rawData.accels[1] = accY; + //rawData.accels[2] = -accZ; + //attRaw->setData(rawData); + Gyros::DataFields gyroData; + memset(&gyroData, 0, sizeof(Gyros::DataFields)); + gyroData.x = rollRate; + gyroData.y = pitchRate; + gyroData.z = yawRate; + gyros->setData(gyroData); + Accels::DataFields accelData; + memset(&accelData, 0, sizeof(Accels::DataFields)); + accelData.x = accX; + accelData.y = accY; + accelData.z = -accZ; + accels->setData(accelData); } // issue manual update diff --git a/ground/openpilotgcs/src/plugins/hitlv2/aerosimrc.cpp b/ground/openpilotgcs/src/plugins/hitlv2/aerosimrc.cpp new file mode 100644 index 000000000..51daf2460 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/hitlv2/aerosimrc.cpp @@ -0,0 +1,468 @@ +#include "aerosimrc.h" +#include +#include +#include + +AeroSimRCSimulator::AeroSimRCSimulator(const SimulatorSettings ¶ms) + : Simulator(params) +{ + udpCounterASrecv = 0; +} + +AeroSimRCSimulator::~AeroSimRCSimulator() +{ +} + +bool AeroSimRCSimulator::setupProcess() +{ + QMutexLocker locker(&lock); + return true; +} + +void AeroSimRCSimulator::setupUdpPorts(const QString &host, int inPort, int outPort) +{ + Q_UNUSED(outPort) + if (inSocket->bind(QHostAddress(host), inPort)) + emit processOutput("Successfully bound to address " + host + ", port " + QString::number(inPort) + "\n"); + else + emit processOutput("Cannot bind to address " + host + ", port " + QString::number(inPort) + "\n"); +} + +void AeroSimRCSimulator::transmitUpdate() +{ + // read actuator output + ActuatorCommand::DataFields actCmdData; + actCmdData = actCommand->getData(); + float channels[10]; + for (int i = 0; i < 10; ++i) { + qint16 ch = actCmdData.Channel[i]; + float out = -1.0; + if (ch >= 1000 && ch <= 2000) { + ch -= 1000; + out = ((float)ch / 500.0) - 1.0; + } + channels[i] = out; + } + + // read flight status + FlightStatus::DataFields flightData; + flightData = flightStatus->getData(); + quint8 armed; + quint8 mode; + armed = flightData.Armed; + mode = flightData.FlightMode; + + QByteArray data; + // 50 - current size of values, 4(quint32) + 10*4(float) + 2(quint8) + 4(quint32) + data.resize(50); + QDataStream stream(&data, QIODevice::WriteOnly); + stream.setFloatingPointPrecision(QDataStream::SinglePrecision); + stream << quint32(0x52434D44); // magic header, "RCMD" + for (int i = 0; i < 10; ++i) + stream << channels[i]; // channels + stream << armed << mode; // flight status + stream << udpCounterASrecv; // packet counter + + if (outSocket->writeDatagram(data, QHostAddress(settings.remoteAddress), settings.outPort) == -1) { + qDebug() << "write failed: " << outSocket->errorString(); + } + +#ifdef DBG_TIMERS + static int cntTX = 0; + if (cntTX >= 100) { + qDebug() << "TX=" << 1000.0 * 100 / timeTX.restart(); + cntTX = 0; + } else { + ++cntTX; + } +#endif +} + +void AeroSimRCSimulator::processUpdate(const QByteArray &data) +{ + // check size + if (data.size() > 188) { + qDebug() << "!!! big datagram: " << data.size(); + return; + } + + QByteArray buf = data; + QDataStream stream(&buf, QIODevice::ReadOnly); + stream.setFloatingPointPrecision(QDataStream::SinglePrecision); + + // check magic header + quint32 magic; + stream >> magic; + if (magic != 0x4153494D) { // "AERO" + qDebug() << "wrong magic: " << magic << ", correct: " << quint32(0x4153494D); + return; + } + + float timeStep, + homeX, homeY, homeZ, + WpHX, WpHY, WpLat, WpLon, + posX, posY, posZ, // world + velX, velY, velZ, // world + angX, angY, angZ, // model + accX, accY, accZ, // model + lat, lon, agl, // world + yaw, pitch, roll, // model + volt, curr, + rx, ry, rz, fx, fy, fz, ux, uy, uz, // matrix + ch[8]; + + stream >> timeStep; + stream >> homeX >> homeY >> homeZ; + stream >> WpHX >> WpHY >> WpLat >> WpLon; + stream >> posX >> posY >> posZ; + stream >> velX >> velY >> velZ; + stream >> angX >> angY >> angZ; + stream >> accX >> accY >> accZ; + stream >> lat >> lon >> agl; + stream >> yaw >> pitch >> roll; + stream >> volt >> curr; + stream >> rx >> ry >> rz >> fx >> fy >> fz >> ux >> uy >> uz; + stream >> ch[0] >> ch[1] >> ch[2] >> ch[3] >> ch[4] >> ch[5] >> ch[6] >> ch[7]; + stream >> udpCounterASrecv; + + /**********************************************************************************************/ + QTime currentTime = QTime::currentTime(); + /**********************************************************************************************/ + static bool firstRun = true; + if (settings.homeLocation) { + if (firstRun) { + HomeLocation::DataFields homeData; + homeData = posHome->getData(); + + homeData.Latitude = WpLat * 10e6; + homeData.Longitude = WpLon * 10e6; + homeData.Altitude = homeZ; + homeData.Set = HomeLocation::SET_TRUE; + + posHome->setData(homeData); + + firstRun = false; + } + if (settings.homeLocRate > 0) { + static QTime homeLocTime = currentTime; + if (homeLocTime.secsTo(currentTime) >= settings.homeLocRate) { + firstRun = true; + homeLocTime = currentTime; + } + } + } + /**********************************************************************************************/ + if (settings.attRaw || settings.attActual) { + QMatrix4x4 mat; + mat = QMatrix4x4( fy, fx, -fz, 0.0, // model matrix + ry, rx, -rz, 0.0, // (X,Y,Z) -> (+Y,+X,-Z) + -uy, -ux, uz, 0.0, + 0.0, 0.0, 0.0, 1.0); + mat.optimize(); + + QQuaternion quat; // model quat + asMatrix2Quat(mat, quat); + + // rotate gravity + QVector3D acc = QVector3D(accY, accX, -accZ); // accel (X,Y,Z) -> (+Y,+X,-Z) + QVector3D gee = QVector3D(0.0, 0.0, -GEE); + QQuaternion qWorld = quat.conjugate(); + gee = qWorld.rotatedVector(gee); + acc += gee; + + /*************************************************************************************/ + if (settings.attRaw) { + Accels::DataFields accelsData; + accelsData = accels->getData(); + Gyros::DataFields gyrosData; + gyrosData = gyros->getData(); + + gyrosData.x = angY * RAD2DEG; // gyros (X,Y,Z) -> (+Y,+X,-Z) + gyrosData.y = angX * RAD2DEG; + gyrosData.z = angZ * -RAD2DEG; + accelsData.x = acc.x(); + accelsData.y = acc.y(); + accelsData.z = acc.z(); + + accels->setData(accelsData); + gyros->setData(gyrosData); + } + /*************************************************************************************/ + if (settings.attActHW) { + // do nothing + /*****************************************/ + } else if (settings.attActSim) { + // take all data from simulator + AttitudeActual::DataFields attActData; + attActData = attActual->getData(); + + QVector3D rpy; // model roll, pitch, yaw + asMatrix2RPY(mat, rpy); + + attActData.Roll = rpy.x(); + attActData.Pitch = rpy.y(); + attActData.Yaw = rpy.z(); + attActData.q1 = quat.scalar(); + attActData.q2 = quat.x(); + attActData.q3 = quat.y(); + attActData.q4 = quat.z(); + + attActual->setData(attActData); + /*****************************************/ + } else if (settings.attActCalc) { + // calculate RPY with code from Attitude module + AttitudeActual::DataFields attActData; + attActData = attActual->getData(); + + static float q[4] = {1, 0, 0, 0}; + static float gyro_correct_int2 = 0; + + float dT = timeStep; + + AttitudeSettings::DataFields attSettData = attSettings->getData(); + float accelKp = attSettData.AccelKp * 0.1666666666666667; + float accelKi = attSettData.AccelKp * 0.1666666666666667; + float yawBiasRate = attSettData.YawBiasRate; + + // calibrate sensors on arming + if (flightStatus->getData().Armed == FlightStatus::ARMED_ARMING) { + accelKp = 2.0; + accelKi = 0.9; + } + + float gyro[3] = {angY * RAD2DEG, angX * RAD2DEG, angZ * -RAD2DEG}; + float attRawAcc[3] = {acc.x(), acc.y(), acc.z()}; + + // code from Attitude module begin /////////////////////////////// + float *accels = attRawAcc; + float grot[3]; + float accel_err[3]; + + // Rotate gravity to body frame and cross with accels + grot[0] = -(2 * (q[1] * q[3] - q[0] * q[2])); + grot[1] = -(2 * (q[2] * q[3] + q[0] * q[1])); + grot[2] = -(q[0] * q[0] - q[1]*q[1] - q[2]*q[2] + q[3]*q[3]); + + // CrossProduct + { + accel_err[0] = accels[1]*grot[2] - grot[1]*accels[2]; + accel_err[1] = grot[0]*accels[2] - accels[0]*grot[2]; + accel_err[2] = accels[0]*grot[1] - grot[0]*accels[1]; + } + + // Account for accel magnitude + float accel_mag = sqrt(accels[0] * accels[0] + accels[1] * accels[1] + accels[2] * accels[2]); + accel_err[0] /= accel_mag; + accel_err[1] /= accel_mag; + accel_err[2] /= accel_mag; + + // Accumulate integral of error. Scale here so that units are (deg/s) but Ki has units of s + gyro_correct_int2 += -gyro[2] * yawBiasRate; + + // Correct rates based on error, integral component dealt with in updateSensors + gyro[0] += accel_err[0] * accelKp / dT; + gyro[1] += accel_err[1] * accelKp / dT; + gyro[2] += accel_err[2] * accelKp / dT + gyro_correct_int2; + + // Work out time derivative from INSAlgo writeup + // Also accounts for the fact that gyros are in deg/s + float qdot[4]; + qdot[0] = (-q[1] * gyro[0] - q[2] * gyro[1] - q[3] * gyro[2]) * dT * M_PI / 180 / 2; + qdot[1] = (+q[0] * gyro[0] - q[3] * gyro[1] + q[2] * gyro[2]) * dT * M_PI / 180 / 2; + qdot[2] = (+q[3] * gyro[0] + q[0] * gyro[1] - q[1] * gyro[2]) * dT * M_PI / 180 / 2; + qdot[3] = (-q[2] * gyro[0] + q[1] * gyro[1] + q[0] * gyro[2]) * dT * M_PI / 180 / 2; + + // Take a time step + q[0] += qdot[0]; + q[1] += qdot[1]; + q[2] += qdot[2]; + q[3] += qdot[3]; + + if(q[0] < 0) { + q[0] = -q[0]; + q[1] = -q[1]; + q[2] = -q[2]; + q[3] = -q[3]; + } + + // Renomalize + float qmag = sqrt((q[0] * q[0]) + (q[1] * q[1]) + (q[2] * q[2]) + (q[3] * q[3])); + q[0] /= qmag; + q[1] /= qmag; + q[2] /= qmag; + q[3] /= qmag; + + // If quaternion has become inappropriately short or is nan reinit. + // THIS SHOULD NEVER ACTUALLY HAPPEN + if((fabs(qmag) < 1e-3) || (qmag != qmag)) { + q[0] = 1; + q[1] = 0; + q[2] = 0; + q[3] = 0; + } + + float rpy2[3]; + // Quaternion2RPY + { + float q0s, q1s, q2s, q3s; + q0s = q[0] * q[0]; + q1s = q[1] * q[1]; + q2s = q[2] * q[2]; + q3s = q[3] * q[3]; + + float R13, R11, R12, R23, R33; + R13 = 2 * (q[1] * q[3] - q[0] * q[2]); + R11 = q0s + q1s - q2s - q3s; + R12 = 2 * (q[1] * q[2] + q[0] * q[3]); + R23 = 2 * (q[2] * q[3] + q[0] * q[1]); + R33 = q0s - q1s - q2s + q3s; + + rpy2[1] = RAD2DEG * asinf(-R13); // pitch always between -pi/2 to pi/2 + rpy2[2] = RAD2DEG * atan2f(R12, R11); + rpy2[0] = RAD2DEG * atan2f(R23, R33); + } + + attActData.Roll = rpy2[0]; + attActData.Pitch = rpy2[1]; + attActData.Yaw = rpy2[2]; + attActData.q1 = q[0]; + attActData.q2 = q[1]; + attActData.q3 = q[2]; + attActData.q4 = q[3]; + attActual->setData(attActData); + /*****************************************/ + } + } + /**********************************************************************************************/ + if (settings.gcsReciever) { + static QTime gcsRcvrTime = currentTime; + if (!settings.manualOutput || gcsRcvrTime.msecsTo(currentTime) >= settings.outputRate) { + GCSReceiver::DataFields gcsRcvrData; + gcsRcvrData = gcsReceiver->getData(); + + for (int i = 0; i < 8; ++i) + gcsRcvrData.Channel[i] = 1500 + (ch[i] * 500); + + gcsReceiver->setData(gcsRcvrData); + if (settings.manualOutput) + gcsRcvrTime = currentTime; + } + } else if (settings.manualControl) { + // not implemented yet + } + /**********************************************************************************************/ + if (settings.gpsPosition) { + static QTime gpsPosTime = currentTime; + if (gpsPosTime.msecsTo(currentTime) >= settings.gpsPosRate) { + GPSPosition::DataFields gpsPosData; + gpsPosData = gpsPosition->getData(); + + gpsPosData.Altitude = posZ; + gpsPosData.Heading = yaw * RAD2DEG; + gpsPosData.Latitude = lat * 10e6; + gpsPosData.Longitude = lon * 10e6; + gpsPosData.Groundspeed = qSqrt(velX * velX + velY * velY); + gpsPosData.GeoidSeparation = 0.0; + gpsPosData.Satellites = 8; + gpsPosData.PDOP = 3.0; + gpsPosData.Status = GPSPosition::STATUS_FIX3D; + + gpsPosition->setData(gpsPosData); + gpsPosTime = currentTime; + } + } + /**********************************************************************************************/ + if (settings.sonarAltitude) { + static QTime sonarAltTime = currentTime; + if (sonarAltTime.msecsTo(currentTime) >= settings.sonarAltRate) { + SonarAltitude::DataFields sonarAltData; + sonarAltData = sonarAlt->getData(); + + float sAlt = settings.sonarMaxAlt; + // 0.35 rad ~= 20 degree + if ((agl < (sAlt * 2.0)) && (roll < 0.35) && (pitch < 0.35)) { + float x = agl * qTan(roll); + float y = agl * qTan(pitch); + float h = qSqrt(x*x + y*y + agl*agl); + sAlt = qMin(h, sAlt); + } + + sonarAltData.Altitude = sAlt; + sonarAlt->setData(sonarAltData); + sonarAltTime = currentTime; + } + } + /**********************************************************************************************/ +/* + BaroAltitude::DataFields altActData; + altActData = altActual->getData(); + altActData.Altitude = posZ; + altActual->setData(altActData); + + PositionActual::DataFields posActData; + posActData = posActual->getData(); + posActData.North = posY * 100; + posActData.East = posX * 100; + posActData.Down = posZ * -100; + posActual->setData(posActData); + + VelocityActual::DataFields velActData; + velActData = velActual->getData(); + velActData.North = velY * 100; + velActData.East = velX * 100; + velActData.Down = velZ * 100; + velActual->setData(velActData); +*/ + +#ifdef DBG_TIMERS + static int cntRX = 0; + if (cntRX >= 100) { + qDebug() << "RX=" << 1000.0 * 100 / timeRX.restart(); + cntRX = 0; + } else { + ++cntRX; + } +#endif +} + +// transfomations + +void AeroSimRCSimulator::asMatrix2Quat(const QMatrix4x4 &m, QQuaternion &q) +{ + qreal w, x, y, z; + + // w always >= 0 + w = qSqrt(qMax(0.0, 1.0 + m(0, 0) + m(1, 1) + m(2, 2))) / 2.0; + x = qSqrt(qMax(0.0, 1.0 + m(0, 0) - m(1, 1) - m(2, 2))) / 2.0; + y = qSqrt(qMax(0.0, 1.0 - m(0, 0) + m(1, 1) - m(2, 2))) / 2.0; + z = qSqrt(qMax(0.0, 1.0 - m(0, 0) - m(1, 1) + m(2, 2))) / 2.0; + + x = copysign(x, (m(1, 2) - m(2, 1))); + y = copysign(y, (m(2, 0) - m(0, 2))); + z = copysign(z, (m(0, 1) - m(1, 0))); + + q.setScalar(w); + q.setX(x); + q.setY(y); + q.setZ(z); +} + +void AeroSimRCSimulator::asMatrix2RPY(const QMatrix4x4 &m, QVector3D &rpy) +{ + qreal roll, pitch, yaw; + + if (qFabs(m(0, 2)) > 0.998) { + // ~86.3°, gimbal lock + roll = 0.0; + pitch = copysign(M_PI_2, -m(0, 2)); + yaw = qAtan2(-m(1, 0), m(1, 1)); + } else { + roll = qAtan2(m(1, 2), m(2, 2)); + pitch = qAsin(-m(0, 2)); + yaw = qAtan2(m(0, 1), m(0, 0)); + } + + rpy.setX(roll * RAD2DEG); + rpy.setY(pitch * RAD2DEG); + rpy.setZ(yaw * RAD2DEG); +} diff --git a/ground/openpilotgcs/src/plugins/hitlv2/aerosimrc.h b/ground/openpilotgcs/src/plugins/hitlv2/aerosimrc.h new file mode 100644 index 000000000..19dae3bce --- /dev/null +++ b/ground/openpilotgcs/src/plugins/hitlv2/aerosimrc.h @@ -0,0 +1,46 @@ +#ifndef AEROSIMRC_H +#define AEROSIMRC_H + +#include +#include +#include +#include +#include "simulatorv2.h" + +class AeroSimRCSimulator: public Simulator +{ + Q_OBJECT + +public: + AeroSimRCSimulator(const SimulatorSettings ¶ms); + ~AeroSimRCSimulator(); + + bool setupProcess(); + void setupUdpPorts(const QString& host, int inPort, int outPort); + +private slots: + void transmitUpdate(); + +private: + quint32 udpCounterASrecv; //keeps track of udp packets received by ASim + + void processUpdate(const QByteArray &data); + + void asMatrix2Quat(const QMatrix4x4 &m, QQuaternion &q); + void asMatrix2RPY(const QMatrix4x4 &m, QVector3D &rpy); +}; + +class AeroSimRCSimulatorCreator : public SimulatorCreator +{ +public: + AeroSimRCSimulatorCreator(const QString &classId, const QString &description) + : SimulatorCreator (classId, description) + {} + + Simulator* createSimulator(const SimulatorSettings ¶ms) + { + return new AeroSimRCSimulator(params); + } +}; + +#endif // AEROSIMRC_H diff --git a/ground/openpilotgcs/src/plugins/hitlv2/hitlv2.pluginspec b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2.pluginspec new file mode 100644 index 000000000..26fede385 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2.pluginspec @@ -0,0 +1,12 @@ + + The OpenPilot Project + (C) 2011 OpenPilot Project + The GNU Public License (GPL) Version 3 + Hardware In The Loop Simulation (v2) + http://www.openpilot.org + + + + + + diff --git a/ground/openpilotgcs/src/plugins/hitlv2/hitlv2.pro b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2.pro new file mode 100644 index 000000000..f567fc401 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2.pro @@ -0,0 +1,27 @@ +TEMPLATE = lib +TARGET = HITLV2 +QT += network +include(../../openpilotgcsplugin.pri) +include(hitlv2_dependencies.pri) +HEADERS += \ + aerosimrc.h \ + hitlv2configuration.h \ + hitlv2factory.h \ + hitlv2gadget.h \ + hitlv2optionspage.h \ + hitlv2plugin.h \ + hitlv2widget.h \ + simulatorv2.h +SOURCES += \ + aerosimrc.cpp \ + hitlv2configuration.cpp \ + hitlv2factory.cpp \ + hitlv2gadget.cpp \ + hitlv2optionspage.cpp \ + hitlv2plugin.cpp \ + hitlv2widget.cpp \ + simulatorv2.cpp +OTHER_FILES += hitlv2.pluginspec +FORMS += \ + hitlv2optionspage.ui \ + hitlv2widget.ui diff --git a/ground/openpilotgcs/src/plugins/hitlv2/hitlv2_dependencies.pri b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2_dependencies.pri new file mode 100644 index 000000000..50268face --- /dev/null +++ b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2_dependencies.pri @@ -0,0 +1,4 @@ +include(../../plugins/uavobjects/uavobjects.pri) +include(../../plugins/uavtalk/uavtalk.pri) +#include(../../plugins/coreplugin/coreplugin.pri) +#include(../../libs/utils/utils.pri) diff --git a/ground/openpilotgcs/src/plugins/hitlv2/hitlv2configuration.cpp b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2configuration.cpp new file mode 100644 index 000000000..0c4b42d39 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2configuration.cpp @@ -0,0 +1,178 @@ +/** + ****************************************************************************** + * + * @file hitlconfiguration.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup HITLPlugin HITL Plugin + * @{ + * @brief The Hardware In The Loop plugin + *****************************************************************************/ +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "hitlv2configuration.h" + +HITLConfiguration::HITLConfiguration(QString classId, + QSettings* qSettings, + QObject *parent) + : IUAVGadgetConfiguration(classId, parent) +{ +// qDebug() << "HITLV2Configuration"; + // default values + QString simulatorId = ""; + QString hostAddress = "127.0.0.1"; + int inPort = 40100; + QString remoteAddress = "127.0.0.1"; + int outPort = 40200; + QString binPath = ""; + QString dataPath = ""; + + bool homeLocation = true; + quint16 homeLocRate = 0; + + bool attRaw = true; + quint8 attRawRate = 20; + + bool attActual = true; + bool attActHW = false; + bool attActSim = true; + bool attActCalc = false; + + bool sonarAltitude = false; + float sonarMaxAlt = 5.0; + quint16 sonarAltRate = 50; + + bool gpsPosition = true; + quint16 gpsPosRate = 200; + + bool inputCommand = true; + bool gcsReciever = true; + bool manualControl = false; + + bool manualOutput = false; + quint8 outputRate = 20; + + // if a saved configuration exists load it + if (qSettings != 0) { + settings.simulatorId = qSettings->value("simulatorId", simulatorId).toString(); + settings.hostAddress = qSettings->value("hostAddress", hostAddress).toString(); + settings.inPort = qSettings->value("inPort", inPort).toInt(); + settings.remoteAddress = qSettings->value("remoteAddress", remoteAddress).toString(); + settings.outPort = qSettings->value("outPort", outPort).toInt(); + settings.binPath = qSettings->value("binPath", binPath).toString(); + settings.dataPath = qSettings->value("dataPath", dataPath).toString(); + + settings.homeLocation = qSettings->value("homeLocation", homeLocation).toBool(); + settings.homeLocRate = qSettings->value("homeLocRate", homeLocRate).toInt(); + + settings.attRaw = qSettings->value("attRaw", attRaw).toBool(); + settings.attRawRate = qSettings->value("attRawRate", attRawRate).toInt(); + + settings.attActual = qSettings->value("attActual", attActual).toBool(); + settings.attActHW = qSettings->value("attActHW", attActHW).toBool(); + settings.attActSim = qSettings->value("attActSim", attActSim).toBool(); + settings.attActCalc = qSettings->value("attActCalc", attActCalc).toBool(); + + settings.sonarAltitude = qSettings->value("sonarAltitude", sonarAltitude).toBool(); + settings.sonarMaxAlt = qSettings->value("sonarMaxAlt", sonarMaxAlt).toFloat(); + settings.sonarAltRate = qSettings->value("sonarAltRate", sonarAltRate).toInt(); + + settings.gpsPosition = qSettings->value("gpsPosition", gpsPosition).toBool(); + settings.gpsPosRate = qSettings->value("gpsPosRate", gpsPosRate).toInt(); + + settings.inputCommand = qSettings->value("inputCommand", inputCommand).toBool(); + settings.gcsReciever = qSettings->value("gcsReciever", gcsReciever).toBool(); + settings.manualControl = qSettings->value("manualControl", manualControl).toBool(); + settings.manualOutput = qSettings->value("manualOutput", manualOutput).toBool(); + settings.outputRate = qSettings->value("outputRate", outputRate).toInt(); + } else { + settings.simulatorId = simulatorId; + settings.hostAddress = hostAddress; + settings.inPort = inPort; + settings.remoteAddress = remoteAddress; + settings.outPort = outPort; + settings.binPath = binPath; + settings.dataPath = dataPath; + + settings.homeLocation = homeLocation; + settings.homeLocRate = homeLocRate; + + settings.attRaw = attRaw; + settings.attRawRate = attRawRate; + + settings.attActual = attActual; + settings.attActHW = attActHW; + settings.attActSim = attActSim; + settings.attActCalc = attActCalc; + + settings.sonarAltitude = sonarAltitude; + settings.sonarMaxAlt = sonarMaxAlt; + settings.sonarAltRate = sonarAltRate; + + settings.gpsPosition = gpsPosition; + settings.gpsPosRate = gpsPosRate; + + settings.inputCommand = inputCommand; + settings.gcsReciever = gcsReciever; + settings.manualControl = manualControl; + settings.manualOutput = manualOutput; + settings.outputRate = outputRate; + } +} + +IUAVGadgetConfiguration *HITLConfiguration::clone() +{ + HITLConfiguration *m = new HITLConfiguration(this->classId()); + m->settings = settings; + return m; +} + +void HITLConfiguration::saveConfig(QSettings* qSettings) const +{ + qSettings->setValue("simulatorId", settings.simulatorId); + qSettings->setValue("hostAddress", settings.hostAddress); + qSettings->setValue("inPort", settings.inPort); + qSettings->setValue("remoteAddress", settings.remoteAddress); + qSettings->setValue("outPort", settings.outPort); + qSettings->setValue("binPath", settings.binPath); + qSettings->setValue("dataPath", settings.dataPath); + + qSettings->setValue("homeLocation", settings.homeLocation); + qSettings->setValue("homeLocRate", settings.homeLocRate); + + qSettings->setValue("attRaw", settings.attRaw); + qSettings->setValue("attRawRate", settings.attRawRate); + + qSettings->setValue("attActual", settings.attActual); + qSettings->setValue("attActHW", settings.attActHW); + qSettings->setValue("attActSim", settings.attActSim); + qSettings->setValue("attActCalc", settings.attActCalc); + + qSettings->setValue("sonarAltitude", settings.sonarAltitude); + qSettings->setValue("sonarMaxAlt", settings.sonarMaxAlt); + qSettings->setValue("sonarAltRate", settings.sonarAltRate); + + qSettings->setValue("gpsPosition", settings.gpsPosition); + qSettings->setValue("gpsPosRate", settings.gpsPosRate); + + qSettings->setValue("inputCommand", settings.inputCommand); + qSettings->setValue("gcsReciever", settings.gcsReciever); + qSettings->setValue("manualControl", settings.manualControl); + qSettings->setValue("manualOutput", settings.manualOutput); + qSettings->setValue("outputRate", settings.outputRate); +} diff --git a/ground/openpilotgcs/src/plugins/hitlv2/hitlv2configuration.h b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2configuration.h new file mode 100644 index 000000000..dfac80ddf --- /dev/null +++ b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2configuration.h @@ -0,0 +1,61 @@ +/** + ****************************************************************************** + * + * @file hitlconfiguration.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup HITLPlugin HITL Plugin + * @{ + * @brief The Hardware In The Loop plugin + *****************************************************************************/ +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef HITLV2CONFIGURATION_H +#define HITLV2CONFIGURATION_H + +#include +#include +#include +#include + +using namespace Core; + +class HITLConfiguration : public IUAVGadgetConfiguration +{ + + Q_OBJECT + + Q_PROPERTY(SimulatorSettings settings READ Settings WRITE setSimulatorSettings) + +public: + explicit HITLConfiguration(QString classId, QSettings* qSettings = 0, QObject *parent = 0); + + void saveConfig(QSettings* settings) const; + IUAVGadgetConfiguration *clone(); + + SimulatorSettings Settings() const { return settings; } + +public slots: + void setSimulatorSettings (const SimulatorSettings& params ) { settings = params; } + + +private: + SimulatorSettings settings; +}; + +#endif // HITLV2CONFIGURATION_H diff --git a/ground/openpilotgcs/src/plugins/hitlv2/hitlv2factory.cpp b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2factory.cpp new file mode 100644 index 000000000..6e6f1a42e --- /dev/null +++ b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2factory.cpp @@ -0,0 +1,58 @@ +/** + ****************************************************************************** + * + * @file hitlfactory.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup HITLPlugin HITL Plugin + * @{ + * @brief The Hardware In The Loop plugin + *****************************************************************************/ +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "hitlv2factory.h" +#include "hitlv2widget.h" +#include "hitlv2gadget.h" +#include "hitlv2configuration.h" +#include "hitlv2optionspage.h" +#include + +HITLFactory::HITLFactory(QObject *parent) + : IUAVGadgetFactory(QString("HITLv2"), tr("HITL Simulation (v2)"), parent) +{ +} + +HITLFactory::~HITLFactory() +{ +} + +Core::IUAVGadget* HITLFactory::createGadget(QWidget *parent) +{ + HITLWidget* gadgetWidget = new HITLWidget(parent); + return new HITLGadget(QString("HITLv2"), gadgetWidget, parent); +} + +IUAVGadgetConfiguration *HITLFactory::createConfiguration(QSettings* qSettings) +{ + return new HITLConfiguration(QString("HITLv2"), qSettings); +} + +IOptionsPage *HITLFactory::createOptionsPage(IUAVGadgetConfiguration *config) +{ + return new HITLOptionsPage(qobject_cast(config)); +} + diff --git a/ground/openpilotgcs/src/plugins/hitlv2/hitlv2factory.h b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2factory.h new file mode 100644 index 000000000..b4142eeed --- /dev/null +++ b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2factory.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * + * @file hitlfactory.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup HITLPlugin HITL Plugin + * @{ + * @brief The Hardware In The Loop plugin + *****************************************************************************/ +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef HITLV2FACTORY_H +#define HITLV2FACTORY_H + +#include + +namespace Core { +class IUAVGadget; +class IUAVGadgetFactory; +} + +using namespace Core; + +class HITLFactory : public Core::IUAVGadgetFactory +{ + Q_OBJECT +public: + HITLFactory(QObject *parent = 0); + ~HITLFactory(); + + IUAVGadget *createGadget(QWidget *parent); + IUAVGadgetConfiguration *createConfiguration(QSettings* qSettings); + IOptionsPage *createOptionsPage(IUAVGadgetConfiguration *config); +}; + +#endif // HITLV2FACTORY_H diff --git a/ground/openpilotgcs/src/plugins/hitlv2/hitlv2gadget.cpp b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2gadget.cpp new file mode 100644 index 000000000..de22d121b --- /dev/null +++ b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2gadget.cpp @@ -0,0 +1,49 @@ +/** + ****************************************************************************** + * + * @file hitl.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup HITLPlugin HITL Plugin + * @{ + * @brief The Hardware In The Loop plugin + *****************************************************************************/ +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "hitlv2gadget.h" +#include "hitlv2widget.h" +#include "hitlv2configuration.h" +#include "simulatorv2.h" + +HITLGadget::HITLGadget(QString classId, HITLWidget *widget, QWidget *parent) : + IUAVGadget(classId, parent), + m_widget(widget) +{ + connect(this, SIGNAL(changeConfiguration(void)), m_widget, SLOT(stopButtonClicked(void))); +} + +HITLGadget::~HITLGadget() +{ + delete m_widget; +} + +void HITLGadget::loadConfiguration(IUAVGadgetConfiguration* config) +{ + HITLConfiguration *m = qobject_cast(config); + emit changeConfiguration(); + m_widget->setSettingParameters(m->Settings()); +} diff --git a/ground/openpilotgcs/src/plugins/hitlv2/hitlv2gadget.h b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2gadget.h new file mode 100644 index 000000000..0e4fd1a80 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2gadget.h @@ -0,0 +1,60 @@ +/** + ****************************************************************************** + * + * @file hitl.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup HITLPlugin HITL Plugin + * @{ + * @brief The Hardware In The Loop plugin + *****************************************************************************/ +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef HITLV2_H +#define HITLV2_H + +#include +#include "hitlv2widget.h" + +class IUAVGadget; +class QWidget; +class QString; +class Simulator; + +using namespace Core; + +class HITLGadget : public Core::IUAVGadget +{ + Q_OBJECT +public: + HITLGadget(QString classId, HITLWidget *widget, QWidget *parent = 0); + ~HITLGadget(); + + QWidget *widget() { return m_widget; } + void loadConfiguration(IUAVGadgetConfiguration* config); + +signals: + void changeConfiguration(); + +private: + HITLWidget* m_widget; + Simulator* simulator; +}; + + +#endif // HITLV2_H diff --git a/ground/openpilotgcs/src/plugins/hitlv2/hitlv2optionspage.cpp b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2optionspage.cpp new file mode 100644 index 000000000..5b88785ad --- /dev/null +++ b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2optionspage.cpp @@ -0,0 +1,146 @@ +/** + ****************************************************************************** + * + * @file hitloptionspage.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup HITLPlugin HITL Plugin + * @{ + * @brief The Hardware In The Loop plugin + *****************************************************************************/ +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "hitlv2optionspage.h" +#include "hitlv2configuration.h" +#include "ui_hitlv2optionspage.h" +#include "hitlv2plugin.h" + +#include +#include +#include +#include "simulatorv2.h" + +HITLOptionsPage::HITLOptionsPage(HITLConfiguration *conf, QObject *parent) : + IOptionsPage(parent), + config(conf) +{ +} + +QWidget *HITLOptionsPage::createPage(QWidget *parent) +{ +// qDebug() << "HITLOptionsPage::createPage"; + // Create page + m_optionsPage = new Ui::HITLOptionsPage(); + QWidget* optionsPageWidget = new QWidget; + m_optionsPage->setupUi(optionsPageWidget); + int index = 0; + foreach (SimulatorCreator* creator, HITLPlugin::typeSimulators) + m_optionsPage->chooseFlightSimulator->insertItem(index++, creator->Description(), creator->ClassId()); + + m_optionsPage->executablePath->setExpectedKind(Utils::PathChooser::File); + m_optionsPage->executablePath->setPromptDialogTitle(tr("Choose flight simulator executable")); + m_optionsPage->dataPath->setExpectedKind(Utils::PathChooser::Directory); + m_optionsPage->dataPath->setPromptDialogTitle(tr("Choose flight simulator data directory")); + + // Restore the contents from the settings: + foreach (SimulatorCreator* creator, HITLPlugin::typeSimulators) { + QString id = config->Settings().simulatorId; + if (creator->ClassId() == id) + m_optionsPage->chooseFlightSimulator->setCurrentIndex(HITLPlugin::typeSimulators.indexOf(creator)); + } + + m_optionsPage->hostAddress->setText(config->Settings().hostAddress); + m_optionsPage->inputPort->setText(QString::number(config->Settings().inPort)); + m_optionsPage->remoteAddress->setText(config->Settings().remoteAddress); + m_optionsPage->outputPort->setText(QString::number(config->Settings().outPort)); + m_optionsPage->executablePath->setPath(config->Settings().binPath); + m_optionsPage->dataPath->setPath(config->Settings().dataPath); + + m_optionsPage->homeLocation->setChecked(config->Settings().homeLocation); + m_optionsPage->homeLocRate->setValue(config->Settings().homeLocRate); + + m_optionsPage->attRaw->setChecked(config->Settings().attRaw); + m_optionsPage->attRawRate->setValue(config->Settings().attRawRate); + + m_optionsPage->attActual->setChecked(config->Settings().attActual); + m_optionsPage->attActHW->setChecked(config->Settings().attActHW); + m_optionsPage->attActSim->setChecked(config->Settings().attActSim); + m_optionsPage->attActCalc->setChecked(config->Settings().attActCalc); + + m_optionsPage->sonarAltitude->setChecked(config->Settings().sonarAltitude); + m_optionsPage->sonarMaxAlt->setValue(config->Settings().sonarMaxAlt); + m_optionsPage->sonarAltRate->setValue(config->Settings().sonarAltRate); + + m_optionsPage->gpsPosition->setChecked(config->Settings().gpsPosition); + m_optionsPage->gpsPosRate->setValue(config->Settings().gpsPosRate); + + m_optionsPage->inputCommand->setChecked(config->Settings().inputCommand); + m_optionsPage->gcsReciever->setChecked(config->Settings().gcsReciever); + m_optionsPage->manualControl->setChecked(config->Settings().manualControl); + + m_optionsPage->manualOutput->setChecked(config->Settings().manualOutput); + m_optionsPage->outputRate->setValue(config->Settings().outputRate); + + return optionsPageWidget; +} + +void HITLOptionsPage::apply() +{ + SimulatorSettings settings; + int i = m_optionsPage->chooseFlightSimulator->currentIndex(); + + settings.simulatorId = m_optionsPage->chooseFlightSimulator->itemData(i).toString(); + settings.hostAddress = m_optionsPage->hostAddress->text(); + settings.inPort = m_optionsPage->inputPort->text().toInt(); + settings.remoteAddress = m_optionsPage->remoteAddress->text(); + settings.outPort = m_optionsPage->outputPort->text().toInt(); + settings.binPath = m_optionsPage->executablePath->path(); + settings.dataPath = m_optionsPage->dataPath->path(); + + settings.homeLocation = m_optionsPage->homeLocation->isChecked(); + settings.homeLocRate = m_optionsPage->homeLocRate->value(); + + settings.attRaw = m_optionsPage->attRaw->isChecked(); + settings.attRawRate = m_optionsPage->attRawRate->value(); + + settings.attActual = m_optionsPage->attActual->isChecked(); + settings.attActHW = m_optionsPage->attActHW->isChecked(); + settings.attActSim = m_optionsPage->attActSim->isChecked(); + settings.attActCalc = m_optionsPage->attActCalc->isChecked(); + + settings.sonarAltitude = m_optionsPage->sonarAltitude->isChecked(); + settings.sonarMaxAlt = m_optionsPage->sonarMaxAlt->value(); + settings.sonarAltRate = m_optionsPage->sonarAltRate->value(); + + settings.gpsPosition = m_optionsPage->gpsPosition->isChecked(); + settings.gpsPosRate = m_optionsPage->gpsPosRate->value(); + + settings.inputCommand = m_optionsPage->inputCommand->isChecked(); + settings.gcsReciever = m_optionsPage->gcsReciever->isChecked(); + settings.manualControl = m_optionsPage->manualControl->isChecked(); + + settings.manualOutput = m_optionsPage->manualOutput->isChecked(); + settings.outputRate = m_optionsPage->outputRate->value(); + + config->setSimulatorSettings(settings); +} + +void HITLOptionsPage::finish() +{ + delete m_optionsPage; +} diff --git a/ground/openpilotgcs/src/plugins/hitlv2/hitlv2optionspage.h b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2optionspage.h new file mode 100644 index 000000000..5c8d33f59 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2optionspage.h @@ -0,0 +1,61 @@ +/** + ****************************************************************************** + * + * @file hitloptionspage.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup HITLPlugin HITL Plugin + * @{ + * @brief The Hardware In The Loop plugin + *****************************************************************************/ +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef HITLV2OPTIONSPAGE_H +#define HITLV2OPTIONSPAGE_H + +#include + +namespace Core { +class IUAVGadgetConfiguration; +} + +class HITLConfiguration; + +using namespace Core; + +namespace Ui { +class HITLOptionsPage; +} + +class HITLOptionsPage : public IOptionsPage +{ + Q_OBJECT +public: + explicit HITLOptionsPage(HITLConfiguration *conf, QObject *parent = 0); + + QWidget *createPage(QWidget *parent); + void apply(); + void finish(); + bool isDecorated() const { return true; } + +private: + HITLConfiguration* config; + Ui::HITLOptionsPage* m_optionsPage; +}; + +#endif // HITLV2OPTIONSPAGE_H diff --git a/ground/openpilotgcs/src/plugins/hitlv2/hitlv2optionspage.ui b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2optionspage.ui new file mode 100644 index 000000000..00a2f60aa --- /dev/null +++ b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2optionspage.ui @@ -0,0 +1,639 @@ + + + HITLOptionsPage + + + + 0 + 0 + 403 + 400 + + + + Form + + + + 3 + + + 0 + + + 0 + + + 0 + + + 3 + + + + + + + Choose flight simulator: + + + + + + + + + + + + + + Local interface (IP): + + + + + + + For communication with sim computer via network. Should be the IP address of one of the interfaces of the GCS computer. + + + + + + + Remote interface (IP): + + + + + + + Only required if running simulator on remote machine. Should be the IP of the machine on which the simulator is running. + + + + + + + Input Port: + + + + + + + For receiving data from sim + + + + + + + Output Port: + + + + + + + For sending data to sim + + + + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + + 0 + 0 + + + + Path executable: + + + + + + + + + + + 0 + 0 + + + + Data directory: + + + + + + + + + + + + + + Attitude data + + + + 3 + + + 3 + + + 3 + + + 3 + + + 0 + + + + + AttitudeRaw (gyro, accels) + + + true + + + true + + + false + + + + 3 + + + 3 + + + 0 + + + 0 + + + + + Refresh rate + + + + + + + ms + + + 10 + + + 100 + + + 20 + + + + + + + + + + AttitudeActual + + + true + + + true + + + false + + + + 3 + + + 3 + + + 0 + + + 0 + + + + + send raw data to board + + + + + + + + 75 + true + + + + + + + use values from simulator + + + true + + + + + + + + + + calculate from AttitudeRaw + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + Other data + + + + 3 + + + 3 + + + 3 + + + 3 + + + 0 + + + + + HomeLocation + + + true + + + true + + + false + + + + 3 + + + 3 + + + 0 + + + 0 + + + + + Refresh rate + + + + + + + 0 - update once, or every N seconds + + + sec + + + 10 + + + + + + + + + + GPSPosition + + + true + + + true + + + false + + + + 3 + + + 3 + + + 0 + + + 0 + + + + + Refresh rate + + + + + + + ms + + + 100 + + + 2000 + + + 500 + + + + + + + + + + SonarAltitude + + + true + + + true + + + false + + + + 3 + + + 6 + + + 3 + + + 0 + + + 0 + + + + + + + Range detectioon + + + + + + + m + + + 1 + + + 10 + + + 5 + + + + + + + Refresh rate + + + + + + + ms + + + 20 + + + 2000 + + + 10 + + + 50 + + + + + + + + + + + + Map command from simulator + + + true + + + true + + + false + + + + 3 + + + 3 + + + 0 + + + 0 + + + + + + 75 + true + + + + to GCSReciver + + + true + + + + + + + false + + + to ManualCtrll (not implemented) + + + + + + + + + + 6 + + + + + Maximum output rate + + + + + + + ms + + + 10 + + + 100 + + + 5 + + + 15 + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + Utils::PathChooser + QWidget +
utils/pathchooser.h
+ 1 +
+
+ + chooseFlightSimulator + hostAddress + inputPort + remoteAddress + outputPort + + + +
diff --git a/ground/openpilotgcs/src/plugins/hitlv2/hitlv2plugin.cpp b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2plugin.cpp new file mode 100644 index 000000000..f0ee2d07a --- /dev/null +++ b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2plugin.cpp @@ -0,0 +1,70 @@ +/** + ****************************************************************************** + * + * @file mapplugin.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup HITLPlugin HITL Plugin + * @{ + * @brief The Hardware In The Loop plugin + *****************************************************************************/ +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "hitlv2plugin.h" +#include "hitlv2factory.h" +#include +#include +#include + +#include "aerosimrc.h" + +QList HITLPlugin::typeSimulators; + +HITLPlugin::HITLPlugin() +{ + // Do nothing +} + +HITLPlugin::~HITLPlugin() +{ + // Do nothing +} + +bool HITLPlugin::initialize(const QStringList& args, QString *errMsg) +{ + Q_UNUSED(args); + Q_UNUSED(errMsg); + mf = new HITLFactory(this); + + addAutoReleasedObject(mf); + + addSimulator(new AeroSimRCSimulatorCreator("ASimRC", "AeroSimRC")); + + return true; +} + +void HITLPlugin::extensionsInitialized() +{ + // Do nothing +} + +void HITLPlugin::shutdown() +{ + // Do nothing +} +Q_EXPORT_PLUGIN(HITLPlugin) + diff --git a/ground/openpilotgcs/src/plugins/hitlv2/hitlv2plugin.h b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2plugin.h new file mode 100644 index 000000000..e68129bd4 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2plugin.h @@ -0,0 +1,67 @@ +/** + ****************************************************************************** + * + * @file browserplugin.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup HITLPlugin HITL Plugin + * @{ + * @brief The Hardware In The Loop plugin + *****************************************************************************/ +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef HITLV2PLUGIN_H +#define HITLV2PLUGIN_H + +#include +#include + +#include + +class HITLFactory; + +class HITLPlugin : public ExtensionSystem::IPlugin +{ +public: + HITLPlugin(); + ~HITLPlugin(); + + void extensionsInitialized(); + bool initialize(const QStringList & arguments, QString * errorString); + void shutdown(); + + static void addSimulator(SimulatorCreator* creator) + { + HITLPlugin::typeSimulators.append(creator); + } + + static SimulatorCreator* getSimulatorCreator(const QString classId) + { + foreach(SimulatorCreator* creator, HITLPlugin::typeSimulators) { + if(classId == creator->ClassId()) + return creator; + } + return 0; + } + + static QList typeSimulators; + +private: + HITLFactory *mf; +}; +#endif /* HITLV2PLUGIN_H */ diff --git a/ground/openpilotgcs/src/plugins/hitlv2/hitlv2widget.cpp b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2widget.cpp new file mode 100644 index 000000000..55d14f735 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2widget.cpp @@ -0,0 +1,187 @@ +/** + ****************************************************************************** + * + * @file hitlwidget.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup HITLPlugin HITL Plugin + * @{ + * @brief The Hardware In The Loop plugin + *****************************************************************************/ +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "hitlv2widget.h" +#include "ui_hitlv2widget.h" +#include +#include +#include +#include +#include + +#include "hitlv2plugin.h" +#include "simulatorv2.h" +#include "uavobjectmanager.h" +#include +#include + +QStringList Simulator::instances; + +HITLWidget::HITLWidget(QWidget *parent) + : QWidget(parent), + simulator(0) +{ + widget = new Ui_HITLWidget(); + widget->setupUi(this); + widget->startButton->setEnabled(true); + widget->stopButton->setEnabled(false); + + strAutopilotDisconnected = " AP OFF "; + strSimulatorDisconnected = " Sim OFF "; + strAutopilotConnected = " AP ON "; +// strSimulatorConnected = " Sim ON "; + strStyleEnable = "QFrame{background-color: green; color: white}"; + strStyleDisable = "QFrame{background-color: red; color: grey}"; + + widget->apLabel->setText(strAutopilotDisconnected); + widget->simLabel->setText(strSimulatorDisconnected); + + connect(widget->startButton, SIGNAL(clicked()), this, SLOT(startButtonClicked())); + connect(widget->stopButton, SIGNAL(clicked()), this, SLOT(stopButtonClicked())); + connect(widget->buttonClearLog, SIGNAL(clicked()), this, SLOT(buttonClearLogClicked())); +} + +HITLWidget::~HITLWidget() +{ + delete widget; +} + +void HITLWidget::startButtonClicked() +{ + // allow only one instance per simulator + if (Simulator::Instances().indexOf(settings.simulatorId) != -1) { + widget->textBrowser->append(settings.simulatorId + " alreary started!"); + return; + } + + if (!HITLPlugin::typeSimulators.size()) { + widget->textBrowser->append("There is no registered simulators, add through HITLPlugin::addSimulator"); + return; + } + + // Stop running process if one is active + if (simulator) { + QMetaObject::invokeMethod(simulator, "onDeleteSimulator", Qt::QueuedConnection); + simulator = NULL; + } + + if (settings.hostAddress == "" || settings.inPort == 0) { + widget->textBrowser->append("Before start, set UDP parameters in options page!"); + return; + } + + SimulatorCreator* creator = HITLPlugin::getSimulatorCreator(settings.simulatorId); + simulator = creator->createSimulator(settings); + simulator->setName(creator->Description()); + simulator->setSimulatorId(creator->ClassId()); + + connect(simulator, SIGNAL(processOutput(QString)), this, SLOT(onProcessOutput(QString))); + + // Setup process + onProcessOutput(QString("[%1] Starting %2... ") + .arg(QTime::currentTime().toString("hh:mm:ss")) + .arg(creator->Description())); + + // Start bridge + bool ret = QMetaObject::invokeMethod(simulator, "setupProcess", Qt::QueuedConnection); + if (ret) { + Simulator::setInstance(settings.simulatorId); + + connect(this, SIGNAL(deleteSimulator()), simulator, SLOT(onDeleteSimulator()), Qt::QueuedConnection); + + widget->startButton->setEnabled(false); + widget->stopButton->setEnabled(true); + + connect(simulator, SIGNAL(autopilotConnected()), this, SLOT(onAutopilotConnect()), Qt::QueuedConnection); + connect(simulator, SIGNAL(autopilotDisconnected()), this, SLOT(onAutopilotDisconnect()), Qt::QueuedConnection); + connect(simulator, SIGNAL(simulatorConnected()), this, SLOT(onSimulatorConnect()), Qt::QueuedConnection); + connect(simulator, SIGNAL(simulatorDisconnected()), this, SLOT(onSimulatorDisconnect()), Qt::QueuedConnection); + + // Initialize connection status + if (simulator->isAutopilotConnected()) + onAutopilotConnect(); + else + onAutopilotDisconnect(); + + if (simulator->isSimulatorConnected()) + onSimulatorConnect(); + else + onSimulatorDisconnect(); + } +} + +void HITLWidget::stopButtonClicked() +{ + if (simulator) + widget->textBrowser->append(QString("[%1] Terminate %2 ") + .arg(QTime::currentTime().toString("hh:mm:ss")) + .arg(simulator->Name())); + + widget->startButton->setEnabled(true); + widget->stopButton->setEnabled(false); + widget->apLabel->setStyleSheet(QString::fromUtf8("QFrame{background-color: transparent; color: white}")); + widget->simLabel->setStyleSheet(QString::fromUtf8("QFrame{background-color: transparent; color: white}")); + widget->apLabel->setText(strAutopilotDisconnected); + widget->simLabel->setText(strSimulatorDisconnected); + if (simulator) { + QMetaObject::invokeMethod(simulator, "onDeleteSimulator", Qt::QueuedConnection); + simulator = NULL; + } +} + +void HITLWidget::buttonClearLogClicked() +{ + widget->textBrowser->clear(); +} + +void HITLWidget::onProcessOutput(QString text) +{ + widget->textBrowser->append(text); +} + +void HITLWidget::onAutopilotConnect() +{ + widget->apLabel->setStyleSheet(strStyleEnable); + widget->apLabel->setText(strAutopilotConnected); +} + +void HITLWidget::onAutopilotDisconnect() +{ + widget->apLabel->setStyleSheet(strStyleDisable); + widget->apLabel->setText(strAutopilotDisconnected); +} + +void HITLWidget::onSimulatorConnect() +{ + widget->simLabel->setStyleSheet(strStyleEnable); + widget->simLabel->setText(" " + simulator->Name() + " ON "); +} + +void HITLWidget::onSimulatorDisconnect() +{ + widget->simLabel->setStyleSheet(strStyleDisable); + widget->simLabel->setText(" " + simulator->Name() + " OFF "); +} diff --git a/ground/openpilotgcs/src/plugins/hitlv2/hitlv2widget.h b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2widget.h new file mode 100644 index 000000000..78f3e9405 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2widget.h @@ -0,0 +1,72 @@ +/** + ****************************************************************************** + * + * @file hitlwidget.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup HITLPlugin HITL Plugin + * @{ + * @brief The Hardware In The Loop plugin + *****************************************************************************/ +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef HITLV2WIDGET_H +#define HITLV2WIDGET_H + +#include +#include +#include "simulatorv2.h" + +class Ui_HITLWidget; + +class HITLWidget : public QWidget +{ + Q_OBJECT + +public: + HITLWidget(QWidget *parent = 0); + ~HITLWidget(); + + void setSettingParameters(const SimulatorSettings& params) { settings = params; } + +signals: + void deleteSimulator(); + +private slots: + void startButtonClicked(); + void stopButtonClicked(); + void buttonClearLogClicked(); + void onProcessOutput(QString text); + void onAutopilotConnect(); + void onAutopilotDisconnect(); + void onSimulatorConnect(); + void onSimulatorDisconnect(); + +private: + Ui_HITLWidget* widget; + Simulator* simulator; + SimulatorSettings settings; + + QString strAutopilotDisconnected; + QString strSimulatorDisconnected; + QString strAutopilotConnected; +// QString strSimulatorConnected; + QString strStyleEnable; + QString strStyleDisable; +}; +#endif /* HITLV2WIDGET_H */ diff --git a/ground/openpilotgcs/src/plugins/hitlv2/hitlv2widget.ui b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2widget.ui new file mode 100644 index 000000000..48d2c2db2 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/hitlv2/hitlv2widget.ui @@ -0,0 +1,314 @@ + + + HITLWidget + + + + 0 + 0 + 477 + 300 + + + + + 0 + 0 + + + + Form + + + + +QScrollBar:vertical { + border: 1px solid grey; + background: grey; + margin: 22px 0 22px 0; + } + +QScrollBar:vertical:disabled { + border: 1px solid grey; + + background-color: grey; + margin: 22px 0 22px 0; + } + + QScrollBar::handle:vertical { +background-color: qlineargradient(spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, stop:0 rgba(120, 120, 255, 255), stop:1 rgba(80, 80, 160, 255)); + min-height: 20px; + } + +QScrollBar::handle:vertical:disabled{ +background-color: grey; + min-height: 20px; + } + + + QScrollBar::handle:vertical:pressed { + + background-color: rgb(85, 85, 255); +background-color: qlineargradient(spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, stop:0 rgba(170, 170, 255, 255), stop:1 rgba(80, 80, 160, 255)); + + min-height: 20px; + } + + QScrollBar::add-line:vertical { + border: 1px solid black; +background-color: qlineargradient(spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, stop:0 rgba(48, 48, 48, 255), stop:1 rgba(120, 120, 120, 255)); + height: 20px; + subcontrol-position: bottom; + subcontrol-origin: margin; + } + + QScrollBar::add-line:vertical:disabled { +background-color: qlineargradient(spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, stop:0 rgba(100, 100, 100, 255)); + border: 1px solid grey; + + } + + QScrollBar::sub-line:vertical:disabled { +background-color: qlineargradient(spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, stop:0 rgba(100, 100, 100, 255)); + border: 1px solid grey; + + } + + QScrollBar::add-line:vertical:pressed { +background-color: qlineargradient(spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, stop:0 rgba(255, 255, 255, 200), stop:1 rgba(180, 180, 180, 200)); + } + + QScrollBar::sub-line:vertical:pressed { +background-color: qlineargradient(spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, stop:0 rgba(255, 255, 255, 200), stop:1 rgba(180, 180, 180, 200)); + } + + QScrollBar::sub-line:vertical { + border: 1px solid black; +background-color: qlineargradient(spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, stop:0 rgba(48, 48, 48, 255), stop:1 rgba(120, 120, 120, 255)); + height: 20px; + subcontrol-position: top; + subcontrol-origin: margin; + } + QScrollBar::down-arrow:vertical { + + image: url(:/hitlnew/images/arrow-down2.png); + } + + QScrollBar::up-arrow:vertical { + image: url(:/hitlnew/images/arrow-up2.png); + } + + QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { + background: none; + } + + +QPushButton { +background-color: qlineargradient(spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, stop:0 rgba(110, 110, 110, 255), stop:1 rgba(71, 71, 71, 255)); + + color: rgb(255, 255, 255); +border: 1px solid black; +width: 66px; +height: 20px; +} + +QPushButton:disabled { +background-color: qlineargradient(spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, stop:0 rgba(120, 120, 120, 255)); + color: rgb(194, 194, 194); +border: 1px solid gray; +width: 66px; +height: 20px; +} + +QPushButton:hover { +background-color: qlineargradient(spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, stop:0 rgba(255, 255, 255, 200), stop:1 rgba(180, 180, 180, 200)); +color: rgb(255, 255, 255); +border: 0px; +} +QPushButton:pressed { +background-color: qlineargradient(spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, stop:0 rgba(48, 48, 48, 255), stop:1 rgba(120, 120, 120, 255)); +color: rgb(255, 255, 255); +border: 0px; +} + +QPushButton:checked { +background-color: qlineargradient(spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, stop:0 rgba(48, 48, 48, 255), stop:1 rgba(120, 120, 120, 255)); +color: rgb(255, 255, 255); +border: 0px; +} + + + + 0 + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + +QFrame{ +background-color: qlineargradient(spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, stop:0 rgba(110, 110, 110, 255), stop:1 rgba(71, 71, 71, 255)); +color: rgba(0, 0, 0, 128); +} + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + QLayout::SetMaximumSize + + + + + QLayout::SetDefaultConstraint + + + + + Request update + + + + + + Start + + + + + + + false + + + Send update + + + Stop + + + + + + + + 0 + 22 + + + + + 50 + false + + + + Qt::LeftToRight + + + false + + + color: rgb(255, 255, 255); + + + AP OFF + + + Qt::AlignCenter + + + + + + + + 0 + 22 + + + + color: rgb(255, 255, 255); + + + Sim OFF + + + Qt::AlignCenter + + + + + + + Clear Log + + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + false + + + QTextEdit { + background-color: white; + color: rgb(0, 0, 0); +} + + + QFrame::NoFrame + + + QFrame::Plain + + + Qt::ScrollBarAlwaysOn + + + + + + + + + + + diff --git a/ground/openpilotgcs/src/plugins/hitlv2/simulatorv2.cpp b/ground/openpilotgcs/src/plugins/hitlv2/simulatorv2.cpp new file mode 100644 index 000000000..c4c698689 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/hitlv2/simulatorv2.cpp @@ -0,0 +1,341 @@ +/** + ****************************************************************************** + * + * @file simulator.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup HITLPlugin HITL Plugin + * @{ + * @brief The Hardware In The Loop plugin + *****************************************************************************/ +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "simulatorv2.h" +#include +#include +#include + +volatile bool Simulator::isStarted = false; + +const float Simulator::GEE = 9.81; +const float Simulator::FT2M = 0.3048; +const float Simulator::KT2MPS = 0.514444444; +const float Simulator::INHG2KPA = 3.386; +const float Simulator::FPS2CMPS = 30.48; +const float Simulator::DEG2RAD = (M_PI/180.0); +const float Simulator::RAD2DEG = (180.0/M_PI); + + +Simulator::Simulator(const SimulatorSettings& params) : + inSocket(NULL), + outSocket(NULL), + settings(params), + updatePeriod(50), + simTimeout(2000), + autopilotConnectionStatus(false), + simConnectionStatus(false), + txTimer(NULL), + simTimer(NULL), + name("") +{ + // move to thread + moveToThread(Core::ICore::instance()->threadManager()->getRealTimeThread()); + connect(this, SIGNAL(myStart()), this, SLOT(onStart()), Qt::QueuedConnection); + emit myStart(); +} + +Simulator::~Simulator() +{ +// qDebug() << "Simulator::~Simulator"; + if (inSocket) { + delete inSocket; + inSocket = NULL; + } + if (outSocket) { + delete outSocket; + outSocket = NULL; + } + if (txTimer) { + delete txTimer; + txTimer = NULL; + } + if (simTimer) { + delete simTimer; + simTimer = NULL; + } +} + +void Simulator::onDeleteSimulator(void) +{ +// qDebug() << "Simulator::onDeleteSimulator"; + resetAllObjects(); + + Simulator::setStarted(false); + Simulator::Instances().removeOne(simulatorId); + + disconnect(this); + delete this; +} + +void Simulator::onStart() +{ +// qDebug() << "Simulator::onStart"; + QMutexLocker locker(&lock); + + // Get required UAVObjects + ExtensionSystem::PluginManager* pm = ExtensionSystem::PluginManager::instance(); + UAVObjectManager* objManager = pm->getObject(); + +// actDesired = ActuatorDesired::GetInstance(objManager); +// manCtrlCommand = ManualControlCommand::GetInstance(objManager); +// velActual = VelocityActual::GetInstance(objManager); +// posActual = PositionActual::GetInstance(objManager); +// altActual = BaroAltitude::GetInstance(objManager); +// camDesired = CameraDesired::GetInstance(objManager); +// acsDesired = AccessoryDesired::GetInstance(objManager); + posHome = HomeLocation::GetInstance(objManager); + accels = Accels::GetInstance(objManager); + gyros = Gyros::GetInstance(objManager); + attActual = AttitudeActual::GetInstance(objManager); + gpsPosition = GPSPosition::GetInstance(objManager); + flightStatus = FlightStatus::GetInstance(objManager); + gcsReceiver = GCSReceiver::GetInstance(objManager); + actCommand = ActuatorCommand::GetInstance(objManager); + attSettings = AttitudeSettings::GetInstance(objManager); + sonarAlt = SonarAltitude::GetInstance(objManager); + + telStats = GCSTelemetryStats::GetInstance(objManager); + + // Listen to autopilot connection events + TelemetryManager* telMngr = pm->getObject(); + connect(telMngr, SIGNAL(connected()), this, SLOT(onAutopilotConnect())); + connect(telMngr, SIGNAL(disconnected()), this, SLOT(onAutopilotDisconnect())); + + // If already connect setup autopilot + GCSTelemetryStats::DataFields stats = telStats->getData(); + if (stats.Status == GCSTelemetryStats::STATUS_CONNECTED) + onAutopilotConnect(); + + emit processOutput("Local interface: " + settings.hostAddress + ":" + \ + QString::number(settings.inPort) + "\n" + \ + "Remote interface: " + settings.remoteAddress + ":" + \ + QString::number(settings.outPort) + "\n"); + + inSocket = new QUdpSocket(); + outSocket = new QUdpSocket(); + setupUdpPorts(settings.hostAddress, settings.inPort, settings.outPort); + + connect(inSocket, SIGNAL(readyRead()), this, SLOT(receiveUpdate())/*, Qt::DirectConnection*/); + + // Setup transmit timer + if (settings.manualOutput) { + txTimer = new QTimer(); + connect(txTimer, SIGNAL(timeout()), this, SLOT(transmitUpdate())/*, Qt::DirectConnection*/); + txTimer->setInterval(settings.outputRate); + txTimer->start(); + } + + // Setup simulator connection timer + simTimer = new QTimer(); + connect(simTimer, SIGNAL(timeout()), this, SLOT(onSimulatorConnectionTimeout())/*, Qt::DirectConnection*/); + simTimer->setInterval(simTimeout); + simTimer->start(); + +#ifdef DBG_TIMERS + timeRX = QTime(); + timeRX.start(); + timeTX = QTime(); + timeTX.start(); +#endif + + setupObjects(); +} + +void Simulator::receiveUpdate() +{ + // Update connection timer and status + simTimer->start(); + if (!simConnectionStatus) { + simConnectionStatus = true; + emit simulatorConnected(); + } + + // Process data + while (inSocket->hasPendingDatagrams()) { + // Receive datagram + QByteArray datagram; + datagram.resize(inSocket->pendingDatagramSize()); + QHostAddress sender; + quint16 senderPort; + inSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort); + // Process incomming data + processUpdate(datagram); + } + if (!settings.manualOutput) + transmitUpdate(); +} + +void Simulator::setupObjects() +{ + if (settings.gcsReciever) { + setupInputObject(actCommand, settings.outputRate); + setupOutputObject(gcsReceiver); + } else if (settings.manualControl) { +// setupInputObject(actDesired); +// setupInputObject(camDesired); +// setupInputObject(acsDesired); +// setupOutputObject(manCtrlCommand); + qDebug() << "ManualControlCommand not implemented yet"; + } + + if (settings.homeLocation) + setupOutputObject(posHome); + + if (settings.sonarAltitude) + setupOutputObject(sonarAlt); + + if (settings.gpsPosition) + setupOutputObject(gpsPosition); + + if (settings.attRaw || settings.attActual) { + setupOutputObject(accels); + setupOutputObject(gyros); + } + + if (settings.attActual && !settings.attActHW) + setupOutputObject(attActual); + else + setupWatchedObject(attActual); +} + +void Simulator::resetAllObjects() +{ + setupDefaultObject(posHome); + setupDefaultObject(accels); + setupDefaultObject(gyros); + setupDefaultObject(attActual); + setupDefaultObject(gpsPosition); + setupDefaultObject(gcsReceiver); + setupDefaultObject(actCommand); + setupDefaultObject(sonarAlt); +// setupDefaultObject(manCtrlCommand); +// setupDefaultObject(actDesired); +// setupDefaultObject(camDesired); +// setupDefaultObject(acsDesired); +// setupDefaultObject(altActual); +// setupDefaultObject(posActual); +// setupDefaultObject(velActual); +} + +void Simulator::setupInputObject(UAVObject* obj, quint32 updateRate) +{ + UAVObject::Metadata mdata; + mdata = obj->getDefaultMetadata(); + + UAVObject::SetGcsAccess(mdata, UAVObject::ACCESS_READONLY); + UAVObject::SetGcsTelemetryAcked(mdata, false); + UAVObject::SetGcsTelemetryUpdateMode(mdata, UAVObject::UPDATEMODE_MANUAL); + mdata.gcsTelemetryUpdatePeriod = 0; + + UAVObject::SetFlightAccess(mdata, UAVObject::ACCESS_READWRITE); + UAVObject::SetFlightTelemetryAcked(mdata, false); + + if (settings.manualOutput) { + UAVObject::SetFlightTelemetryUpdateMode(mdata, UAVObject::UPDATEMODE_PERIODIC); + mdata.flightTelemetryUpdatePeriod = updateRate; + } else { + UAVObject::SetFlightTelemetryUpdateMode(mdata, UAVObject::UPDATEMODE_ONCHANGE); + mdata.flightTelemetryUpdatePeriod = 0; + } + + obj->setMetadata(mdata); +} + +void Simulator::setupWatchedObject(UAVObject *obj) +{ + UAVObject::Metadata mdata; + mdata = obj->getDefaultMetadata(); + + UAVObject::SetGcsAccess(mdata, UAVObject::ACCESS_READONLY); + UAVObject::SetGcsTelemetryAcked(mdata, false); + UAVObject::SetGcsTelemetryUpdateMode(mdata, UAVObject::UPDATEMODE_MANUAL); + mdata.gcsTelemetryUpdatePeriod = 0; + + UAVObject::SetFlightAccess(mdata, UAVObject::ACCESS_READWRITE); + UAVObject::SetFlightTelemetryAcked(mdata, false); + UAVObject::SetFlightTelemetryUpdateMode(mdata, UAVObject::UPDATEMODE_PERIODIC); + mdata.flightTelemetryUpdatePeriod = 100; + + obj->setMetadata(mdata); +} + +void Simulator::setupOutputObject(UAVObject* obj) +{ + UAVObject::Metadata mdata; + mdata = obj->getDefaultMetadata(); + + UAVObject::SetGcsAccess(mdata, UAVObject::ACCESS_READWRITE); + UAVObject::SetGcsTelemetryAcked(mdata, false); + UAVObject::SetGcsTelemetryUpdateMode(mdata, UAVObject::UPDATEMODE_ONCHANGE); + mdata.gcsTelemetryUpdatePeriod = 0; + + UAVObject::SetFlightAccess(mdata, UAVObject::ACCESS_READONLY); + UAVObject::SetFlightTelemetryAcked(mdata, false); + UAVObject::SetFlightTelemetryUpdateMode(mdata, UAVObject::UPDATEMODE_MANUAL); + mdata.flightTelemetryUpdatePeriod = 0; + + obj->setMetadata(mdata); +} + +void Simulator::setupDefaultObject(UAVObject *obj) +{ + UAVObject::Metadata mdata; + mdata = obj->getDefaultMetadata(); + + obj->setMetadata(mdata); +} + +void Simulator::onAutopilotConnect() +{ + autopilotConnectionStatus = true; + emit autopilotConnected(); +} + +void Simulator::onAutopilotDisconnect() +{ + autopilotConnectionStatus = false; + emit autopilotDisconnected(); +} + +void Simulator::onSimulatorConnectionTimeout() +{ + if (simConnectionStatus) { + simConnectionStatus = false; + emit simulatorDisconnected(); + } +} + +void Simulator::telStatsUpdated(UAVObject* obj) +{ + GCSTelemetryStats::DataFields stats = telStats->getData(); + if (!autopilotConnectionStatus && stats.Status == GCSTelemetryStats::STATUS_CONNECTED) + onAutopilotConnect(); + else if (autopilotConnectionStatus && stats.Status != GCSTelemetryStats::STATUS_CONNECTED) + onAutopilotDisconnect(); +} + diff --git a/ground/openpilotgcs/src/plugins/hitlv2/simulatorv2.h b/ground/openpilotgcs/src/plugins/hitlv2/simulatorv2.h new file mode 100644 index 000000000..6a0a9f008 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/hitlv2/simulatorv2.h @@ -0,0 +1,222 @@ +/** + ****************************************************************************** + * + * @file simulator.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup HITLPlugin HITL Plugin + * @{ + * @brief The Hardware In The Loop plugin + *****************************************************************************/ +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef ISIMULATORV2_H +#define ISIMULATORV2_H + +#include +#include +#include +#include +#include +#include +#include "uavtalk/telemetrymanager.h" +#include "uavobjectmanager.h" +#include "homelocation.h" +#include "accels.h" +#include "gyros.h" +#include "attitudeactual.h" +#include "gpsposition.h" +#include "flightstatus.h" +#include "gcsreceiver.h" +#include "actuatorcommand.h" +#include "gcstelemetrystats.h" +#include "attitudesettings.h" +#include "sonaraltitude.h" + +//#define DBG_TIMERS +#undef DBG_TIMERS + +/** + * just imagine this was a class without methods and all public properties + */ + +typedef struct _CONNECTION +{ + QString simulatorId; + QString hostAddress; + int inPort; + QString remoteAddress; + int outPort; + QString binPath; + QString dataPath; + + bool homeLocation; + quint16 homeLocRate; + + bool attRaw; + quint8 attRawRate; + + bool attActual; + bool attActHW; + bool attActSim; + bool attActCalc; + + bool sonarAltitude; + float sonarMaxAlt; + quint16 sonarAltRate; + + bool gpsPosition; + quint16 gpsPosRate; + + bool inputCommand; + bool gcsReciever; + bool manualControl; + bool manualOutput; + quint8 outputRate; + +} SimulatorSettings; + +class Simulator : public QObject +{ + Q_OBJECT + +public: + Simulator(const SimulatorSettings& params); + virtual ~Simulator(); + + bool isAutopilotConnected() const { return autopilotConnectionStatus; } + bool isSimulatorConnected() const { return simConnectionStatus; } + + QString Name() const { return name; } + void setName(QString str) { name = str; } + + QString SimulatorId() const { return simulatorId; } + void setSimulatorId(QString str) { simulatorId = str; } + + static bool IsStarted() { return isStarted; } + static void setStarted(bool val) { isStarted = val; } + + static QStringList& Instances() { return Simulator::instances; } + static void setInstance(const QString& str) { Simulator::instances.append(str); } + + virtual void stopProcess() {} + virtual void setupUdpPorts(const QString& host, int inPort, int outPort) { Q_UNUSED(host) Q_UNUSED(inPort) Q_UNUSED(outPort)} + +signals: + void processOutput(QString str); + void autopilotConnected(); + void autopilotDisconnected(); + void simulatorConnected(); + void simulatorDisconnected(); + void myStart(); + +public slots: + Q_INVOKABLE virtual bool setupProcess() { return true; } + +private slots: + void onStart(); + void receiveUpdate(); + void onAutopilotConnect(); + void onAutopilotDisconnect(); + void onSimulatorConnectionTimeout(); + void telStatsUpdated(UAVObject* obj); + Q_INVOKABLE void onDeleteSimulator(void); + + virtual void transmitUpdate() = 0; + virtual void processUpdate(const QByteArray& data) = 0; + +protected: + static const float GEE; + static const float FT2M; + static const float KT2MPS; + static const float INHG2KPA; + static const float FPS2CMPS; + static const float DEG2RAD; + static const float RAD2DEG; + +#ifdef DBG_TIMERS + QTime timeRX; + QTime timeTX; +#endif + + QUdpSocket* inSocket; + QUdpSocket* outSocket; + +// ActuatorDesired* actDesired; +// ManualControlCommand* manCtrlCommand; +// VelocityActual* velActual; +// PositionActual* posActual; +// BaroAltitude* altActual; +// CameraDesired *camDesired; +// AccessoryDesired *acsDesired; + Accels *accels; + Gyros *gyros; + AttitudeActual *attActual; + HomeLocation *posHome; + FlightStatus *flightStatus; + GPSPosition *gpsPosition; + GCSReceiver *gcsReceiver; + ActuatorCommand *actCommand; + AttitudeSettings *attSettings; + SonarAltitude *sonarAlt; + + GCSTelemetryStats* telStats; + SimulatorSettings settings; + + QMutex lock; + +private: + int updatePeriod; + int simTimeout; + volatile bool autopilotConnectionStatus; + volatile bool simConnectionStatus; + QTimer* txTimer; + QTimer* simTimer; + QString name; + QString simulatorId; + volatile static bool isStarted; + static QStringList instances; + + void setupObjects(); + void resetAllObjects(); + void setupInputObject(UAVObject* obj, quint32 updateRate); + void setupOutputObject(UAVObject* obj); + void setupWatchedObject(UAVObject *obj); + void setupDefaultObject(UAVObject *obj); +}; + +class SimulatorCreator +{ +public: + SimulatorCreator(QString id, QString descr) : + classId(id), + description(descr) + {} + virtual ~SimulatorCreator() {} + + QString ClassId() const { return classId; } + QString Description() const { return description; } + + virtual Simulator* createSimulator(const SimulatorSettings& params) = 0; + +private: + QString classId; + QString description; +}; + +#endif // ISIMULATORV2_H diff --git a/ground/openpilotgcs/src/plugins/notify/notifypluginoptionspage.cpp b/ground/openpilotgcs/src/plugins/notify/notifypluginoptionspage.cpp index fa8ff053f..38df0eb52 100644 --- a/ground/openpilotgcs/src/plugins/notify/notifypluginoptionspage.cpp +++ b/ground/openpilotgcs/src/plugins/notify/notifypluginoptionspage.cpp @@ -256,7 +256,10 @@ void NotifyPluginOptionsPage::addDynamicField(UAVObjectField* objField) _dynamicFieldCondition->removeItem(smaller); _dynamicFieldCondition->removeItem(bigger); } - _dynamicFieldCondition->setCurrentIndex(_dynamicFieldCondition->findText(NotifyPluginOptionsPage::conditionValues.at(_selectedNotification->getCondition()))); + int cond=_selectedNotification->getCondition(); + if(cond<0) + return; + _dynamicFieldCondition->setCurrentIndex(_dynamicFieldCondition->findText(NotifyPluginOptionsPage::conditionValues.at(cond))); connect(_dynamicFieldCondition, SIGNAL(currentIndexChanged(QString)), this, SLOT(on_changedIndex_rangeValue(QString))); @@ -434,8 +437,10 @@ void NotifyPluginOptionsPage::updateConfigView(NotificationItem* notification) _optionsPage->SoundCollectionList->setCurrentIndex(_optionsPage->SoundCollectionList->findText("default")); _optionsPage->Sound3->setCurrentIndex(_optionsPage->Sound3->findText(notification->getSound3())); } - - _dynamicFieldCondition->setCurrentIndex(_dynamicFieldCondition->findText(NotifyPluginOptionsPage::conditionValues.at(notification->getCondition()))); + int cond=notification->getCondition(); + if(cond<0) + return; + _dynamicFieldCondition->setCurrentIndex(_dynamicFieldCondition->findText(NotifyPluginOptionsPage::conditionValues.at(cond))); _sayOrder->setCurrentIndex(notification->getSayOrder()); diff --git a/ground/openpilotgcs/src/plugins/plugins.pro b/ground/openpilotgcs/src/plugins/plugins.pro index b6a9a309d..154335e3a 100644 --- a/ground/openpilotgcs/src/plugins/plugins.pro +++ b/ground/openpilotgcs/src/plugins/plugins.pro @@ -140,13 +140,19 @@ plugin_ipconnection.subdir = ipconnection plugin_ipconnection.depends = plugin_coreplugin SUBDIRS += plugin_ipconnection -# Disable until updated to the new sensor objects #HITLNEW Simulation gadget -#plugin_hitlnew.subdir = hitlnew -#plugin_hitlnew.depends = plugin_coreplugin -#plugin_hitlnew.depends += plugin_uavobjects -#plugin_hitlnew.depends += plugin_uavtalk -#SUBDIRS += plugin_hitlnew +plugin_hitlnew.subdir = hitlnew +plugin_hitlnew.depends = plugin_coreplugin +plugin_hitlnew.depends += plugin_uavobjects +plugin_hitlnew.depends += plugin_uavtalk +SUBDIRS += plugin_hitlnew + +#HITLNEW Simulation gadget v2 +plugin_hitl_v2.subdir = hitlv2 +plugin_hitl_v2.depends = plugin_coreplugin +plugin_hitl_v2.depends += plugin_uavobjects +plugin_hitl_v2.depends += plugin_uavtalk +SUBDIRS += plugin_hitl_v2 # Export and Import GCS Configuration plugin_importexport.subdir = importexport diff --git a/ground/openpilotgcs/src/plugins/uavobjectutil/devicedescriptorstruct.h b/ground/openpilotgcs/src/plugins/uavobjectutil/devicedescriptorstruct.h index bf8fafb19..a725c0bfe 100644 --- a/ground/openpilotgcs/src/plugins/uavobjectutil/devicedescriptorstruct.h +++ b/ground/openpilotgcs/src/plugins/uavobjectutil/devicedescriptorstruct.h @@ -12,18 +12,23 @@ public: int boardRevision; static QString idToBoardName(int id) { - switch (id | 0x0011) { - case 0x0111://MB + switch (id) { + case 0x0101://MB return QString("OpenPilot MainBoard"); break; - case 0x0311://PipX + case 0x0201://INS + return QString("OpenPilot INS"); + break; + case 0x0301://PipX return QString("PipXtreame"); break; - case 0x0411://Coptercontrol + case 0x0401://Coptercontrol return QString("CopterControl"); break; - case 0x0211://INS - return QString("OpenPilot INS"); + case 0x0402://Coptercontrol + // It would be nice to say CC3D here but since currently we use string comparisons + // for firmware compatibility and the filename path that would break + return QString("CopterControl"); break; default: return QString(""); diff --git a/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutilmanager.cpp b/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutilmanager.cpp index 1d1d208a9..a30172fb0 100644 --- a/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutilmanager.cpp +++ b/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutilmanager.cpp @@ -35,6 +35,7 @@ #include #include #include +#include // ****************************** // constructor/destructor @@ -199,25 +200,63 @@ void UAVObjectUtilManager::objectPersistenceOperationFailed() */ void UAVObjectUtilManager::objectPersistenceUpdated(UAVObject * obj) { - qDebug() << "objectPersistenceUpdated: " << obj->getField("Operation")->getValue().toString(); - Q_ASSERT(obj->getName().compare("ObjectPersistence") == 0); - if(saveState == AWAITING_COMPLETED) { - failureTimer.stop(); - // Check flight is saying it completed. This is the only thing flight should do to trigger an update. - Q_ASSERT( obj->getField("Operation")->getValue().toString().compare(QString("Completed")) == 0 ); + Q_ASSERT(obj); + Q_ASSERT(obj->getObjID() == ObjectPersistence::OBJID); + ObjectPersistence::DataFields objectPersistence = ((ObjectPersistence *)obj)->getData(); + if(saveState == AWAITING_COMPLETED && objectPersistence.Operation == ObjectPersistence::OPERATION_ERROR) { + failureTimer.stop(); + objectPersistenceOperationFailed(); + } else if (saveState == AWAITING_COMPLETED && + objectPersistence.Operation == ObjectPersistence::OPERATION_COMPLETED) { + failureTimer.stop(); // Check right object saved UAVObject* savingObj = queue.head(); - Q_ASSERT( obj->getField("ObjectID")->getValue() == savingObj->getObjID() ); + if(objectPersistence.ObjectID != savingObj->getObjID() ) { + objectPersistenceOperationFailed(); + return; + } obj->disconnect(this); queue.dequeue(); // We can now remove the object, it's done. saveState = IDLE; - emit saveCompleted(obj->getField("ObjectID")->getValue().toInt(), true); + + emit saveCompleted(objectPersistence.ObjectID, true); saveNextObject(); } } +/** + * Helper function that makes sure FirmwareIAP is updated and then returns the data + */ +FirmwareIAPObj::DataFields UAVObjectUtilManager::getFirmwareIap() +{ + FirmwareIAPObj::DataFields dummy; + + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + Q_ASSERT(pm); + if (!pm) + return dummy; + UAVObjectManager *om = pm->getObject(); + Q_ASSERT(om); + if (!om) + return dummy; + + FirmwareIAPObj *firmwareIap = FirmwareIAPObj::GetInstance(om); + Q_ASSERT(firmwareIap); + if (!firmwareIap) + return dummy; + + // The code below will ask for the object update and wait for the updated to be received, + // or the timeout of the timer, set to 1 second. + QEventLoop loop; + connect(firmwareIap, SIGNAL(objectUpdated(UAVObject*)), &loop, SLOT(quit())); + QTimer::singleShot(1000, &loop, SLOT(quit())); // Create a timeout + firmwareIap->requestUpdate(); + loop.exec(); + + return firmwareIap->getData(); +} /** * Get the UAV Board model, for anyone interested. Return format is: @@ -225,25 +264,8 @@ void UAVObjectUtilManager::objectPersistenceUpdated(UAVObject * obj) */ int UAVObjectUtilManager::getBoardModel() { - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - if (!pm) - return 0; - UAVObjectManager *om = pm->getObject(); - if (!om) - return 0; - - UAVDataObject *obj = dynamic_cast(om->getObject(QString("FirmwareIAPObj"))); - // The code below will ask for the object update and wait for the updated to be received, - // or the timeout of the timer, set to 1 second. - QEventLoop loop; - connect(obj, SIGNAL(objectUpdated(UAVObject*)), &loop, SLOT(quit())); - QTimer::singleShot(1000, &loop, SLOT(quit())); // Create a timeout - obj->requestUpdate(); - loop.exec(); - - int boardType = (obj->getField("BoardType")->getValue().toInt()) << 8; - boardType += obj->getField("BoardRevision")->getValue().toInt(); - return boardType; + FirmwareIAPObj::DataFields firmwareIapData = getFirmwareIap(); + return (firmwareIapData.BoardType << 8) + firmwareIapData.BoardRevision; } /** @@ -252,54 +274,18 @@ int UAVObjectUtilManager::getBoardModel() QByteArray UAVObjectUtilManager::getBoardCPUSerial() { QByteArray cpuSerial; - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - if (!pm) - return 0; - UAVObjectManager *om = pm->getObject(); - if (!om) - return 0; + FirmwareIAPObj::DataFields firmwareIapData = getFirmwareIap(); - UAVDataObject *obj = dynamic_cast(om->getObject(QString("FirmwareIAPObj"))); - // The code below will ask for the object update and wait for the updated to be received, - // or the timeout of the timer, set to 1 second. - QEventLoop loop; - connect(obj, SIGNAL(objectUpdated(UAVObject*)), &loop, SLOT(quit())); - QTimer::singleShot(1000, &loop, SLOT(quit())); // Create a timeout - obj->requestUpdate(); - loop.exec(); + for (int i = 0; i < FirmwareIAPObj::CPUSERIAL_NUMELEM; i++) + cpuSerial.append(firmwareIapData.CPUSerial[i]); - UAVObjectField* cpuField = obj->getField("CPUSerial"); - for (uint i = 0; i < cpuField->getNumElements(); ++i) { - cpuSerial.append(cpuField->getValue(i).toUInt()); - } return cpuSerial; } quint32 UAVObjectUtilManager::getFirmwareCRC() { - quint32 fwCRC; - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - if (!pm) - return 0; - UAVObjectManager *om = pm->getObject(); - if (!om) - return 0; - - UAVDataObject *obj = dynamic_cast(om->getObject(QString("FirmwareIAPObj"))); - obj->getField("crc")->setValue(0); - obj->updated(); - // The code below will ask for the object update and wait for the updated to be received, - // or the timeout of the timer, set to 1 second. - QEventLoop loop; - connect(obj, SIGNAL(objectUpdated(UAVObject*)), &loop, SLOT(quit())); - QTimer::singleShot(1000, &loop, SLOT(quit())); // Create a timeout - obj->requestUpdate(); - loop.exec(); - - UAVObjectField* fwCRCField = obj->getField("crc"); - - fwCRC=(quint32)fwCRCField->getValue().toLongLong(); - return fwCRC; + FirmwareIAPObj::DataFields firmwareIapData = getFirmwareIap(); + return firmwareIapData.crc; } /** @@ -308,27 +294,11 @@ quint32 UAVObjectUtilManager::getFirmwareCRC() QByteArray UAVObjectUtilManager::getBoardDescription() { QByteArray ret; - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - if (!pm) - return 0; - UAVObjectManager *om = pm->getObject(); - if (!om) - return 0; + FirmwareIAPObj::DataFields firmwareIapData = getFirmwareIap(); - UAVDataObject *obj = dynamic_cast(om->getObject(QString("FirmwareIAPObj"))); - // The code below will ask for the object update and wait for the updated to be received, - // or the timeout of the timer, set to 1 second. - QEventLoop loop; - connect(obj, SIGNAL(objectUpdated(UAVObject*)), &loop, SLOT(quit())); - QTimer::singleShot(1000, &loop, SLOT(quit())); // Create a timeout - obj->requestUpdate(); - loop.exec(); + for (int i = 0; i < FirmwareIAPObj::DESCRIPTION_NUMELEM; i++) + ret.append(firmwareIapData.Description[i]); - UAVObjectField* descriptionField = obj->getField("Description"); - // Description starts with an offset of - for (uint i = 0; i < descriptionField->getNumElements(); ++i) { - ret.append(descriptionField->getValue(i).toInt()); - } return ret; } diff --git a/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutilmanager.h b/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutilmanager.h index 6c7782b25..6f71123b8 100644 --- a/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutilmanager.h +++ b/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutilmanager.h @@ -43,6 +43,8 @@ #include #include #include +#include + class UAVOBJECTUTIL_EXPORT UAVObjectUtilManager: public QObject { Q_OBJECT @@ -69,6 +71,8 @@ public: static bool descriptionToStructure(QByteArray desc,deviceDescriptorStruct * struc); UAVObjectManager* getObjectManager(); void saveObjectToSD(UAVObject *obj); +protected: + FirmwareIAPObj::DataFields getFirmwareIap(); signals: void saveCompleted(int objectID, bool status); diff --git a/ground/openpilotgcs/src/plugins/uavobjectwidgetutils/configtaskwidget.cpp b/ground/openpilotgcs/src/plugins/uavobjectwidgetutils/configtaskwidget.cpp index cceec4216..7fb8d70c7 100644 --- a/ground/openpilotgcs/src/plugins/uavobjectwidgetutils/configtaskwidget.cpp +++ b/ground/openpilotgcs/src/plugins/uavobjectwidgetutils/configtaskwidget.cpp @@ -32,7 +32,7 @@ /** * Constructor */ -ConfigTaskWidget::ConfigTaskWidget(QWidget *parent) : QWidget(parent),isConnected(false),smartsave(NULL),dirty(false),outOfLimitsStyle("background-color: rgb(255, 0, 0);"),timeOut(NULL) +ConfigTaskWidget::ConfigTaskWidget(QWidget *parent) : QWidget(parent),isConnected(false),smartsave(NULL),dirty(false),outOfLimitsStyle("background-color: rgb(255, 0, 0);"),timeOut(NULL),allowWidgetUpdates(true) { pm = ExtensionSystem::PluginManager::instance(); objManager = pm->getObject(); @@ -127,7 +127,7 @@ void ConfigTaskWidget::addUAVObjectToWidgetRelation(QString object, QString fiel Q_ASSERT(obj); objectUpdates.insert(obj,true); connect(obj, SIGNAL(objectUpdated(UAVObject*)),this, SLOT(objectUpdated(UAVObject*))); - connect(obj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(refreshWidgetsValues(UAVObject*))); + connect(obj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(refreshWidgetsValues(UAVObject*)), Qt::UniqueConnection); } if(!field.isEmpty() && obj) _field = obj->getField(QString(field)); @@ -258,6 +258,9 @@ void ConfigTaskWidget::populateWidgets() */ void ConfigTaskWidget::refreshWidgetsValues(UAVObject * obj) { + if (!allowWidgetUpdates) + return; + bool dirtyBack=dirty; emit refreshWidgetsValuesRequested(); foreach(objectToWidget * ow,objOfInterest) @@ -452,10 +455,10 @@ bool ConfigTaskWidget::isDirty() */ void ConfigTaskWidget::disableObjUpdates() { + allowWidgetUpdates = false; foreach(objectToWidget * obj,objOfInterest) { - if(obj->object) - disconnect(obj->object, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(refreshWidgetsValues())); + if(obj->object)disconnect(obj->object, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(refreshWidgetsValues(UAVObject*))); } } /** @@ -463,10 +466,11 @@ void ConfigTaskWidget::disableObjUpdates() */ void ConfigTaskWidget::enableObjUpdates() { + allowWidgetUpdates = true; foreach(objectToWidget * obj,objOfInterest) { if(obj->object) - connect(obj->object, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(refreshWidgetsValues(UAVObject*))); + connect(obj->object, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(refreshWidgetsValues(UAVObject*)), Qt::UniqueConnection); } } /** diff --git a/ground/openpilotgcs/src/plugins/uavobjectwidgetutils/configtaskwidget.h b/ground/openpilotgcs/src/plugins/uavobjectwidgetutils/configtaskwidget.h index 3099fa529..76d6b55bd 100644 --- a/ground/openpilotgcs/src/plugins/uavobjectwidgetutils/configtaskwidget.h +++ b/ground/openpilotgcs/src/plugins/uavobjectwidgetutils/configtaskwidget.h @@ -145,6 +145,7 @@ private slots: void reloadButtonClicked(); private: bool isConnected; + bool allowWidgetUpdates; QStringList objectsList; QList objOfInterest; ExtensionSystem::PluginManager *pm; diff --git a/ground/openpilotgcs/src/plugins/uploader/devicewidget.cpp b/ground/openpilotgcs/src/plugins/uploader/devicewidget.cpp index 0393d5534..e3ca707b3 100644 --- a/ground/openpilotgcs/src/plugins/uploader/devicewidget.cpp +++ b/ground/openpilotgcs/src/plugins/uploader/devicewidget.cpp @@ -78,27 +78,6 @@ void deviceWidget::setDfu(DFUObject *dfu) m_dfu = dfu; } -QString deviceWidget::idToBoardName(int id) -{ - switch (id | 0x0011) { - case 0x0111://MB - return QString("OpenPilot MainBoard"); - break; - case 0x0311://PipX - return QString("PipXtreme"); - break; - case 0x0411://Coptercontrol - return QString("CopterControl"); - break; - case 0x0211://INS - return QString("OpenPilot INS"); - break; - default: - return QString(""); - break; - } -} - /** Fills the various fields for the device */ @@ -125,6 +104,9 @@ void deviceWidget::populate() case 0x0401: devicePic->renderer()->load(QString(":/uploader/images/deviceID-0401.svg")); break; + case 0x0402: + devicePic->renderer()->load(QString(":/uploader/images/deviceID-0402.svg")); + break; case 0x0201: devicePic->renderer()->load(QString(":/uploader/images/deviceID-0201.svg")); break; @@ -200,7 +182,7 @@ bool deviceWidget::populateBoardStructuredDescription(QByteArray desc) myDevice->lblCertified->setToolTip(tr("Untagged or custom firmware build")); } - myDevice->lblBrdName->setText(idToBoardName(onBoardDescription.boardType<<8)); + myDevice->lblBrdName->setText(deviceDescriptorStruct::idToBoardName(onBoardDescription.boardType << 8 | onBoardDescription.boardRevision)); return true; } @@ -230,7 +212,7 @@ bool deviceWidget::populateLoadedStructuredDescription(QByteArray desc) myDevice->lblCertifiedL->setPixmap(pix); myDevice->lblCertifiedL->setToolTip(tr("Untagged or custom firmware build")); } - myDevice->lblBrdNameL->setText(deviceDescriptorStruct::idToBoardName(LoadedDescription.boardType<<8)); + myDevice->lblBrdNameL->setText(deviceDescriptorStruct::idToBoardName(LoadedDescription.boardType << 8 | LoadedDescription.boardRevision)); return true; } diff --git a/ground/openpilotgcs/src/plugins/uploader/devicewidget.h b/ground/openpilotgcs/src/plugins/uploader/devicewidget.h index 6415985df..202023d50 100644 --- a/ground/openpilotgcs/src/plugins/uploader/devicewidget.h +++ b/ground/openpilotgcs/src/plugins/uploader/devicewidget.h @@ -59,7 +59,6 @@ private: deviceDescriptorStruct onBoardDescription; deviceDescriptorStruct LoadedDescription; QByteArray loadedFW; - QString idToBoardName(int id); Ui_deviceWidget *myDevice; int deviceID; DFUObject *m_dfu; diff --git a/ground/openpilotgcs/src/plugins/uploader/images/deviceID-0402.svg b/ground/openpilotgcs/src/plugins/uploader/images/deviceID-0402.svg new file mode 100644 index 000000000..90121943d --- /dev/null +++ b/ground/openpilotgcs/src/plugins/uploader/images/deviceID-0402.svg @@ -0,0 +1,2389 @@ + + + +image/svg+xmlCC3D + \ No newline at end of file diff --git a/ground/openpilotgcs/src/plugins/uploader/uploader.qrc b/ground/openpilotgcs/src/plugins/uploader/uploader.qrc index 7d2677927..083eab94d 100644 --- a/ground/openpilotgcs/src/plugins/uploader/uploader.qrc +++ b/ground/openpilotgcs/src/plugins/uploader/uploader.qrc @@ -12,5 +12,6 @@ images/application-certificate.svg images/warning.svg images/error.svg + images/deviceID-0402.svg diff --git a/ground/openpilotgcs/src/plugins/welcome/qml/main.qml b/ground/openpilotgcs/src/plugins/welcome/qml/main.qml index 764ce36a5..a2362d3e2 100644 --- a/ground/openpilotgcs/src/plugins/welcome/qml/main.qml +++ b/ground/openpilotgcs/src/plugins/welcome/qml/main.qml @@ -51,37 +51,37 @@ Rectangle { WelcomePageButton { baseIconName: "flightdata" label: "Flight Data" - onClicked: welcomePlugin.openPage("Mode1") + onClicked: welcomePlugin.openPage("Flight data") } WelcomePageButton { baseIconName: "config" label: "Configuration" - onClicked: welcomePlugin.openPage("Mode2") + onClicked: welcomePlugin.openPage("Configuration") } WelcomePageButton { baseIconName: "planner" label: "Flight Planner" - onClicked: welcomePlugin.openPage("Mode3") + onClicked: welcomePlugin.openPage("Flight Planner") } WelcomePageButton { baseIconName: "scopes" label: "Scopes" - onClicked: welcomePlugin.openPage("Mode4") + onClicked: welcomePlugin.openPage("Scopes") } WelcomePageButton { baseIconName: "hitl" - label: "HIL" - onClicked: welcomePlugin.openPage("Mode5") + label: "HITL" + onClicked: welcomePlugin.openPage("HITL") } WelcomePageButton { baseIconName: "firmware" label: "Firmware" - onClicked: welcomePlugin.openPage("Mode6") + onClicked: welcomePlugin.openPage("Firmware") } } //icons grid } // images row diff --git a/ground/openpilotgcs/src/plugins/welcome/welcomemode.cpp b/ground/openpilotgcs/src/plugins/welcome/welcomemode.cpp index f08a58420..cf36b3036 100644 --- a/ground/openpilotgcs/src/plugins/welcome/welcomemode.cpp +++ b/ground/openpilotgcs/src/plugins/welcome/welcomemode.cpp @@ -124,7 +124,7 @@ void WelcomeMode::openUrl(const QString &url) void WelcomeMode::openPage(const QString &page) { - Core::ModeManager::instance()->activateMode(page); + Core::ModeManager::instance()->activateModeByWorkspaceName(page); } } // namespace Welcome diff --git a/overo b/overo index 8381aa124..335a3486d 160000 --- a/overo +++ b/overo @@ -1 +1 @@ -Subproject commit 8381aa124feafbb268c4d87d569a8185765f4297 +Subproject commit 335a3486dd41e48345209d0a65d49a8cc8b442a1 diff --git a/shared/uavobjectdefinition/gcsreceiver.xml b/shared/uavobjectdefinition/gcsreceiver.xml index 9e48e6381..cbc00c965 100644 --- a/shared/uavobjectdefinition/gcsreceiver.xml +++ b/shared/uavobjectdefinition/gcsreceiver.xml @@ -1,8 +1,8 @@ A receiver channel group carried over the telemetry link. - - + + diff --git a/shared/uavobjectdefinition/manualcontrolsettings.xml b/shared/uavobjectdefinition/manualcontrolsettings.xml index 8ed79dbd0..c2c8ec715 100644 --- a/shared/uavobjectdefinition/manualcontrolsettings.xml +++ b/shared/uavobjectdefinition/manualcontrolsettings.xml @@ -18,9 +18,9 @@ - - - + + + diff --git a/shared/uavobjectdefinition/objectpersistence.xml b/shared/uavobjectdefinition/objectpersistence.xml index afeb2ff24..2d73e07b3 100644 --- a/shared/uavobjectdefinition/objectpersistence.xml +++ b/shared/uavobjectdefinition/objectpersistence.xml @@ -1,7 +1,7 @@ Someone who knows please enter this - + diff --git a/shared/uavobjectdefinition/stabilizationdesired.xml b/shared/uavobjectdefinition/stabilizationdesired.xml index 21138c2e3..02c63cd90 100644 --- a/shared/uavobjectdefinition/stabilizationdesired.xml +++ b/shared/uavobjectdefinition/stabilizationdesired.xml @@ -6,7 +6,7 @@ - + diff --git a/shared/uavobjectdefinition/stabilizationsettings.xml b/shared/uavobjectdefinition/stabilizationsettings.xml index de1c92daa..7cd7de210 100644 --- a/shared/uavobjectdefinition/stabilizationsettings.xml +++ b/shared/uavobjectdefinition/stabilizationsettings.xml @@ -13,6 +13,15 @@ + + + + + + + + + diff --git a/shared/uavobjectdefinition/txpidsettings.xml b/shared/uavobjectdefinition/txpidsettings.xml index bdc05ba33..5b69063e8 100644 --- a/shared/uavobjectdefinition/txpidsettings.xml +++ b/shared/uavobjectdefinition/txpidsettings.xml @@ -16,7 +16,8 @@ Roll Rate.ILimit, Pitch Rate.ILimit, Roll+Pitch Rate.ILimit, Yaw Rate.ILimit, Roll Attitude.Kp, Pitch Attitude.Kp, Roll+Pitch Attitude.Kp, Yaw Attitude.Kp, Roll Attitude.Ki, Pitch Attitude.Ki, Roll+Pitch Attitude.Ki, Yaw Attitude.Ki, - Roll Attitude.ILimit, Pitch Attitude.ILimit, Roll+Pitch Attitude.ILimit, Yaw Attitude.ILimit" + Roll Attitude.ILimit, Pitch Attitude.ILimit, Roll+Pitch Attitude.ILimit, Yaw Attitude.ILimit, + GyroTau" defaultvalue="Disabled"/>