2 ******************************************************************************
4 * @file cameracontrol.c
5 * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016.
6 * @brief camera control module. triggers cameras with multiple options
8 * @see The GNU Public License (GPL) Version 3
10 *****************************************************************************/
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 3 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 * Additional note on redistribution: The copyright and license notices above
27 * must be maintained in each individual source file that is a derivative work
28 * of this source file; otherwise redistribution is prohibited.
31 #include <openpilot.h>
32 #include "inc/cameracontrol.h"
33 #include <CoordinateConversions.h>
34 #include <cameradesired.h>
35 #include <cameracontrolsettings.h>
36 #include <cameracontrolactivity.h>
37 #include <accessorydesired.h>
38 #include <attitudestate.h>
39 #include <callbackinfo.h>
40 #include <flightstatus.h>
42 #include <homelocation.h>
43 #include <hwsettings.h>
44 #include <positionstate.h>
45 #include <velocitystate.h>
50 CAMERASTATUS_Idle
= 0,
55 static struct CameraControl_data
{
56 int32_t lastTriggerTimeRaw
;
57 float lastTriggerNEDPosition
[3];
58 CameraControlSettingsData settings
;
59 CameraControlActivityData activity
;
60 DelayedCallbackInfo
*callbackHandle
;
61 CameraStatus outputStatus
;
62 CameraStatus lastOutputStatus
;
63 CameraStatus manualInput
;
64 CameraStatus lastManualInput
;
65 bool autoTriggerEnabled
;
71 #define CALLBACK_PRIORITY CALLBACK_PRIORITY_REGULAR
72 #define CBTASK_PRIORITY CALLBACK_TASK_AUXILIARY
73 #define STACK_SIZE_BYTES 512
74 #define CALLBACK_STD_PERIOD 50
75 #define INPUT_DEADBAND 0.1f
77 static void CameraControlTask();
78 static void SettingsUpdateCb(__attribute__((unused
)) UAVObjEvent
*ev
);
79 static void HomeLocationUpdateCb(__attribute__((unused
)) UAVObjEvent
*ev
);
80 static void UpdateOutput();
81 static void PublishActivity();
82 static bool checkActivation();
83 static void FillActivityInfo();
87 * Initialise the module, called on startup
88 * \returns 0 on success or -1 if initialisation failed
90 int32_t CameraControlInitialize(void)
93 HwSettingsOptionalModulesData modules
;
94 HwSettingsOptionalModulesGet(&modules
);
95 if (modules
.CameraControl
== HWSETTINGS_OPTIONALMODULES_ENABLED
) {
96 ccd
= (struct CameraControl_data
*)pios_malloc(sizeof(struct CameraControl_data
));
97 memset(ccd
, 0, sizeof(struct CameraControl_data
));
98 ccd
->callbackHandle
= PIOS_CALLBACKSCHEDULER_Create(&CameraControlTask
, CALLBACK_PRIORITY
, CBTASK_PRIORITY
, CALLBACKINFO_RUNNING_CAMERACONTROL
, STACK_SIZE_BYTES
);
99 CameraControlActivityInitialize();
100 CameraDesiredInitialize();
101 CameraControlSettingsConnectCallback(SettingsUpdateCb
);
102 HomeLocationConnectCallback(HomeLocationUpdateCb
);
104 PositionStateInitialize();
105 AttitudeStateInitialize();
106 AccessoryDesiredInitialize();
107 FlightStatusInitialize();
110 SettingsUpdateCb(NULL
);
111 HomeLocationUpdateCb(NULL
);
114 ccd
->outputStatus
= CAMERASTATUS_Idle
;
120 /* stub: module has no module thread */
121 int32_t CameraControlStart(void)
127 PIOS_CALLBACKSCHEDULER_Schedule(ccd
->callbackHandle
, CALLBACK_STD_PERIOD
, CALLBACK_UPDATEMODE_LATER
);
128 ccd
->lastTriggerTimeRaw
= PIOS_DELAY_GetRaw();
132 MODULE_INITCALL(CameraControlInitialize
, CameraControlStart
);
134 static void CameraControlTask()
136 bool trigger
= false;
137 PositionStateData pos
;
138 uint32_t timeSinceLastShot
= PIOS_DELAY_DiffuS(ccd
->lastTriggerTimeRaw
);
139 CameraStatus newStatus
;
141 if (checkActivation()) {
142 if (ccd
->manualInput
!= ccd
->lastManualInput
&& ccd
->manualInput
!= CAMERASTATUS_Idle
) {
145 newStatus
= ccd
->manualInput
;
146 ccd
->activity
.Reason
= CAMERACONTROLACTIVITY_REASON_MANUAL
;
148 // MinimumTimeInterval sets a hard limit on time between two consecutive shots, i.e. the minimum time between shots the camera can achieve
149 if (ccd
->autoTriggerEnabled
&&
150 timeSinceLastShot
> (ccd
->settings
.MinimumTimeInterval
* 1000 * 1000)) {
151 // check trigger conditions
152 if (ccd
->settings
.TimeInterval
> 0) {
153 if (timeSinceLastShot
> ccd
->settings
.TimeInterval
* (1000 * 1000)) {
155 newStatus
= CAMERASTATUS_Shot
;
156 ccd
->activity
.Reason
= CAMERACONTROLACTIVITY_REASON_AUTOTIME
;
160 if (ccd
->settings
.SpaceInterval
> 0) {
161 PositionStateGet(&pos
);
162 float dn
= pos
.North
- ccd
->lastTriggerNEDPosition
[0];
163 float de
= pos
.East
- ccd
->lastTriggerNEDPosition
[1];
164 float distance
= sqrtf((dn
* dn
) + (de
* de
));
165 ccd
->activity
.TriggerMillisecond
= (int16_t)distance
* 10.0f
;
166 if (distance
> ccd
->settings
.SpaceInterval
) {
168 newStatus
= CAMERASTATUS_Shot
;
169 ccd
->activity
.Reason
= CAMERACONTROLACTIVITY_REASON_AUTODISTANCE
;
176 ccd
->outputStatus
= newStatus
;
178 ccd
->lastTriggerTimeRaw
= PIOS_DELAY_GetRaw();
179 ccd
->lastTriggerNEDPosition
[0] = pos
.North
;
180 ccd
->lastTriggerNEDPosition
[1] = pos
.East
;
181 ccd
->lastTriggerNEDPosition
[2] = pos
.Down
;
183 ccd
->outputStatus
= CAMERASTATUS_Idle
;
184 ccd
->activity
.Activity
= CAMERACONTROLACTIVITY_ACTIVITY_IDLE
;
187 ccd
->lastManualInput
= ccd
->manualInput
;
190 PIOS_CALLBACKSCHEDULER_Schedule(ccd
->callbackHandle
, CALLBACK_STD_PERIOD
, CALLBACK_UPDATEMODE_SOONER
);
193 static void SettingsUpdateCb(__attribute__((unused
)) UAVObjEvent
*ev
)
195 CameraControlSettingsGet(&ccd
->settings
);
198 static bool checkActivation()
200 if (ccd
->settings
.ManualTriggerInput
!= CAMERACONTROLSETTINGS_MANUALTRIGGERINPUT_NONE
) {
201 uint8_t accessory
= ccd
->settings
.ManualTriggerInput
- CAMERACONTROLSETTINGS_MANUALTRIGGERINPUT_ACCESSORY0
;
203 AccessoryDesiredData accessoryDesired
;
204 AccessoryDesiredInstGet(accessory
, &accessoryDesired
);
206 if (fabsf(accessoryDesired
.AccessoryVal
- ccd
->settings
.InputValues
.Shot
) < INPUT_DEADBAND
) {
207 ccd
->manualInput
= CAMERASTATUS_Shot
;
208 } else if (fabsf(accessoryDesired
.AccessoryVal
- ccd
->settings
.InputValues
.Video
) < INPUT_DEADBAND
) {
209 ccd
->manualInput
= CAMERASTATUS_Video
;
211 ccd
->manualInput
= CAMERASTATUS_Idle
;
215 switch (ccd
->settings
.AutoTriggerMode
) {
216 case CAMERACONTROLSETTINGS_AUTOTRIGGERMODE_DISABLED
:
217 ccd
->autoTriggerEnabled
= false;
219 case CAMERACONTROLSETTINGS_AUTOTRIGGERMODE_WHENARMED
:
221 FlightStatusArmedOptions armed
;
223 FlightStatusArmedGet(&armed
);
224 ccd
->autoTriggerEnabled
= (armed
== FLIGHTSTATUS_ARMED_ARMED
);
227 case CAMERACONTROLSETTINGS_AUTOTRIGGERMODE_ALWAYS
:
228 ccd
->autoTriggerEnabled
= true;
230 case CAMERACONTROLSETTINGS_AUTOTRIGGERMODE_INPUT
:
232 uint8_t accessory
= ccd
->settings
.AutoTriggerInput
- CAMERACONTROLSETTINGS_AUTOTRIGGERINPUT_ACCESSORY0
;
233 AccessoryDesiredData accessoryDesired
;
234 AccessoryDesiredInstGet(accessory
, &accessoryDesired
);
236 ccd
->autoTriggerEnabled
= (accessoryDesired
.AccessoryVal
> INPUT_DEADBAND
);
239 case CAMERACONTROLSETTINGS_AUTOTRIGGERMODE_MISSION
:
241 FlightStatusFlightModeOptions flightmode
;
242 FlightStatusFlightModeGet(&flightmode
);
243 ccd
->autoTriggerEnabled
= (flightmode
== FLIGHTSTATUS_FLIGHTMODE_PATHPLANNER
);
247 return ccd
->autoTriggerEnabled
|| (ccd
->manualInput
!= CAMERASTATUS_Idle
);
250 static void UpdateOutput()
252 if (ccd
->outputStatus
!= ccd
->lastOutputStatus
) {
253 switch (ccd
->outputStatus
) {
254 case CAMERASTATUS_Idle
:
255 if (CAMERASTATUS_Shot
== ccd
->lastOutputStatus
) {
256 if (PIOS_DELAY_DiffuS(ccd
->lastTriggerTimeRaw
) > ccd
->settings
.TriggerPulseWidth
* 1000) {
257 CameraDesiredTriggerSet(&ccd
->settings
.OutputValues
.Idle
);
259 // skip updating lastOutputStatus until TriggerPulseWidth elapsed
264 case CAMERASTATUS_Shot
:
265 CameraDesiredTriggerSet(&ccd
->settings
.OutputValues
.Shot
);
267 case CAMERASTATUS_Video
:
268 CameraDesiredTriggerSet(&ccd
->settings
.OutputValues
.Video
);
272 ccd
->lastOutputStatus
= ccd
->outputStatus
;
275 static void PublishActivity()
277 if (ccd
->outputStatus
!= ccd
->lastOutputStatus
) {
278 switch (ccd
->outputStatus
) {
279 case CAMERASTATUS_Idle
:
280 if (ccd
->lastOutputStatus
== CAMERASTATUS_Video
) {
281 ccd
->activity
.Activity
= CAMERACONTROLACTIVITY_ACTIVITY_STOPVIDEO
;
283 ccd
->activity
.Activity
= CAMERACONTROLACTIVITY_ACTIVITY_IDLE
;
286 case CAMERASTATUS_Shot
:
287 ccd
->activity
.Activity
= CAMERACONTROLACTIVITY_ACTIVITY_TRIGGERPICTURE
;
289 case CAMERASTATUS_Video
:
290 if (ccd
->lastOutputStatus
!= CAMERASTATUS_Video
) {
291 ccd
->activity
.Activity
= CAMERACONTROLACTIVITY_ACTIVITY_STARTVIDEO
;
293 ccd
->activity
.Activity
= CAMERACONTROLACTIVITY_ACTIVITY_IDLE
;
297 if (ccd
->activity
.Activity
!= CAMERACONTROLACTIVITY_ACTIVITY_IDLE
298 || ccd
->lastOutputStatus
!= CAMERASTATUS_Shot
) {
300 CameraControlActivitySet(&ccd
->activity
);
305 static void FillActivityInfo()
307 CameraControlActivityData
*activity
= &ccd
->activity
;
309 PositionStateData position
;
310 PositionStateGet(&position
);
312 const float pos
[3] = {
317 Base2LLA(pos
, ccd
->HomeECEF
, ccd
->HomeRne
, LLAi
);
319 activity
->Latitude
= LLAi
[0];
320 activity
->Longitude
= LLAi
[1];
321 activity
->Altitude
= ((float)LLAi
[2]) * 1e-4f
;
327 activity
->TriggerYear
= time
.Year
;
328 activity
->TriggerMonth
= time
.Month
;
329 activity
->TriggerDay
= time
.Day
;
330 activity
->TriggerHour
= time
.Hour
;
331 activity
->TriggerMinute
= time
.Minute
;
332 activity
->TriggerSecond
= time
.Second
;
333 activity
->TriggerMillisecond
= time
.Millisecond
;
336 activity
->ImageId
= ccd
->ImageId
;
337 activity
->SystemTS
= xTaskGetTickCount() * portTICK_RATE_MS
;
339 AttitudeStateData attitude
;
340 AttitudeStateGet(&attitude
);
342 activity
->Roll
= attitude
.Roll
;
343 activity
->Pitch
= attitude
.Pitch
;
344 activity
->Yaw
= attitude
.Yaw
;
348 static void HomeLocationUpdateCb(__attribute__((unused
)) UAVObjEvent
*ev
)
350 HomeLocationData home
;
352 HomeLocationGet(&home
);
359 LLA2ECEF(LLAi
, ccd
->HomeECEF
);
360 RneFromLLA(LLAi
, ccd
->HomeRne
);