LCOV - code coverage report
Current view: top level - AP_Mount - AP_Mount_Alexmos.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 137 0.0 %
Date: 2026-09-09 11:02:08 Functions: 0 13 0.0 %

          Line data    Source code
       1             : #include "AP_Mount_config.h"
       2             : 
       3             : #if HAL_MOUNT_ALEXMOS_ENABLED
       4             : 
       5             : #include "AP_Mount_Alexmos.h"
       6             : 
       7             : #include <AP_SerialManager/AP_SerialManager.h>
       8             : 
       9             : //definition of the commands id for the Alexmos Serial Protocol
      10             : #define CMD_READ_PARAMS 'R'
      11             : #define CMD_WRITE_PARAMS 'W'
      12             : #define CMD_REALTIME_DATA 'D'
      13             : #define CMD_BOARD_INFO 'V'
      14             : #define CMD_CALIB_ACC 'A'
      15             : #define CMD_CALIB_GYRO 'g'
      16             : #define CMD_CALIB_EXT_GAIN 'G'
      17             : #define CMD_USE_DEFAULTS 'F'
      18             : #define CMD_CALIB_POLES 'P'
      19             : #define CMD_RESET 'r'
      20             : #define CMD_HELPER_DATA 'H'
      21             : #define CMD_CALIB_OFFSET 'O'
      22             : #define CMD_CALIB_BAT 'B'
      23             : #define CMD_MOTORS_ON 'M'
      24             : #define CMD_MOTORS_OFF 'm'
      25             : #define CMD_CONTROL 'C'
      26             : #define CMD_TRIGGER_PIN 'T'
      27             : #define CMD_EXECUTE_MENU 'E'
      28             : #define CMD_GET_ANGLES 'I'
      29             : #define CMD_CONFIRM 'C'
      30             : // Board v3.x only
      31             : #define CMD_BOARD_INFO_3 20
      32             : #define CMD_READ_PARAMS_3 21
      33             : #define CMD_WRITE_PARAMS_3 22
      34             : #define CMD_REALTIME_DATA_3 23
      35             : #define CMD_SELECT_IMU_3 24
      36             : #define CMD_READ_PROFILE_NAMES 28
      37             : #define CMD_WRITE_PROFILE_NAMES 29
      38             : #define CMD_QUEUE_PARAMS_INFO_3 30
      39             : #define CMD_SET_PARAMS_3 31
      40             : #define CMD_SAVE_PARAMS_3 32
      41             : #define CMD_READ_PARAMS_EXT 33
      42             : #define CMD_WRITE_PARAMS_EXT 34
      43             : #define CMD_AUTO_PID 35
      44             : #define CMD_SERVO_OUT 36
      45             : #define CMD_ERROR 255
      46             : 
      47             : #define AP_MOUNT_ALEXMOS_MODE_NO_CONTROL 0
      48             : #define AP_MOUNT_ALEXMOS_MODE_SPEED 1
      49             : #define AP_MOUNT_ALEXMOS_MODE_ANGLE 2
      50             : #define AP_MOUNT_ALEXMOS_MODE_SPEED_ANGLE 3
      51             : #define AP_MOUNT_ALEXMOS_MODE_RC 4
      52             : 
      53             : #define AP_MOUNT_ALEXMOS_SPEED 30 // deg/s
      54             : 
      55             : #define INT14_DEGREES (360.0f / float(0x3FFF)) // 1 full rotation in degrees over 14 bit range
      56             : #define VALUE_TO_DEGREE(d) (float(d)*INT14_DEGREES)
      57             : #define DEGREE_TO_VALUE(d) ((int16_t)((float)(d)*(1.0f/INT14_DEGREES)))
      58             : #define DEGREE_PER_SEC_TO_VALUE(d) ((int16_t)((float)(d)*(1.0f/0.1220740379f)))
      59             : 
      60           0 : void AP_Mount_Alexmos::init()
      61             : {
      62           0 :     const AP_SerialManager& serial_manager = AP::serialmanager();
      63             : 
      64             :     // check for alexmos protcol
      65           0 :     if ((_port = serial_manager.find_serial(AP_SerialManager::SerialProtocol_AlexMos, 0))) {
      66           0 :         _initialised = true;
      67           0 :         get_boardinfo();
      68           0 :         read_params(0); //we request parameters for profile 0 and therfore get global and profile parameters
      69             :     }
      70           0 :     AP_Mount_Backend::init();
      71           0 : }
      72             : 
      73             : // update mount position - should be called periodically
      74           0 : void AP_Mount_Alexmos::update()
      75             : {
      76           0 :     AP_Mount_Backend::update();
      77             : 
      78           0 :     if (!_initialised) {
      79           0 :         return;
      80             :     }
      81             : 
      82           0 :     read_incoming(); // read the incoming messages from the gimbal
      83             : 
      84             :     // update based on mount mode
      85           0 :     update_mnt_target();
      86             : 
      87             :     // send target angles or rates depending on the target type
      88           0 :     send_target_to_gimbal();
      89             : }
      90             : 
      91             : // has_pan_control - returns true if this mount can control its pan (required for multicopters)
      92           0 : bool AP_Mount_Alexmos::has_pan_control() const
      93             : {
      94           0 :     return _gimbal_3axis && yaw_range_valid();
      95             : }
      96             : 
      97             : // get attitude as a quaternion.  returns true on success
      98           0 : bool AP_Mount_Alexmos::get_attitude_quaternion(Quaternion& att_quat)
      99             : {
     100           0 :     if (!_initialised) {
     101           0 :         return false;
     102             :     }
     103             : 
     104             :     // request attitude from gimbal
     105           0 :     get_angles();
     106             : 
     107             :     // construct quaternion
     108           0 :     att_quat.from_euler(radians(_current_angle.x), radians(_current_angle.y), radians(_current_angle.z));
     109           0 :     return true;
     110             : }
     111             : 
     112             : /*
     113             :  * get_angles
     114             :  */
     115           0 : void AP_Mount_Alexmos::get_angles()
     116             : {
     117           0 :     uint8_t data[1] = {(uint8_t)1};
     118           0 :     send_command(CMD_GET_ANGLES, data, 1);
     119           0 : }
     120             : 
     121             : /*
     122             :  * set_motor will activate motors if true, and disable them if false.
     123             :  */
     124           0 : void AP_Mount_Alexmos::set_motor(bool on)
     125             : {
     126           0 :     if (on) {
     127           0 :         uint8_t data[1] = {(uint8_t)1};
     128           0 :         send_command(CMD_MOTORS_ON, data, 1);
     129             :     } else {
     130           0 :         uint8_t data[1] = {(uint8_t)1};
     131           0 :         send_command(CMD_MOTORS_OFF, data, 1);
     132             :     }
     133           0 : }
     134             : 
     135             : /*
     136             :  * get board version and firmware version
     137             :  */
     138           0 : void AP_Mount_Alexmos::get_boardinfo()
     139             : {
     140           0 :     if (_board_version != 0) {
     141           0 :         return;
     142             :     }
     143           0 :     uint8_t data[1] = {(uint8_t)1};
     144           0 :     send_command(CMD_BOARD_INFO, data, 1);
     145             : }
     146             : 
     147             : /*
     148             :   control_axis : send new angle target to the gimbal at a fixed speed of 30 deg/s
     149             : */
     150           0 : void AP_Mount_Alexmos::send_target_angles(const MountAngleTarget& angle_target_rad)
     151             : {
     152             :     alexmos_parameters outgoing_buffer;
     153           0 :     outgoing_buffer.angle_speed.mode = AP_MOUNT_ALEXMOS_MODE_ANGLE;
     154           0 :     outgoing_buffer.angle_speed.speed_roll = DEGREE_PER_SEC_TO_VALUE(AP_MOUNT_ALEXMOS_SPEED);
     155           0 :     outgoing_buffer.angle_speed.angle_roll = DEGREE_TO_VALUE(degrees(angle_target_rad.roll));
     156           0 :     outgoing_buffer.angle_speed.speed_pitch = DEGREE_PER_SEC_TO_VALUE(AP_MOUNT_ALEXMOS_SPEED);
     157           0 :     outgoing_buffer.angle_speed.angle_pitch = DEGREE_TO_VALUE(degrees(angle_target_rad.pitch));
     158           0 :     outgoing_buffer.angle_speed.speed_yaw = DEGREE_PER_SEC_TO_VALUE(AP_MOUNT_ALEXMOS_SPEED);
     159           0 :     outgoing_buffer.angle_speed.angle_yaw = DEGREE_TO_VALUE(degrees(angle_target_rad.get_bf_yaw()));
     160           0 :     send_command(CMD_CONTROL, (uint8_t *)&outgoing_buffer.angle_speed, sizeof(alexmos_angles_speed));
     161           0 : }
     162             : 
     163             : /*
     164             :   read current profile profile_id and global parameters from the gimbal settings
     165             : */
     166           0 : void AP_Mount_Alexmos::read_params(uint8_t profile_id)
     167             : {
     168           0 :     uint8_t data[1] = {(uint8_t) profile_id}; 
     169           0 :     send_command(CMD_READ_PARAMS, data, 1);
     170           0 : }
     171             : 
     172             : /*
     173             :   write new parameters to the gimbal settings
     174             : */
     175           0 : void AP_Mount_Alexmos::write_params()
     176             : {
     177           0 :     if (!_param_read_once) {
     178           0 :         return;
     179             :     }
     180           0 :     send_command(CMD_WRITE_PARAMS, (uint8_t *)&_current_parameters.params, sizeof(alexmos_params));
     181             : }
     182             : 
     183             : /*
     184             :  send a command to the Alemox Serial API
     185             : */
     186           0 : void AP_Mount_Alexmos::send_command(uint8_t cmd, uint8_t* data, uint8_t size)
     187             : {
     188           0 :     if (_port->txspace() < (size + 5U)) {
     189           0 :         return;
     190             :     }
     191           0 :     uint8_t checksum = 0;
     192           0 :     _port->write( '>' );
     193           0 :     _port->write( cmd );  // write command id
     194           0 :     _port->write( size );  // write body size
     195           0 :     _port->write( cmd+size ); // write header checkum
     196             : 
     197           0 :     for (uint8_t i = 0;  i != size ; i++) {
     198           0 :         checksum += data[i];
     199           0 :         _port->write( data[i] );
     200             :     }
     201           0 :     _port->write(checksum);
     202             : }
     203             : 
     204             : /*
     205             :  * Parse the body of the message received from the Alexmos gimbal
     206             :  */
     207           0 : void AP_Mount_Alexmos::parse_body()
     208             : {
     209           0 :     switch (_command_id ) {
     210           0 :         case CMD_BOARD_INFO:
     211           0 :             _board_version = _buffer.version._board_version/ 10;
     212           0 :             _current_firmware_version = _buffer.version._firmware_version * 0.001f ;
     213           0 :             _firmware_beta_version = _buffer.version._firmware_version % 10 ;
     214           0 :             _gimbal_3axis = (_buffer.version._board_features & 0x1);
     215           0 :             _gimbal_bat_monitoring = (_buffer.version._board_features & 0x2);
     216           0 :             break;
     217             : 
     218           0 :         case CMD_GET_ANGLES:
     219           0 :             _current_angle.x = VALUE_TO_DEGREE(_buffer.angles.angle_roll);
     220           0 :             _current_angle.y = VALUE_TO_DEGREE(_buffer.angles.angle_pitch);
     221           0 :             _current_angle.z = VALUE_TO_DEGREE(_buffer.angles.angle_yaw);
     222           0 :             break;
     223             : 
     224           0 :         case CMD_READ_PARAMS:
     225           0 :             _param_read_once = true;
     226           0 :             _current_parameters.params = _buffer.params;
     227           0 :             break;
     228             : 
     229           0 :         case CMD_WRITE_PARAMS:
     230           0 :             break;
     231             : 
     232           0 :         default :
     233           0 :             _last_command_confirmed = true;
     234           0 :             break;
     235             :     }
     236           0 : }
     237             : 
     238             : /*
     239             :  * detect and read the header of the incoming message from the gimbal
     240             :  */
     241           0 : void AP_Mount_Alexmos::read_incoming()
     242             : {
     243             :     uint8_t data;
     244             :     int16_t numc;
     245             : 
     246           0 :     numc = _port->available();
     247             : 
     248           0 :     if (numc < 0 ) {
     249           0 :         return;
     250             :     }
     251             : 
     252           0 :     for (int16_t i = 0; i < numc; i++) {        // Process bytes received
     253           0 :         data = _port->read();
     254           0 :         switch (_step) {
     255           0 :             case 0:
     256           0 :                 if ( '>' == data) {
     257           0 :                     _step = 1;
     258           0 :                     _checksum = 0; //reset checksum accumulator
     259           0 :                     _last_command_confirmed = false;
     260             :                 }
     261           0 :                 break;
     262             : 
     263           0 :             case 1: // command ID
     264           0 :                 _checksum = data;
     265           0 :                 _command_id = data;
     266           0 :                 _step++;
     267           0 :                 break;
     268             : 
     269           0 :             case 2: // Size of the body of the message
     270           0 :                 _checksum += data;
     271           0 :                 _payload_length = data;
     272           0 :                 _step++;
     273           0 :                 break;
     274             : 
     275           0 :             case 3:     // checksum of the header
     276           0 :                 if (_checksum != data ) {
     277           0 :                     _step = 0;
     278           0 :                     _checksum = 0;
     279             :                     // checksum error
     280           0 :                     break;
     281             :                 }
     282           0 :                 _step++;
     283           0 :                 _checksum = 0;
     284           0 :                 _payload_counter = 0;                               // prepare to receive payload
     285           0 :                 break;
     286             : 
     287           0 :             case 4: // parsing body
     288           0 :                 _checksum += data;
     289           0 :                 if (_payload_counter < sizeof(_buffer)) {
     290           0 :                     _buffer[_payload_counter] = data;
     291             :                 }
     292           0 :                 if (++_payload_counter == _payload_length)
     293           0 :                     _step++;
     294           0 :                 break;
     295             : 
     296           0 :             case 5:// body checksum
     297           0 :                 _step = 0;
     298           0 :                 if (_checksum  != data) {
     299           0 :                     break;
     300             :                 }
     301           0 :                 parse_body();
     302             :         }
     303             :     }
     304             : }
     305             : #endif // HAL_MOUNT_ALEXMOS_ENABLED

Generated by: LCOV version 1.14