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 HwSettingsInitialize();
94 HwSettingsOptionalModulesData modules
;
95 HwSettingsOptionalModulesGet(&modules
);
96 if (modules
.CameraControl
== HWSETTINGS_OPTIONALMODULES_ENABLED
) {
97 ccd
= (struct CameraControl_data
*)pios_malloc(sizeof(struct CameraControl_data
));
98 memset(ccd
, 0, sizeof(struct CameraControl_data
));
99 ccd
->callbackHandle
= PIOS_CALLBACKSCHEDULER_Create(&CameraControlTask
, CALLBACK_PRIORITY
, CBTASK_PRIORITY
, CALLBACKINFO_RUNNING_CAMERACONTROL
, STACK_SIZE_BYTES
);
100 CameraControlActivityInitialize();
101 CameraDesiredInitialize();
102 CameraControlSettingsInitialize();
103 CameraControlSettingsConnectCallback(SettingsUpdateCb
);
104 HomeLocationInitialize();
105 HomeLocationConnectCallback(HomeLocationUpdateCb
);
107 PositionStateInitialize();
108 AttitudeStateInitialize();
109 AccessoryDesiredInitialize();
110 FlightStatusInitialize();
113 SettingsUpdateCb(NULL
);
114 HomeLocationUpdateCb(NULL
);
117 ccd
->outputStatus
= CAMERASTATUS_Idle
;
123 /* stub: module has no module thread */
124 int32_t CameraControlStart(void)
130 PIOS_CALLBACKSCHEDULER_Schedule(ccd
->callbackHandle
, CALLBACK_STD_PERIOD
, CALLBACK_UPDATEMODE_LATER
);
131 ccd
->lastTriggerTimeRaw
= PIOS_DELAY_GetRaw();
135 MODULE_INITCALL(CameraControlInitialize
, CameraControlStart
);
137 static void CameraControlTask()
139 bool trigger
= false;
140 PositionStateData pos
;
141 uint32_t timeSinceLastShot
= PIOS_DELAY_DiffuS(ccd
->lastTriggerTimeRaw
);
142 CameraStatus newStatus
;
144 if (checkActivation()) {
145 if (ccd
->manualInput
!= ccd
->lastManualInput
&& ccd
->manualInput
!= CAMERASTATUS_Idle
) {
148 newStatus
= ccd
->manualInput
;
149 ccd
->activity
.Reason
= CAMERACONTROLACTIVITY_REASON_MANUAL
;
151 // MinimumTimeInterval sets a hard limit on time between two consecutive shots, i.e. the minimum time between shots the camera can achieve
152 if (ccd
->autoTriggerEnabled
&&
153 timeSinceLastShot
> (ccd
->settings
.MinimumTimeInterval
* 1000 * 1000)) {
154 // check trigger conditions
155 if (ccd
->settings
.TimeInterval
> 0) {
156 if (timeSinceLastShot
> ccd
->settings
.TimeInterval
* (1000 * 1000)) {
158 newStatus
= CAMERASTATUS_Shot
;
159 ccd
->activity
.Reason
= CAMERACONTROLACTIVITY_REASON_AUTOTIME
;
163 if (ccd
->settings
.SpaceInterval
> 0) {
164 PositionStateGet(&pos
);
165 float dn
= pos
.North
- ccd
->lastTriggerNEDPosition
[0];
166 float de
= pos
.East
- ccd
->lastTriggerNEDPosition
[1];
167 float distance
= sqrtf((dn
* dn
) + (de
* de
));
168 ccd
->activity
.TriggerMillisecond
= (int16_t)distance
* 10.0f
;
169 if (distance
> ccd
->settings
.SpaceInterval
) {
171 newStatus
= CAMERASTATUS_Shot
;
172 ccd
->activity
.Reason
= CAMERACONTROLACTIVITY_REASON_AUTODISTANCE
;
179 ccd
->outputStatus
= newStatus
;
181 ccd
->lastTriggerTimeRaw
= PIOS_DELAY_GetRaw();
182 ccd
->lastTriggerNEDPosition
[0] = pos
.North
;
183 ccd
->lastTriggerNEDPosition
[1] = pos
.East
;
184 ccd
->lastTriggerNEDPosition
[2] = pos
.Down
;
186 ccd
->outputStatus
= CAMERASTATUS_Idle
;
187 ccd
->activity
.Activity
= CAMERACONTROLACTIVITY_ACTIVITY_IDLE
;
190 ccd
->lastManualInput
= ccd
->manualInput
;
193 PIOS_CALLBACKSCHEDULER_Schedule(ccd
->callbackHandle
, CALLBACK_STD_PERIOD
, CALLBACK_UPDATEMODE_SOONER
);
196 static void SettingsUpdateCb(__attribute__((unused
)) UAVObjEvent
*ev
)
198 CameraControlSettingsGet(&ccd
->settings
);
201 static bool checkActivation()
203 if (ccd
->settings
.ManualTriggerInput
!= CAMERACONTROLSETTINGS_MANUALTRIGGERINPUT_NONE
) {
204 uint8_t accessory
= ccd
->settings
.ManualTriggerInput
- CAMERACONTROLSETTINGS_MANUALTRIGGERINPUT_ACCESSORY0
;
206 AccessoryDesiredData accessoryDesired
;
207 AccessoryDesiredInstGet(accessory
, &accessoryDesired
);
209 if (fabsf(accessoryDesired
.AccessoryVal
- ccd
->settings
.InputValues
.Shot
) < INPUT_DEADBAND
) {
210 ccd
->manualInput
= CAMERASTATUS_Shot
;
211 } else if (fabsf(accessoryDesired
.AccessoryVal
- ccd
->settings
.InputValues
.Video
) < INPUT_DEADBAND
) {
212 ccd
->manualInput
= CAMERASTATUS_Video
;
214 ccd
->manualInput
= CAMERASTATUS_Idle
;
218 switch (ccd
->settings
.AutoTriggerMode
) {
219 case CAMERACONTROLSETTINGS_AUTOTRIGGERMODE_DISABLED
:
220 ccd
->autoTriggerEnabled
= false;
222 case CAMERACONTROLSETTINGS_AUTOTRIGGERMODE_WHENARMED
:
224 FlightStatusArmedOptions armed
;
226 FlightStatusArmedGet(&armed
);
227 ccd
->autoTriggerEnabled
= (armed
== FLIGHTSTATUS_ARMED_ARMED
);
230 case CAMERACONTROLSETTINGS_AUTOTRIGGERMODE_ALWAYS
:
231 ccd
->autoTriggerEnabled
= true;
233 case CAMERACONTROLSETTINGS_AUTOTRIGGERMODE_INPUT
:
235 uint8_t accessory
= ccd
->settings
.AutoTriggerInput
- CAMERACONTROLSETTINGS_AUTOTRIGGERINPUT_ACCESSORY0
;
236 AccessoryDesiredData accessoryDesired
;
237 AccessoryDesiredInstGet(accessory
, &accessoryDesired
);
239 ccd
->autoTriggerEnabled
= (accessoryDesired
.AccessoryVal
> INPUT_DEADBAND
);
242 case CAMERACONTROLSETTINGS_AUTOTRIGGERMODE_MISSION
:
244 FlightStatusFlightModeOptions flightmode
;
245 FlightStatusFlightModeGet(&flightmode
);
246 ccd
->autoTriggerEnabled
= (flightmode
== FLIGHTSTATUS_FLIGHTMODE_PATHPLANNER
);
250 return ccd
->autoTriggerEnabled
|| (ccd
->manualInput
!= CAMERASTATUS_Idle
);
253 static void UpdateOutput()
255 if (ccd
->outputStatus
!= ccd
->lastOutputStatus
) {
256 switch (ccd
->outputStatus
) {
257 case CAMERASTATUS_Idle
:
258 if (CAMERASTATUS_Shot
== ccd
->lastOutputStatus
) {
259 if (PIOS_DELAY_DiffuS(ccd
->lastTriggerTimeRaw
) > ccd
->settings
.TriggerPulseWidth
* 1000) {
260 CameraDesiredTriggerSet(&ccd
->settings
.OutputValues
.Idle
);
262 // skip updating lastOutputStatus until TriggerPulseWidth elapsed
267 case CAMERASTATUS_Shot
:
268 CameraDesiredTriggerSet(&ccd
->settings
.OutputValues
.Shot
);
270 case CAMERASTATUS_Video
:
271 CameraDesiredTriggerSet(&ccd
->settings
.OutputValues
.Video
);
275 ccd
->lastOutputStatus
= ccd
->outputStatus
;
278 static void PublishActivity()
280 if (ccd
->outputStatus
!= ccd
->lastOutputStatus
) {
281 switch (ccd
->outputStatus
) {
282 case CAMERASTATUS_Idle
:
283 if (ccd
->lastOutputStatus
== CAMERASTATUS_Video
) {
284 ccd
->activity
.Activity
= CAMERACONTROLACTIVITY_ACTIVITY_STOPVIDEO
;
286 ccd
->activity
.Activity
= CAMERACONTROLACTIVITY_ACTIVITY_IDLE
;
289 case CAMERASTATUS_Shot
:
290 ccd
->activity
.Activity
= CAMERACONTROLACTIVITY_ACTIVITY_TRIGGERPICTURE
;
292 case CAMERASTATUS_Video
:
293 if (ccd
->lastOutputStatus
!= CAMERASTATUS_Video
) {
294 ccd
->activity
.Activity
= CAMERACONTROLACTIVITY_ACTIVITY_STARTVIDEO
;
296 ccd
->activity
.Activity
= CAMERACONTROLACTIVITY_ACTIVITY_IDLE
;
300 if (ccd
->activity
.Activity
!= CAMERACONTROLACTIVITY_ACTIVITY_IDLE
301 || ccd
->lastOutputStatus
!= CAMERASTATUS_Shot
) {
303 CameraControlActivitySet(&ccd
->activity
);
308 static void FillActivityInfo()
310 CameraControlActivityData
*activity
= &ccd
->activity
;
312 PositionStateData position
;
313 PositionStateGet(&position
);
315 const float pos
[3] = {
320 Base2LLA(pos
, ccd
->HomeECEF
, ccd
->HomeRne
, LLAi
);
322 activity
->Latitude
= LLAi
[0];
323 activity
->Longitude
= LLAi
[1];
324 activity
->Altitude
= ((float)LLAi
[2]) * 1e-4f
;
330 activity
->TriggerYear
= time
.Year
;
331 activity
->TriggerMonth
= time
.Month
;
332 activity
->TriggerDay
= time
.Day
;
333 activity
->TriggerHour
= time
.Hour
;
334 activity
->TriggerMinute
= time
.Minute
;
335 activity
->TriggerSecond
= time
.Second
;
336 activity
->TriggerMillisecond
= time
.Millisecond
;
339 activity
->ImageId
= ccd
->ImageId
;
340 activity
->SystemTS
= xTaskGetTickCount() * portTICK_RATE_MS
;
342 AttitudeStateData attitude
;
343 AttitudeStateGet(&attitude
);
345 activity
->Roll
= attitude
.Roll
;
346 activity
->Pitch
= attitude
.Pitch
;
347 activity
->Yaw
= attitude
.Yaw
;
351 static void HomeLocationUpdateCb(__attribute__((unused
)) UAVObjEvent
*ev
)
353 HomeLocationData home
;
355 HomeLocationGet(&home
);
362 LLA2ECEF(LLAi
, ccd
->HomeECEF
);
363 RneFromLLA(LLAi
, ccd
->HomeRne
);