2015-08-11 03:28:42 -03:00
# include "AP_Camera.h"
2019-06-27 04:23:37 -03:00
# include <AP_AHRS/AP_AHRS.h>
2015-08-11 03:28:42 -03:00
# include <AP_Relay/AP_Relay.h>
# include <AP_Math/AP_Math.h>
# include <RC_Channel/RC_Channel.h>
# include <AP_HAL/AP_HAL.h>
2019-02-11 01:11:17 -04:00
# include <GCS_MAVLink/GCS_MAVLink.h>
# include <GCS_MAVLink/GCS.h>
2019-04-04 07:46:40 -03:00
# include <SRV_Channel/SRV_Channel.h>
# include <AP_Logger/AP_Logger.h>
# include <AP_GPS/AP_GPS.h>
2020-02-09 01:47:52 -04:00
# include "AP_Camera_SoloGimbal.h"
2012-06-13 16:00:20 -03:00
// ------------------------------
# define CAM_DEBUG DISABLED
2015-10-25 14:03:46 -03:00
const AP_Param : : GroupInfo AP_Camera : : var_info [ ] = {
2012-08-17 03:09:29 -03:00
// @Param: TRIGG_TYPE
// @DisplayName: Camera shutter (trigger) type
// @Description: how to trigger the camera to take a picture
2020-02-09 01:47:52 -04:00
// @Values: 0:Servo,1:Relay, 2:GoPro in Solo Gimbal
2012-08-17 03:09:29 -03:00
// @User: Standard
2020-02-15 20:27:08 -04:00
AP_GROUPINFO ( " TRIGG_TYPE " , 0 , AP_Camera , _trigger_type , 0 ) ,
2012-12-06 04:46:09 -04:00
// @Param: DURATION
// @DisplayName: Duration that shutter is held open
// @Description: How long the shutter will be held open in 10ths of a second (i.e. enter 10 for 1second, 50 for 5seconds)
2017-05-02 10:42:29 -03:00
// @Units: ds
2012-12-06 04:46:09 -04:00
// @Range: 0 50
// @User: Standard
AP_GROUPINFO ( " DURATION " , 1 , AP_Camera , _trigger_duration , AP_CAMERA_TRIGGER_DEFAULT_DURATION ) ,
// @Param: SERVO_ON
// @DisplayName: Servo ON PWM value
2017-05-15 20:19:53 -03:00
// @Description: PWM value in microseconds to move servo to when shutter is activated
2017-05-02 10:42:29 -03:00
// @Units: PWM
2012-12-06 04:46:09 -04:00
// @Range: 1000 2000
// @User: Standard
AP_GROUPINFO ( " SERVO_ON " , 2 , AP_Camera , _servo_on_pwm , AP_CAMERA_SERVO_ON_PWM ) ,
// @Param: SERVO_OFF
// @DisplayName: Servo OFF PWM value
2017-05-15 20:19:53 -03:00
// @Description: PWM value in microseconds to move servo to when shutter is deactivated
2017-05-02 10:42:29 -03:00
// @Units: PWM
2012-12-06 04:46:09 -04:00
// @Range: 1000 2000
// @User: Standard
AP_GROUPINFO ( " SERVO_OFF " , 3 , AP_Camera , _servo_off_pwm , AP_CAMERA_SERVO_OFF_PWM ) ,
2013-06-24 09:39:50 -03:00
// @Param: TRIGG_DIST
// @DisplayName: Camera trigger distance
2013-10-14 20:09:39 -03:00
// @Description: Distance in meters between camera triggers. If this value is non-zero then the camera will trigger whenever the GPS position changes by this number of meters regardless of what mode the APM is in. Note that this parameter can also be set in an auto mission using the DO_SET_CAM_TRIGG_DIST command, allowing you to enable/disable the triggering of the camera during the flight.
2013-06-24 09:39:50 -03:00
// @User: Standard
2017-05-02 10:42:29 -03:00
// @Units: m
2013-06-24 09:39:50 -03:00
// @Range: 0 1000
AP_GROUPINFO ( " TRIGG_DIST " , 4 , AP_Camera , _trigg_dist , 0 ) ,
2015-09-05 00:44:07 -03:00
// @Param: RELAY_ON
// @DisplayName: Relay ON value
// @Description: This sets whether the relay goes high or low when it triggers. Note that you should also set RELAY_DEFAULT appropriately for your camera
// @Values: 0:Low,1:High
// @User: Standard
AP_GROUPINFO ( " RELAY_ON " , 5 , AP_Camera , _relay_on , 1 ) ,
2015-12-18 03:16:11 -04:00
// @Param: MIN_INTERVAL
// @DisplayName: Minimum time between photos
// @Description: Postpone shooting if previous picture was taken less than preset time(ms) ago.
// @User: Standard
2017-05-02 10:42:29 -03:00
// @Units: ms
2015-12-18 03:16:11 -04:00
// @Range: 0 10000
AP_GROUPINFO ( " MIN_INTERVAL " , 6 , AP_Camera , _min_interval , 0 ) ,
// @Param: MAX_ROLL
// @DisplayName: Maximum photo roll angle.
// @Description: Postpone shooting if roll is greater than limit. (0=Disable, will shoot regardless of roll).
// @User: Standard
2017-05-02 10:42:29 -03:00
// @Units: deg
2015-12-18 03:16:11 -04:00
// @Range: 0 180
AP_GROUPINFO ( " MAX_ROLL " , 7 , AP_Camera , _max_roll , 0 ) ,
2018-10-03 21:26:34 -03:00
2015-06-07 14:11:30 -03:00
// @Param: FEEDBACK_PIN
// @DisplayName: Camera feedback pin
2018-05-14 22:03:49 -03:00
// @Description: pin number to use for save accurate camera feedback messages. If set to -1 then don't use a pin flag for this, otherwise this is a pin number which if held high after a picture trigger order, will save camera messages when camera really takes a picture. A universal camera hot shoe is needed. The pin should be held high for at least 2 milliseconds for reliable trigger detection. See also the CAM_FEEDBACK_POL option.
// @Values: -1:Disabled,50:AUX1,51:AUX2,52:AUX3,53:AUX4,54:AUX5,55:AUX6
2015-06-07 14:11:30 -03:00
// @User: Standard
2018-06-19 05:19:53 -03:00
// @RebootRequired: True
2015-06-07 14:11:30 -03:00
AP_GROUPINFO ( " FEEDBACK_PIN " , 8 , AP_Camera , _feedback_pin , AP_CAMERA_FEEDBACK_DEFAULT_FEEDBACK_PIN ) ,
2015-12-18 03:16:11 -04:00
2016-01-20 17:33:17 -04:00
// @Param: FEEDBACK_POL
// @DisplayName: Camera feedback pin polarity
// @Description: Polarity for feedback pin. If this is 1 then the feedback pin should go high on trigger. If set to 0 then it should go low
// @Values: 0:TriggerLow,1:TriggerHigh
// @User: Standard
AP_GROUPINFO ( " FEEDBACK_POL " , 9 , AP_Camera , _feedback_polarity , 1 ) ,
2018-10-03 21:26:34 -03:00
2017-10-24 07:42:17 -03:00
// @Param: AUTO_ONLY
// @DisplayName: Distance-trigging in AUTO mode only
// @Description: When enabled, trigging by distance is done in AUTO mode only.
// @Values: 0:Always,1:Only when in AUTO
// @User: Standard
AP_GROUPINFO ( " AUTO_ONLY " , 10 , AP_Camera , _auto_mode_only , 0 ) ,
2018-10-03 21:26:34 -03:00
// @Param: TYPE
// @DisplayName: Type of camera (0: None, 1: BMMCC)
// @Description: Set the camera type that is being used, certain cameras have custom functions that need further configuration, this enables that.
// @Values: 0:Default,1:BMMCC
// @User: Standard
AP_GROUPINFO ( " TYPE " , 11 , AP_Camera , _type , 0 ) ,
2012-08-17 03:09:29 -03:00
AP_GROUPEND
2012-06-13 16:00:20 -03:00
} ;
2015-12-18 03:16:11 -04:00
extern const AP_HAL : : HAL & hal ;
2012-06-13 16:00:20 -03:00
2012-06-17 17:53:54 -03:00
/// Servo operated camera
2012-06-13 16:00:20 -03:00
void
2012-06-17 17:53:54 -03:00
AP_Camera : : servo_pic ( )
2012-06-13 16:00:20 -03:00
{
2018-10-03 21:26:34 -03:00
SRV_Channels : : set_output_pwm ( SRV_Channel : : k_cam_trigger , _servo_on_pwm ) ;
2012-12-06 04:46:09 -04:00
2018-10-03 21:26:34 -03:00
// leave a message that it should be active for this many loops (assumes 50hz loops)
_trigger_counter = constrain_int16 ( _trigger_duration * 5 , 0 , 255 ) ;
2012-06-13 16:00:20 -03:00
}
2012-06-17 17:53:54 -03:00
/// basic relay activation
2012-06-13 16:00:20 -03:00
void
2012-06-17 17:53:54 -03:00
AP_Camera : : relay_pic ( )
2012-06-13 16:00:20 -03:00
{
2019-06-27 04:23:37 -03:00
AP_Relay * _apm_relay = AP : : relay ( ) ;
if ( _apm_relay = = nullptr ) {
return ;
}
2015-09-05 00:44:07 -03:00
if ( _relay_on ) {
_apm_relay - > on ( 0 ) ;
} else {
_apm_relay - > off ( 0 ) ;
}
2012-12-06 04:46:09 -04:00
// leave a message that it should be active for this many loops (assumes 50hz loops)
2012-12-18 22:36:35 -04:00
_trigger_counter = constrain_int16 ( _trigger_duration * 5 , 0 , 255 ) ;
2012-06-13 16:00:20 -03:00
}
2012-06-17 17:53:54 -03:00
/// single entry point to take pictures
2017-07-26 01:32:40 -03:00
void AP_Camera : : trigger_pic ( )
2012-06-13 16:00:20 -03:00
{
2016-04-14 20:24:41 -03:00
setup_feedback_callback ( ) ;
2016-01-19 01:25:53 -04:00
2014-08-26 18:08:54 -03:00
_image_index + + ;
2020-02-15 20:27:08 -04:00
switch ( get_trigger_type ( ) ) {
case CamTrigType : : servo :
servo_pic ( ) ; // Servo operated camera
2012-08-17 03:09:29 -03:00
break ;
2020-02-15 20:27:08 -04:00
case CamTrigType : : relay :
relay_pic ( ) ; // basic relay activation
2012-08-17 03:09:29 -03:00
break ;
2020-02-15 20:27:08 -04:00
case CamTrigType : : gopro : // gopro in Solo Gimbal
2020-02-09 01:47:52 -04:00
AP_Camera_SoloGimbal : : gopro_shutter_toggle ( ) ;
break ;
2012-08-17 03:09:29 -03:00
}
2015-03-28 22:36:43 -03:00
2017-07-26 01:32:40 -03:00
log_picture ( ) ;
2012-06-13 16:00:20 -03:00
}
2012-06-17 17:53:54 -03:00
/// de-activate the trigger after some delay, but without using a delay() function
2012-12-06 04:46:09 -04:00
/// should be called at 50hz
2012-06-13 16:00:20 -03:00
void
AP_Camera : : trigger_pic_cleanup ( )
{
2012-12-06 04:46:09 -04:00
if ( _trigger_counter ) {
_trigger_counter - - ;
} else {
2020-02-15 20:27:08 -04:00
switch ( get_trigger_type ( ) ) {
case CamTrigType : : servo :
2018-10-03 21:26:34 -03:00
SRV_Channels : : set_output_pwm ( SRV_Channel : : k_cam_trigger , _servo_off_pwm ) ;
break ;
2020-02-15 20:27:08 -04:00
case CamTrigType : : relay : {
2019-06-27 04:23:37 -03:00
AP_Relay * _apm_relay = AP : : relay ( ) ;
if ( _apm_relay = = nullptr ) {
break ;
}
2018-10-03 21:26:34 -03:00
if ( _relay_on ) {
_apm_relay - > off ( 0 ) ;
} else {
_apm_relay - > on ( 0 ) ;
}
break ;
}
2020-02-15 20:27:08 -04:00
case CamTrigType : : gopro :
// nothing to do
break ;
2019-06-27 04:23:37 -03:00
}
2018-10-03 21:26:34 -03:00
}
if ( _trigger_counter_cam_function ) {
_trigger_counter_cam_function - - ;
} else {
switch ( _type ) {
case AP_Camera : : CAMERA_TYPE_BMMCC :
SRV_Channels : : set_output_pwm ( SRV_Channel : : k_cam_iso , _servo_off_pwm ) ;
break ;
2012-08-17 03:09:29 -03:00
}
}
2012-06-13 16:00:20 -03:00
}
2012-06-17 17:53:54 -03:00
2020-02-09 01:47:52 -04:00
void AP_Camera : : handle_message ( mavlink_channel_t chan , const mavlink_message_t & msg )
{
switch ( msg . msgid ) {
case MAVLINK_MSG_ID_DIGICAM_CONTROL :
control_msg ( msg ) ;
break ;
case MAVLINK_MSG_ID_GOPRO_HEARTBEAT :
// heartbeat from the Solo gimbal with a GoPro
2020-02-15 20:27:08 -04:00
if ( get_trigger_type ( ) = = CamTrigType : : gopro ) {
2020-02-09 01:47:52 -04:00
AP_Camera_SoloGimbal : : handle_gopro_heartbeat ( chan , msg ) ;
break ;
}
break ;
}
}
/// momentary switch to cycle camera modes
void AP_Camera : : cam_mode_toggle ( )
{
2020-02-15 20:27:08 -04:00
switch ( get_trigger_type ( ) ) {
case CamTrigType : : gopro :
2020-02-09 01:47:52 -04:00
AP_Camera_SoloGimbal : : gopro_capture_mode_toggle ( ) ;
break ;
default :
// no other cameras use this yet
break ;
}
}
2015-09-06 17:41:47 -03:00
/// decode deprecated MavLink message that controls camera.
2012-06-13 16:00:20 -03:00
void
2019-04-30 07:22:48 -03:00
AP_Camera : : control_msg ( const mavlink_message_t & msg )
2012-06-13 16:00:20 -03:00
{
2012-08-17 03:09:29 -03:00
__mavlink_digicam_control_t packet ;
2019-04-30 07:22:48 -03:00
mavlink_msg_digicam_control_decode ( & msg , & packet ) ;
2014-12-09 23:04:19 -04:00
2015-09-06 17:41:47 -03:00
control ( packet . session , packet . zoom_pos , packet . zoom_step , packet . focus_lock , packet . shot , packet . command_id ) ;
2012-06-13 16:00:20 -03:00
}
2015-09-06 17:41:47 -03:00
void AP_Camera : : configure ( float shooting_mode , float shutter_speed , float aperture , float ISO , float exposure_type , float cmd_id , float engine_cutoff_time )
2015-04-18 10:30:03 -03:00
{
2015-04-18 03:37:06 -03:00
// we cannot process the configure command so convert to mavlink message
// and send to all components in case they and process it
mavlink_command_long_t mav_cmd_long = { } ;
// convert mission command to mavlink command_long
2015-09-16 00:53:47 -03:00
mav_cmd_long . command = MAV_CMD_DO_DIGICAM_CONFIGURE ;
2015-09-06 17:41:47 -03:00
mav_cmd_long . param1 = shooting_mode ;
mav_cmd_long . param2 = shutter_speed ;
mav_cmd_long . param3 = aperture ;
mav_cmd_long . param4 = ISO ;
mav_cmd_long . param5 = exposure_type ;
mav_cmd_long . param6 = cmd_id ;
mav_cmd_long . param7 = engine_cutoff_time ;
2015-04-18 03:37:06 -03:00
// send to all components
2019-10-17 04:08:28 -03:00
GCS_MAVLINK : : send_to_components ( MAVLINK_MSG_ID_COMMAND_LONG , ( char * ) & mav_cmd_long , sizeof ( mav_cmd_long ) ) ;
2018-10-03 21:26:34 -03:00
if ( _type = = AP_Camera : : CAMERA_TYPE_BMMCC ) {
// Set a trigger for the additional functions that are flip controlled (so far just ISO and Record Start / Stop use this method, will add others if required)
_trigger_counter_cam_function = constrain_int16 ( _trigger_duration * 5 , 0 , 255 ) ;
// If the message contains non zero values then use them for the below functions
if ( ISO > 0 ) {
SRV_Channels : : set_output_pwm ( SRV_Channel : : k_cam_iso , _servo_on_pwm ) ;
}
if ( aperture > 0 ) {
SRV_Channels : : set_output_pwm ( SRV_Channel : : k_cam_aperture , ( int ) aperture ) ;
}
if ( shutter_speed > 0 ) {
SRV_Channels : : set_output_pwm ( SRV_Channel : : k_cam_shutter_speed , ( int ) shutter_speed ) ;
}
// Use the shooting mode PWM value for the BMMCC as the focus control - no need to modify or create a new MAVlink message type.
if ( shooting_mode > 0 ) {
SRV_Channels : : set_output_pwm ( SRV_Channel : : k_cam_focus , ( int ) shooting_mode ) ;
}
}
2015-04-18 10:30:03 -03:00
}
2017-07-25 23:45:20 -03:00
void AP_Camera : : control ( float session , float zoom_pos , float zoom_step , float focus_lock , float shooting_cmd , float cmd_id )
2015-04-18 10:30:03 -03:00
{
2015-04-18 10:43:23 -03:00
// take picture
2015-09-16 00:53:47 -03:00
if ( is_equal ( shooting_cmd , 1.0f ) ) {
2017-07-26 01:32:40 -03:00
trigger_pic ( ) ;
2015-09-06 17:41:47 -03:00
}
2015-04-18 10:43:23 -03:00
2015-04-18 03:37:06 -03:00
mavlink_command_long_t mav_cmd_long = { } ;
// convert command to mavlink command long
mav_cmd_long . command = MAV_CMD_DO_DIGICAM_CONTROL ;
2015-09-06 17:41:47 -03:00
mav_cmd_long . param1 = session ;
mav_cmd_long . param2 = zoom_pos ;
mav_cmd_long . param3 = zoom_step ;
mav_cmd_long . param4 = focus_lock ;
mav_cmd_long . param5 = shooting_cmd ;
mav_cmd_long . param6 = cmd_id ;
2015-04-18 03:37:06 -03:00
// send to all components
2019-10-17 04:08:28 -03:00
GCS_MAVLINK : : send_to_components ( MAVLINK_MSG_ID_COMMAND_LONG , ( char * ) & mav_cmd_long , sizeof ( mav_cmd_long ) ) ;
2015-04-18 10:30:03 -03:00
}
2012-06-13 16:00:20 -03:00
2014-10-31 02:40:27 -03:00
/*
Send camera feedback to the GCS
*/
2017-07-25 23:45:20 -03:00
void AP_Camera : : send_feedback ( mavlink_channel_t chan )
2014-10-31 02:40:27 -03:00
{
2019-06-27 04:23:37 -03:00
const AP_AHRS & ahrs = AP : : ahrs ( ) ;
2014-10-31 02:40:27 -03:00
float altitude , altitude_rel ;
2019-01-01 19:59:50 -04:00
if ( current_loc . relative_alt ) {
2014-10-31 02:40:27 -03:00
altitude = current_loc . alt + ahrs . get_home ( ) . alt ;
altitude_rel = current_loc . alt ;
} else {
altitude = current_loc . alt ;
altitude_rel = current_loc . alt - ahrs . get_home ( ) . alt ;
}
2017-11-12 20:30:58 -04:00
mavlink_msg_camera_feedback_send (
chan ,
AP : : gps ( ) . time_epoch_usec ( ) ,
2014-08-26 18:08:54 -03:00
0 , 0 , _image_index ,
2014-10-31 02:40:27 -03:00
current_loc . lat , current_loc . lng ,
2018-06-08 13:05:34 -03:00
altitude * 1e-2 f , altitude_rel * 1e-2 f ,
ahrs . roll_sensor * 1e-2 f , ahrs . pitch_sensor * 1e-2 f , ahrs . yaw_sensor * 1e-2 f ,
2018-05-14 22:03:49 -03:00
0.0f , CAMERA_FEEDBACK_PHOTO , _camera_trigger_logged ) ;
2014-10-31 02:40:27 -03:00
}
2017-07-25 23:45:20 -03:00
/* update; triggers by distance moved
2013-07-09 19:31:25 -03:00
*/
2017-07-25 23:45:20 -03:00
void AP_Camera : : update ( )
2013-06-24 09:39:50 -03:00
{
2017-11-12 20:30:58 -04:00
if ( AP : : gps ( ) . status ( ) < AP_GPS : : GPS_OK_FIX_3D ) {
2017-07-25 23:45:20 -03:00
return ;
}
2015-05-04 23:35:15 -03:00
if ( is_zero ( _trigg_dist ) ) {
2020-03-23 21:01:11 -03:00
_last_location . lat = 0 ;
_last_location . lng = 0 ;
2017-07-25 23:45:20 -03:00
return ;
2013-06-24 09:39:50 -03:00
}
if ( _last_location . lat = = 0 & & _last_location . lng = = 0 ) {
2017-07-25 23:45:20 -03:00
_last_location = current_loc ;
return ;
2013-06-24 09:39:50 -03:00
}
2017-07-25 23:45:20 -03:00
if ( _last_location . lat = = current_loc . lat & & _last_location . lng = = current_loc . lng ) {
// we haven't moved - this can happen as update() may
2013-06-24 09:39:50 -03:00
// be called without a new GPS fix
2017-07-25 23:45:20 -03:00
return ;
2013-06-24 09:39:50 -03:00
}
2015-12-18 03:16:11 -04:00
2019-02-24 20:16:19 -04:00
if ( current_loc . get_distance ( _last_location ) < _trigg_dist ) {
2017-07-25 23:45:20 -03:00
return ;
2013-06-24 09:39:50 -03:00
}
2015-12-18 03:16:11 -04:00
2019-06-27 04:23:37 -03:00
if ( _max_roll > 0 & & fabsf ( AP : : ahrs ( ) . roll_sensor * 1e-2 f ) > _max_roll ) {
2017-07-25 23:45:20 -03:00
return ;
2015-12-18 03:16:11 -04:00
}
2017-10-24 07:42:17 -03:00
if ( _is_in_auto_mode ! = true & & _auto_mode_only ! = 0 ) {
2018-10-03 21:26:34 -03:00
return ;
2017-10-24 07:42:17 -03:00
}
2015-12-18 03:16:11 -04:00
uint32_t tnow = AP_HAL : : millis ( ) ;
if ( tnow - _last_photo_time < ( unsigned ) _min_interval ) {
2017-07-25 23:45:20 -03:00
return ;
2015-12-18 03:16:11 -04:00
}
2017-07-25 23:45:20 -03:00
take_picture ( ) ;
_last_location = current_loc ;
_last_photo_time = tnow ;
2016-01-19 01:25:53 -04:00
}
/*
2018-05-14 22:03:49 -03:00
interrupt handler for interrupt based feedback trigger
*/
void AP_Camera : : feedback_pin_isr ( uint8_t pin , bool high , uint32_t timestamp_us )
{
_feedback_timestamp_us = timestamp_us ;
_camera_trigger_count + + ;
}
/*
check if feedback pin is high for timer based feedback trigger , when
attach_interrupt fails
2016-01-19 01:25:53 -04:00
*/
void AP_Camera : : feedback_pin_timer ( void )
{
2018-06-19 05:19:53 -03:00
uint8_t pin_state = hal . gpio - > read ( _feedback_pin ) ;
2016-01-20 17:33:17 -04:00
uint8_t trigger_polarity = _feedback_polarity = = 0 ? 0 : 1 ;
if ( pin_state = = trigger_polarity & &
_last_pin_state ! = trigger_polarity ) {
2018-05-14 22:03:49 -03:00
_feedback_timestamp_us = AP_HAL : : micros ( ) ;
_camera_trigger_count + + ;
2016-01-19 01:25:53 -04:00
}
2016-01-20 17:33:17 -04:00
_last_pin_state = pin_state ;
2016-01-19 01:25:53 -04:00
}
2016-04-14 20:24:41 -03:00
/*
setup a callback for a feedback pin . When on PX4 with the right FMU
mode we can use the microsecond timer .
*/
void AP_Camera : : setup_feedback_callback ( void )
{
2018-05-14 22:03:49 -03:00
if ( _feedback_pin < = 0 | | _timer_installed | | _isr_installed ) {
2016-04-14 20:24:41 -03:00
// invalid or already installed
return ;
}
2018-05-14 22:03:49 -03:00
// ensure we are in input mode
hal . gpio - > pinMode ( _feedback_pin , HAL_GPIO_INPUT ) ;
2016-04-14 20:24:41 -03:00
2018-05-14 22:03:49 -03:00
// enable pullup/pulldown
uint8_t trigger_polarity = _feedback_polarity = = 0 ? 0 : 1 ;
hal . gpio - > write ( _feedback_pin , ! trigger_polarity ) ;
2018-06-19 05:19:53 -03:00
2018-05-14 22:03:49 -03:00
if ( hal . gpio - > attach_interrupt ( _feedback_pin , FUNCTOR_BIND_MEMBER ( & AP_Camera : : feedback_pin_isr , void , uint8_t , bool , uint32_t ) ,
trigger_polarity ? AP_HAL : : GPIO : : INTERRUPT_RISING : AP_HAL : : GPIO : : INTERRUPT_FALLING ) ) {
_isr_installed = true ;
} else {
// install a 1kHz timer to check feedback pin
hal . scheduler - > register_timer_process ( FUNCTOR_BIND_MEMBER ( & AP_Camera : : feedback_pin_timer , void ) ) ;
2018-06-19 05:19:53 -03:00
2018-05-14 22:03:49 -03:00
_timer_installed = true ;
}
2016-04-14 20:24:41 -03:00
}
2017-07-25 23:45:20 -03:00
// log_picture - log picture taken and send feedback to GCS
void AP_Camera : : log_picture ( )
{
2020-01-25 10:05:20 -04:00
if ( ! using_feedback_pin ( ) ) {
gcs ( ) . send_message ( MSG_CAMERA_FEEDBACK ) ;
}
2019-02-11 04:18:13 -04:00
AP_Logger * logger = AP_Logger : : get_singleton ( ) ;
if ( logger = = nullptr ) {
2017-07-25 23:45:20 -03:00
return ;
}
2020-01-25 10:05:20 -04:00
if ( ! logger - > should_log ( log_camera_bit ) ) {
return ;
}
2017-07-25 23:45:20 -03:00
if ( ! using_feedback_pin ( ) ) {
2020-01-25 10:05:20 -04:00
logger - > Write_Camera ( current_loc ) ;
2017-07-25 23:45:20 -03:00
} else {
2020-01-25 10:05:20 -04:00
logger - > Write_Trigger ( current_loc ) ;
2017-07-25 23:45:20 -03:00
}
}
// take_picture - take a picture
void AP_Camera : : take_picture ( )
{
2017-07-26 01:32:40 -03:00
// take a local picture:
trigger_pic ( ) ;
// tell all of our components to take a picture:
2019-10-17 04:08:28 -03:00
mavlink_command_long_t cmd_msg { } ;
2017-07-26 01:32:40 -03:00
cmd_msg . command = MAV_CMD_DO_DIGICAM_CONTROL ;
cmd_msg . param5 = 1 ;
// forward to all components
2019-10-17 04:08:28 -03:00
GCS_MAVLINK : : send_to_components ( MAVLINK_MSG_ID_COMMAND_LONG , ( char * ) & cmd_msg , sizeof ( cmd_msg ) ) ;
2017-07-25 23:45:20 -03:00
}
/*
update camera trigger - 50 Hz
*/
void AP_Camera : : update_trigger ( )
{
trigger_pic_cleanup ( ) ;
2018-05-14 22:03:49 -03:00
if ( _camera_trigger_logged ! = _camera_trigger_count ) {
uint32_t timestamp32 = _feedback_timestamp_us ;
_camera_trigger_logged = _camera_trigger_count ;
2017-07-25 23:45:20 -03:00
gcs ( ) . send_message ( MSG_CAMERA_FEEDBACK ) ;
2019-02-11 04:18:13 -04:00
AP_Logger * logger = AP_Logger : : get_singleton ( ) ;
if ( logger ! = nullptr ) {
if ( logger - > should_log ( log_camera_bit ) ) {
2018-05-14 22:03:49 -03:00
uint32_t tdiff = AP_HAL : : micros ( ) - timestamp32 ;
uint64_t timestamp = AP_HAL : : micros64 ( ) ;
2019-06-27 04:23:37 -03:00
logger - > Write_Camera ( current_loc , timestamp - tdiff ) ;
2017-07-25 23:45:20 -03:00
}
}
}
}
2018-04-14 01:03:29 -03:00
2020-02-15 20:27:08 -04:00
AP_Camera : : CamTrigType AP_Camera : : get_trigger_type ( void )
{
uint8_t type = _trigger_type . get ( ) ;
switch ( ( CamTrigType ) type ) {
case CamTrigType : : servo :
case CamTrigType : : relay :
case CamTrigType : : gopro :
return ( CamTrigType ) type ;
default :
return CamTrigType : : servo ;
}
}
2018-04-14 01:03:29 -03:00
// singleton instance
AP_Camera * AP_Camera : : _singleton ;
namespace AP {
AP_Camera * camera ( )
{
return AP_Camera : : get_singleton ( ) ;
}
}