Files
ardupilot/libraries/SITL/SIM_QuadPlane.cpp
T
Thomas Watson 733ddb2b81 SITL: construct multicopter frame dynamically to save RAM
Only one ever exists so there's little reason to construct all
possibilities ahead of time and store them in global RAM. Instead, keep
a list of the parameters and only construct the one requested. Saves
some 60K of RAM on hardware when using sim on hardware.

In particular, enough is saved to get esp32empty copter building again.
But esp32 sim on hardware still does not work due to other regressions.
2025-12-29 17:33:14 +11:00

166 lines
5.0 KiB
C++

/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
simple quadplane simulator class
*/
#include "SIM_QuadPlane.h"
#include <stdio.h>
using namespace SITL;
QuadPlane::QuadPlane(const char *frame_str) :
Plane(frame_str)
{
// default to X frame
const char *frame_type = "x";
uint8_t motor_offset = 4;
ground_behavior = GROUND_BEHAVIOR_NO_MOVEMENT;
if (strstr(frame_str, "-octa-quad-cor")) {
frame_type = "octa-quad-cor";
} else if (strstr(frame_str, "-octa-quad-cw-cor")) {
frame_type = "octa-quad-cw-cor";
} else if (strstr(frame_str, "-octa-quad")) {
frame_type = "octa-quad";
} else if (strstr(frame_str, "-octaquad")) {
frame_type = "octa-quad";
} else if (strstr(frame_str, "-octa")) {
frame_type = "octa";
} else if (strstr(frame_str, "-hexax")) {
frame_type = "hexax";
} else if (strstr(frame_str, "-hexa")) {
frame_type = "hexa";
} else if (strstr(frame_str, "-plus")) {
frame_type = "+";
} else if (strstr(frame_str, "-y6")) {
frame_type = "y6";
} else if (strstr(frame_str, "-tri")) {
frame_type = "tri";
} else if (strstr(frame_str, "-tilttrivec")) {
frame_type = "tilttrivec";
// fwd motor gives zero thrust
thrust_scale = 0;
} else if (strstr(frame_str, "-tilthvec")) {
frame_type = "tilthvec";
} else if (strstr(frame_str, "-tilttri")) {
frame_type = "tilttri";
// fwd motor gives zero thrust
thrust_scale = 0;
} else if (strstr(frame_str, "firefly")) {
frame_type = "firefly";
// elevon style surfaces
elevons = true;
// fwd motor gives zero thrust
thrust_scale = 0;
// vtol motors start at 2
motor_offset = 2;
} else if (strstr(frame_str, "-tilt")) {
frame_type = "tilt";
// fwd motor gives zero thrust
thrust_scale = 0;
} else if (strstr(frame_str, "cl84")) {
frame_type = "tilttri";
// fwd motor gives zero thrust
thrust_scale = 0;
} else if (strstr(frame_str, "-copter_tailsitter")) {
frame_type = "+";
copter_tailsitter = true;
ground_behavior = GROUND_BEHAVIOR_TAILSITTER;
thrust_scale *= 1.5;
}
frame = Frame::create_frame(frame_type);
if (frame == nullptr) {
printf("Failed to find frame '%s' or insufficient memory\n", frame_type);
exit(1);
}
if (strstr(frame_str, "cl84")) {
// setup retract servos at front
frame->motors[0].servo_type = Motor::SERVO_RETRACT;
frame->motors[0].servo_rate = 7*60.0/90; // 7 seconds to change
frame->motors[1].servo_type = Motor::SERVO_RETRACT;
frame->motors[1].servo_rate = 7*60.0/90; // 7 seconds to change
}
// leave first 4 servos free for plane
frame->motor_offset = motor_offset;
// we use zero terminal velocity to let the plane model handle the drag
frame->init(frame_str, &battery);
// increase mass for plane components
mass = frame->get_mass() * 1.5;
frame->set_mass(mass);
lock_step_scheduled = true;
}
/*
update the quadplane simulation by one time step
*/
void QuadPlane::update(const struct sitl_input &input)
{
// get wind vector setup
update_wind(input);
// first plane forces
Vector3f rot_accel;
calculate_forces(input, rot_accel);
// now quad forces
Vector3f quad_rot_accel;
Vector3f quad_accel_body;
motor_mask |= ((1U<<frame->num_motors)-1U) << frame->motor_offset;
frame->calculate_forces(*this, input, quad_rot_accel, quad_accel_body, rpm, false);
// rotate frames for copter tailsitters
if (copter_tailsitter) {
quad_rot_accel.rotate(ROTATION_PITCH_270);
quad_accel_body.rotate(ROTATION_PITCH_270);
}
// estimate voltage and current
frame->current_and_voltage(battery_voltage, battery_current);
battery.set_current(battery_current);
float throttle;
if (reverse_thrust) {
throttle = filtered_servo_angle(input, 2);
} else {
throttle = filtered_servo_range(input, 2);
}
// assume 20A at full fwd throttle
throttle = fabsf(throttle);
battery_current += 20 * throttle;
rot_accel += quad_rot_accel;
accel_body += quad_accel_body;
update_dynamics(rot_accel);
update_external_payload(input);
// update lat/lon/altitude
update_position();
time_advance();
// update magnetic field
update_mag_field_bf();
}