LCOV - code coverage report
Current view: top level - SITL - SIM_QuadPlane.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 90 102 88.2 %
Date: 2026-09-09 11:02:08 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /*
       2             :    This program is free software: you can redistribute it and/or modify
       3             :    it under the terms of the GNU General Public License as published by
       4             :    the Free Software Foundation, either version 3 of the License, or
       5             :    (at your option) any later version.
       6             : 
       7             :    This program is distributed in the hope that it will be useful,
       8             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
       9             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      10             :    GNU General Public License for more details.
      11             : 
      12             :    You should have received a copy of the GNU General Public License
      13             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      14             :  */
      15             : /*
      16             :   simple quadplane simulator class
      17             : */
      18             : 
      19             : #include "SIM_QuadPlane.h"
      20             : 
      21             : #include <stdio.h>
      22             : 
      23             : using namespace SITL;
      24             : 
      25         201 : QuadPlane::QuadPlane(const char *frame_str) :
      26         201 :     Plane(frame_str)
      27             : {
      28             :     // default to X frame
      29         201 :     const char *frame_type = "x";
      30         201 :     uint8_t motor_offset = 4;
      31             : 
      32         201 :     ground_behavior = GROUND_BEHAVIOR_NO_MOVEMENT;
      33             : 
      34         201 :     if (strstr(frame_str, "-octa-quad-cor")) {
      35           0 :         frame_type = "octa-quad-cor";
      36         201 :     } else if (strstr(frame_str, "-octa-quad-cw-cor")) {
      37           0 :         frame_type = "octa-quad-cw-cor";
      38         201 :     } else if (strstr(frame_str, "-octa-quad")) {
      39           0 :         frame_type = "octa-quad";
      40         201 :     } else if (strstr(frame_str, "-octaquad")) {
      41           0 :         frame_type = "octa-quad";
      42         201 :     } else if (strstr(frame_str, "-octa")) {
      43           0 :         frame_type = "octa";
      44         201 :     } else if (strstr(frame_str, "-hexax")) {
      45           0 :         frame_type = "hexax";
      46         201 :     } else if (strstr(frame_str, "-hexa")) {
      47           0 :         frame_type = "hexa";
      48         201 :     } else if (strstr(frame_str, "-plus")) {
      49           0 :         frame_type = "+";
      50         201 :     } else if (strstr(frame_str, "-y6")) {
      51           0 :         frame_type = "y6";
      52         201 :     } else if (strstr(frame_str, "-tri")) {
      53           3 :         frame_type = "tri";
      54         198 :     } else if (strstr(frame_str, "-tilttrivec")) {
      55           2 :         frame_type = "tilttrivec";
      56             :         // fwd motor gives zero thrust
      57           2 :         thrust_scale = 0;
      58         196 :     } else if (strstr(frame_str, "-tilthvec")) {
      59           3 :         frame_type = "tilthvec";
      60         193 :     } else if (strstr(frame_str, "-tilttri")) {
      61           2 :         frame_type = "tilttri";
      62             :         // fwd motor gives zero thrust
      63           2 :         thrust_scale = 0;
      64         191 :     } else if (strstr(frame_str, "firefly")) {
      65           2 :         frame_type = "firefly";
      66             :         // elevon style surfaces
      67           2 :         elevons = true;
      68             :         // fwd motor gives zero thrust
      69           2 :         thrust_scale = 0;
      70             :         // vtol motors start at 2
      71           2 :         motor_offset = 2;
      72         189 :     } else if (strstr(frame_str, "-tilt")) {
      73           2 :         frame_type = "tilt";
      74             :         // fwd motor gives zero thrust
      75           2 :         thrust_scale = 0;
      76         187 :     } else if (strstr(frame_str, "cl84")) {
      77           2 :         frame_type = "tilttri";
      78             :         // fwd motor gives zero thrust
      79           2 :         thrust_scale = 0;
      80         185 :     } else if (strstr(frame_str, "-copter_tailsitter")) {
      81           5 :         frame_type = "+";
      82           5 :         copter_tailsitter = true;
      83           5 :         ground_behavior = GROUND_BEHAVIOR_TAILSITTER;
      84           5 :         thrust_scale *= 1.5;
      85             :     }
      86         201 :     frame = Frame::create_frame(frame_type);
      87         201 :     if (frame == nullptr) {
      88           0 :         printf("Failed to find frame '%s' or insufficient memory\n", frame_type);
      89           0 :         exit(1);
      90             :     }
      91             : 
      92         201 :     if (strstr(frame_str, "cl84")) {
      93             :         // setup retract servos at front
      94           2 :         frame->motors[0].servo_type = Motor::SERVO_RETRACT;
      95           2 :         frame->motors[0].servo_rate = 7*60.0/90; // 7 seconds to change
      96           2 :         frame->motors[1].servo_type = Motor::SERVO_RETRACT;
      97           2 :         frame->motors[1].servo_rate = 7*60.0/90; // 7 seconds to change
      98             :     }
      99             :     
     100             :     // leave first 4 servos free for plane
     101         201 :     frame->motor_offset = motor_offset;
     102             : 
     103             :     // increase mass for plane components
     104         201 :     frame->set_mass_scale(1.5);
     105             : 
     106         201 :     frame->init(frame_str);
     107         402 :     battery.setup(frame->get_model_batt_capacity_ah(),
     108         201 :                   frame->get_model_batt_resistance_ohm(),
     109         201 :                   frame->get_model_batt_max_voltage(),
     110             :                   ambient_outside_temperature_degC());
     111             : 
     112         201 :     mass = frame->get_mass();
     113             : 
     114         201 :     lock_step_scheduled = true;
     115         201 : }
     116             : 
     117             : /*
     118             :   update the quadplane simulation by one time step
     119             :  */
     120    26485960 : void QuadPlane::update(const struct sitl_input &input)
     121             : {
     122             :     // refresh mass in case SIM_FRM_ parameters have changed
     123    26485960 :     mass = frame->get_mass();
     124             : 
     125             :     // get wind vector setup
     126    26485960 :     update_wind(input);
     127             : 
     128             :     // first plane forces
     129    26485960 :     Vector3f rot_accel;
     130    26485960 :     calculate_forces(input, rot_accel);
     131             : 
     132             :     // now quad forces
     133    26485960 :     Vector3f quad_rot_accel;
     134    26485960 :     Vector3f quad_accel_body;
     135             : 
     136    26485960 :     motor_mask |= ((1U<<frame->num_motors)-1U) << frame->motor_offset;
     137    26485960 :     frame->calculate_forces(*this, input, quad_rot_accel, quad_accel_body, rpm);
     138             : 
     139             :     // rotate frames for copter tailsitters
     140    26485960 :     if (copter_tailsitter) {
     141      541998 :         quad_rot_accel.rotate(ROTATION_PITCH_270);
     142      541998 :         quad_accel_body.rotate(ROTATION_PITCH_270);
     143             :     }
     144             : 
     145    26485960 :     if (frame->battery_changed()) {
     146             :         // battery model changed via SIM_FRM_ parameters
     147         402 :         battery.setup(frame->get_model_batt_capacity_ah(),
     148         201 :                       frame->get_model_batt_resistance_ohm(),
     149         201 :                       frame->get_model_batt_max_voltage(),
     150             :                       ambient_outside_temperature_degC());
     151             :     }
     152    26485960 :     battery.maybe_reset(sitl->batt_voltage, sitl->batt_capacity_ah, sitl->batt_resistance);
     153    26485960 :     battery_voltage = battery.get_voltage();
     154    26485960 :     battery_current = frame->get_current_amp();
     155    26485960 :     battery_temperature_degC = battery.get_temperature_degC();
     156             : 
     157    26485960 :     const uint64_t now_us = AP_HAL::micros64();
     158    26485960 :     battery.consume_energy(battery_current, now_us);
     159             : 
     160             :     float throttle;
     161    26485960 :     if (reverse_thrust) {
     162           0 :         throttle = filtered_servo_angle(input, 2);
     163             :     } else {
     164    26485960 :         throttle = filtered_servo_range(input, 2);
     165             :     }
     166             :     // assume 20A at full fwd throttle
     167    26485960 :     throttle = fabsf(throttle);
     168    26485960 :     battery_current += 20 * throttle;
     169             :     
     170    26485960 :     rot_accel += quad_rot_accel;
     171    26485960 :     accel_body += quad_accel_body;
     172             : 
     173    26485960 :     update_dynamics(rot_accel);
     174    26485960 :     update_external_payload(input);
     175             : 
     176             :     // update lat/lon/altitude
     177    26485960 :     update_position();
     178    26485960 :     time_advance();
     179             : 
     180             :     // update magnetic field
     181    26485960 :     update_mag_field_bf();
     182    26485960 : }

Generated by: LCOV version 1.14