SITL: rearrange Grippers and Sprayers in SITL

This commit is contained in:
Pierre Kancir 2018-07-31 22:33:23 +10:00 committed by Peter Barker
parent 96c54550e5
commit 37f7cc4bcf
21 changed files with 295 additions and 168 deletions

View File

@ -84,7 +84,6 @@ Aircraft::Aircraft(const char *home_str, const char *frame_str) :
// allow for orientation settings, such as with tailsitters // allow for orientation settings, such as with tailsitters
enum ap_var_type ptype; enum ap_var_type ptype;
ahrs_orientation = (AP_Int8 *)AP_Param::find("AHRS_ORIENTATION", &ptype); ahrs_orientation = (AP_Int8 *)AP_Param::find("AHRS_ORIENTATION", &ptype);
terrain = reinterpret_cast<AP_Terrain *>(AP_Param::find_object("TERRAIN_")); terrain = reinterpret_cast<AP_Terrain *>(AP_Param::find_object("TERRAIN_"));
} }
@ -737,4 +736,24 @@ void Aircraft::extrapolate_sensors(float delta_time)
velocity_air_bf = dcm.transposed() * velocity_air_ef; velocity_air_bf = dcm.transposed() * velocity_air_ef;
} }
void Aircraft::update_external_payload(const struct sitl_input &input)
{
external_payload_mass = 0;
// update sprayer
if (sprayer && sprayer->is_enabled()) {
sprayer->update(input);
external_payload_mass += sprayer->payload_mass();
}
// update grippers
if (gripper && gripper->is_enabled()) {
gripper->set_alt(hagl());
gripper->update(input);
external_payload_mass += gripper->payload_mass();
}
if (gripper_epm && gripper_epm->is_enabled()) {
gripper_epm->update(input);
external_payload_mass += gripper_epm->payload_mass();
}
}

View File

@ -21,8 +21,11 @@
#include <AP_Math/AP_Math.h> #include <AP_Math/AP_Math.h>
#include "SITL.h" #include "SITL.h"
#include "SITL_Input.h"
#include <AP_Terrain/AP_Terrain.h> #include <AP_Terrain/AP_Terrain.h>
#include "SIM_Sprayer.h"
#include "SIM_Gripper_Servo.h"
#include "SIM_Gripper_EPM.h"
namespace SITL { namespace SITL {
@ -30,25 +33,9 @@ namespace SITL {
parent class for all simulator types parent class for all simulator types
*/ */
class Aircraft { class Aircraft {
friend class Gripper_Servo;
public: public:
Aircraft(const char *home_str, const char *frame_str); Aircraft(const char *home_str, const char *frame_str);
/*
structure passed in giving servo positions as PWM values in
microseconds
*/
struct sitl_input {
uint16_t servos[16];
struct {
float speed; // m/s
float direction; // degrees 0..360
float turbulence;
float dir_z; //degrees -90..90
} wind;
};
/* /*
set simulation speedup set simulation speedup
*/ */
@ -111,7 +98,7 @@ public:
return mag_bf; return mag_bf;
} }
virtual float gross_mass() const { return mass; } float gross_mass() const { return mass + external_payload_mass; }
const Location &get_location() const { return location; } const Location &get_location() const { return location; }
@ -121,6 +108,10 @@ public:
attitude.from_rotation_matrix(dcm); attitude.from_rotation_matrix(dcm);
} }
void set_sprayer(Sprayer *_sprayer) { sprayer = _sprayer; }
void set_gripper_servo(Gripper_Servo *_gripper) { gripper = _gripper; }
void set_gripper_epm(Gripper_EPM *_gripper_epm) { gripper_epm = _gripper_epm; }
protected: protected:
SITL *sitl; SITL *sitl;
Location home; Location home;
@ -129,26 +120,27 @@ protected:
float ground_level; float ground_level;
float home_yaw; float home_yaw;
float frame_height; float frame_height;
Matrix3f dcm; // rotation matrix, APM conventions, from body to earth Matrix3f dcm; // rotation matrix, APM conventions, from body to earth
Vector3f gyro; // rad/s Vector3f gyro; // rad/s
Vector3f gyro_prev; // rad/s Vector3f gyro_prev; // rad/s
Vector3f ang_accel; // rad/s/s Vector3f ang_accel; // rad/s/s
Vector3f velocity_ef; // m/s, earth frame Vector3f velocity_ef; // m/s, earth frame
Vector3f wind_ef; // m/s, earth frame Vector3f wind_ef; // m/s, earth frame
Vector3f velocity_air_ef; // velocity relative to airmass, earth frame Vector3f velocity_air_ef; // velocity relative to airmass, earth frame
Vector3f velocity_air_bf; // velocity relative to airmass, body frame Vector3f velocity_air_bf; // velocity relative to airmass, body frame
Vector3f position; // meters, NED from origin Vector3f position; // meters, NED from origin
float mass; // kg float mass; // kg
Vector3f accel_body; // m/s/s NED, body frame float external_payload_mass = 0.0f; // kg
float airspeed; // m/s, apparent airspeed Vector3f accel_body; // m/s/s NED, body frame
float airspeed_pitot; // m/s, apparent airspeed, as seen by fwd pitot tube float airspeed; // m/s, apparent airspeed
float airspeed_pitot; // m/s, apparent airspeed, as seen by fwd pitot tube
float battery_voltage = -1.0f; float battery_voltage = -1.0f;
float battery_current = 0.0f; float battery_current = 0.0f;
float rpm1 = 0; float rpm1 = 0;
float rpm2 = 0; float rpm2 = 0;
uint8_t rcin_chan_count = 0; uint8_t rcin_chan_count = 0;
float rcin[8]; float rcin[8];
float range = -1.0f; // rangefinder detection in m float range = -1.0f; // rangefinder detection in m
// Wind Turbulence simulated Data // Wind Turbulence simulated Data
float turbulence_azimuth = 0.0f; float turbulence_azimuth = 0.0f;
@ -175,7 +167,7 @@ protected:
// allow for AHRS_ORIENTATION // allow for AHRS_ORIENTATION
AP_Int8 *ahrs_orientation; AP_Int8 *ahrs_orientation;
enum { enum {
GROUND_BEHAVIOR_NONE = 0, GROUND_BEHAVIOR_NONE = 0,
GROUND_BEHAVIOR_NO_MOVEMENT, GROUND_BEHAVIOR_NO_MOVEMENT,
@ -234,7 +226,10 @@ protected:
// extrapolate sensors by a given delta time in seconds // extrapolate sensors by a given delta time in seconds
void extrapolate_sensors(float delta_time); void extrapolate_sensors(float delta_time);
// update external payload/sensor dynamic
void update_external_payload(const struct sitl_input &input);
private: private:
uint64_t last_time_us = 0; uint64_t last_time_us = 0;
uint32_t frame_counter = 0; uint32_t frame_counter = 0;
@ -253,6 +248,10 @@ private:
} smoothing; } smoothing;
LowPassFilterFloat servo_filter[4]; LowPassFilterFloat servo_filter[4];
Sprayer *sprayer;
Gripper_Servo *gripper;
Gripper_EPM *gripper_epm;
}; };
} // namespace SITL } // namespace SITL

View File

@ -30,7 +30,7 @@ SITL::Calibration::Calibration(const char *home_str, const char *frame_str)
mass = 1.5f; mass = 1.5f;
} }
void SITL::Calibration::update(const struct sitl_input& input) void SITL::Calibration::update(const struct sitl_input &input)
{ {
Vector3f rot_accel{0, 0, 0}; Vector3f rot_accel{0, 0, 0};
@ -54,7 +54,7 @@ void SITL::Calibration::update(const struct sitl_input& input)
update_mag_field_bf(); update_mag_field_bf();
} }
void SITL::Calibration::_stop_control(const struct sitl_input& input, void SITL::Calibration::_stop_control(const struct sitl_input &input,
Vector3f& rot_accel) Vector3f& rot_accel)
{ {
Vector3f desired_angvel{0, 0, 0}; Vector3f desired_angvel{0, 0, 0};
@ -65,7 +65,7 @@ void SITL::Calibration::_stop_control(const struct sitl_input& input,
rot_accel *= 0.002f; rot_accel *= 0.002f;
} }
void SITL::Calibration::_attitude_control(const struct sitl_input& input, void SITL::Calibration::_attitude_control(const struct sitl_input &input,
Vector3f& rot_accel) Vector3f& rot_accel)
{ {
float desired_roll = -M_PI + 2 * M_PI * (input.servos[5] - 1000) / 1000.f; float desired_roll = -M_PI + 2 * M_PI * (input.servos[5] - 1000) / 1000.f;
@ -103,7 +103,7 @@ void SITL::Calibration::_attitude_set(float desired_roll, float desired_pitch, f
rot_accel = error * (1.0f / dt); rot_accel = error * (1.0f / dt);
} }
void SITL::Calibration::_angular_velocity_control(const struct sitl_input& in, void SITL::Calibration::_angular_velocity_control(const struct sitl_input &in,
Vector3f& rot_accel) Vector3f& rot_accel)
{ {
Vector3f axis{(float)(in.servos[5] - 1500), Vector3f axis{(float)(in.servos[5] - 1500),

View File

@ -66,22 +66,22 @@ class Calibration : public Aircraft {
public: public:
Calibration(const char *home_str, const char *frame_str); Calibration(const char *home_str, const char *frame_str);
void update(const struct sitl_input& input); void update(const struct sitl_input &input);
static Aircraft *create(const char *home_str, const char *frame_str) { static Aircraft *create(const char *home_str, const char *frame_str) {
return new Calibration(home_str, frame_str); return new Calibration(home_str, frame_str);
} }
private: private:
void _stop_control(const struct sitl_input& input, Vector3f& rot_accel); void _stop_control(const struct sitl_input &input, Vector3f& rot_accel);
void _attitude_set(float desired_roll, float desired_pitch, float desired_yaw, void _attitude_set(float desired_roll, float desired_pitch, float desired_yaw,
Vector3f& rot_accel); Vector3f& rot_accel);
void _attitude_control(const struct sitl_input& input, void _attitude_control(const struct sitl_input &input,
Vector3f& rot_accel); Vector3f& rot_accel);
void _angular_velocity_control(const struct sitl_input& input, void _angular_velocity_control(const struct sitl_input &input,
Vector3f& rot_accel); Vector3f& rot_accel);
void _calibration_poses(Vector3f& rot_accel); void _calibration_poses(Vector3f& rot_accel);

View File

@ -202,7 +202,7 @@ Frame *Frame::find_frame(const char *name)
// calculate rotational and linear accelerations // calculate rotational and linear accelerations
void Frame::calculate_forces(const Aircraft &aircraft, void Frame::calculate_forces(const Aircraft &aircraft,
const Aircraft::sitl_input &input, const struct sitl_input &input,
Vector3f &rot_accel, Vector3f &rot_accel,
Vector3f &body_accel) Vector3f &body_accel)
{ {

View File

@ -48,7 +48,7 @@ public:
// calculate rotational and linear accelerations // calculate rotational and linear accelerations
void calculate_forces(const Aircraft &aircraft, void calculate_forces(const Aircraft &aircraft,
const Aircraft::sitl_input &input, const struct sitl_input &input,
Vector3f &rot_accel, Vector3f &body_accel); Vector3f &rot_accel, Vector3f &body_accel);
float terminal_velocity; float terminal_velocity;

View File

@ -17,42 +17,65 @@
*/ */
#include "SIM_Gripper_EPM.h" #include "SIM_Gripper_EPM.h"
#include "AP_HAL/AP_HAL.h"
#include <stdio.h> #include <stdio.h>
#include <AP_Common/AP_Common.h> #include <AP_Math/AP_Math.h>
using namespace SITL; using namespace SITL;
// table of user settable parameters
const AP_Param::GroupInfo Gripper_EPM::var_info[] = {
// @Param: ENABLE
// @DisplayName: Gripper servo Sim enable/disable
// @Description: Allows you to enable (1) or disable (0) the gripper servo simulation
// @Values: 0:Disabled,1:Enabled
// @User: Advanced
AP_GROUPINFO("ENABLE", 0, Gripper_EPM, gripper_emp_enable, 0),
// @Param: PIN
// @DisplayName: Gripper emp pin
// @Description: The pin number that the gripper emp is connected to. (start at 1)
// @Range: 0 15
// @User: Advanced
AP_GROUPINFO("PIN", 1, Gripper_EPM, gripper_emp_servo_pin, -1),
AP_GROUPEND
};
/* /*
update gripper state update gripper state
*/ */
void Gripper_EPM::update_servobased(const Aircraft::sitl_input &input) void Gripper_EPM::update_servobased(int16_t gripper_pwm)
{ {
if (! servo_based) { if (!servo_based) {
return; return;
} }
demand = (input.servos[gripper_servo]-1000) * 0.001f; // 0.0 - 1.0 if (gripper_pwm >= 0) {
if (demand < 0) { // never updated demand = (gripper_pwm - 1000) * 0.001f; // 0.0 - 1.0
demand = 0; if (is_negative(demand)) { // never updated
demand = 0.0f;
}
} }
} }
void Gripper_EPM::update_from_demand(const Aircraft::sitl_input &input) void Gripper_EPM::update_from_demand()
{ {
const uint64_t now = AP_HAL::micros64(); const uint64_t now = AP_HAL::micros64();
const float dt = (now - last_update_us) * 1.0e-6f; const float dt = (now - last_update_us) * 1.0e-6f;
// decay the field // decay the field
field_strength = field_strength * (100-field_decay_rate * dt)/100.0f; field_strength = field_strength * (100.0f - field_decay_rate * dt) / 100.0f;
// note that "demand" here is just an on/off switch; we only care // note that "demand" here is just an on/off switch; we only care
// about which range it falls into // about which range it falls into
if (demand > 0.6) { if (demand > 0.6f) {
// we are instructed to grip harder // we are instructed to grip harder
field_strength = field_strength + (100.0f-field_strength) * field_strength_slew_rate/100.0f * dt; field_strength = field_strength + (100.0f - field_strength) * field_strength_slew_rate / 100.0f * dt;
} else if (demand < 0.4) { } else if (demand < 0.4f) {
// we are instructed to loosen grip // we are instructed to loosen grip
field_strength = field_strength * (100-field_degauss_rate * dt)/100.0f; field_strength = field_strength * (100.0f - field_degauss_rate * dt) / 100.0f;
} else { } else {
// neutral; no demanded change // neutral; no demanded change
} }
@ -66,14 +89,15 @@ void Gripper_EPM::update_from_demand(const Aircraft::sitl_input &input)
} }
last_update_us = now; last_update_us = now;
return;
} }
void Gripper_EPM::update(const Aircraft::sitl_input &input) void Gripper_EPM::update(const struct sitl_input &input)
{ {
update_servobased(input); const int16_t gripper_pwm = gripper_emp_servo_pin >= 1 ? input.servos[gripper_emp_servo_pin-1] : -1;
update_from_demand(input); update_servobased(gripper_pwm);
update_from_demand();
} }
@ -83,7 +107,7 @@ bool Gripper_EPM::should_report()
return false; return false;
} }
if (fabs(reported_field_strength - field_strength) > 10.0f) { if (abs(reported_field_strength - field_strength) > 10.0) {
return true; return true;
} }
@ -94,6 +118,6 @@ float Gripper_EPM::tesla()
{ {
// https://en.wikipedia.org/wiki/Orders_of_magnitude_(magnetic_field) // https://en.wikipedia.org/wiki/Orders_of_magnitude_(magnetic_field)
// 200N lifting capacity ~= 2.5T // 200N lifting capacity ~= 2.5T
const float percentage_to_tesla = 0.25; const float percentage_to_tesla = 0.25f;
return percentage_to_tesla * field_strength/100.0f; return static_cast<float>(percentage_to_tesla * field_strength / 100.0f);
} }

View File

@ -18,23 +18,31 @@
#pragma once #pragma once
#include "SIM_Aircraft.h" #include "stdint.h"
#include <AP_Param/AP_Param.h>
#include "SITL_Input.h"
namespace SITL { namespace SITL {
class Gripper_EPM { class Gripper_EPM {
public: public:
const uint8_t gripper_servo; Gripper_EPM() {
AP_Param::setup_object_defaults(this, var_info);
};
Gripper_EPM(const uint8_t _gripper_servo) : float payload_mass() const { return 0.0f; } // kg
gripper_servo(_gripper_servo)
{}
// update field stength // update field stength
void update(const struct Aircraft::sitl_input &input); void update(const struct sitl_input &input);
static const struct AP_Param::GroupInfo var_info[];
bool is_enabled() const {return static_cast<bool>(gripper_emp_enable);}
private: private:
AP_Int8 gripper_emp_enable; // enable gripper sim
AP_Int8 gripper_emp_servo_pin;
const uint32_t report_interval = 100000; // microseconds const uint32_t report_interval = 100000; // microseconds
uint64_t last_report_us; uint64_t last_report_us;
@ -52,8 +60,8 @@ private:
bool should_report(); bool should_report();
void update_from_demand(const Aircraft::sitl_input &input); void update_from_demand();
void update_servobased(const struct Aircraft::sitl_input &input); void update_servobased(int16_t gripper_pwm);
float tesla(); float tesla();

View File

@ -17,29 +17,57 @@
*/ */
#include "SIM_Gripper_Servo.h" #include "SIM_Gripper_Servo.h"
#include "AP_HAL/AP_HAL.h"
#include "AP_Math/AP_Math.h"
#include <stdio.h> #include <stdio.h>
using namespace SITL; using namespace SITL;
// table of user settable parameters
const AP_Param::GroupInfo Gripper_Servo::var_info[] = {
// @Param: ENABLE
// @DisplayName: Gripper servo Sim enable/disable
// @Description: Allows you to enable (1) or disable (0) the gripper servo simulation
// @Values: 0:Disabled,1:Enabled
// @User: Advanced
AP_GROUPINFO("ENABLE", 0, Gripper_Servo, gripper_enable, 0),
// @Param: PIN
// @DisplayName: Gripper servo pin
// @Description: The pin number that the gripper servo is connected to. (start at 1)
// @Range: 0 15
// @User: Advanced
AP_GROUPINFO("PIN", 1, Gripper_Servo, gripper_servo_pin, -1),
AP_GROUPEND
};
/* /*
update gripper state update gripper state
*/ */
void Gripper_Servo::update(const Aircraft::sitl_input &input) void Gripper_Servo::update(const struct sitl_input &input)
{ {
const int16_t gripper_pwm = gripper_servo_pin >= 1 ? input.servos[gripper_servo_pin-1] : -1;
const uint64_t now = AP_HAL::micros64(); const uint64_t now = AP_HAL::micros64();
const float dt = (now - last_update_us) * 1.0e-6f; const float dt = (now - last_update_us) * 1.0e-6f;
// update gripper position // update gripper position
if (gripper_pwm < 0) {
float position_demand = (input.servos[gripper_servo]-1000) * 0.001f; last_update_us = now;
if (position_demand < 0) { // never updated return;
position_demand = 0;
} }
const float position_max_change = position_slew_rate/100.0f * dt; float position_demand = (gripper_pwm - 1000) * 0.001f;
position = constrain_float(position_demand, position-position_max_change, position+position_max_change); if (is_negative(position_demand)) { // never updated
position_demand = 0.0f;
}
const float jaw_gap = gap*(1.0f-position); const float position_max_change = position_slew_rate / 100.0f * dt;
position = constrain_float(position_demand, position - position_max_change, position + position_max_change);
const float jaw_gap = gap * (1.0f - position);
if (should_report()) { if (should_report()) {
::fprintf(stderr, "position_demand=%f jaw_gap=%f load=%f\n", position_demand, jaw_gap, load_mass); ::fprintf(stderr, "position_demand=%f jaw_gap=%f load=%f\n", position_demand, jaw_gap, load_mass);
last_report_us = now; last_report_us = now;
@ -47,7 +75,7 @@ void Gripper_Servo::update(const Aircraft::sitl_input &input)
} }
if (jaw_gap < 5) { if (jaw_gap < 5) {
if (aircraft->on_ground()) { if (altitude <= 0.0f) {
load_mass = 1.0f; // attach the load load_mass = 1.0f; // attach the load
} }
} else if (jaw_gap > 10) { } else if (jaw_gap > 10) {
@ -55,7 +83,6 @@ void Gripper_Servo::update(const Aircraft::sitl_input &input)
} }
last_update_us = now; last_update_us = now;
return;
} }
bool Gripper_Servo::should_report() bool Gripper_Servo::should_report()
@ -74,7 +101,7 @@ bool Gripper_Servo::should_report()
float Gripper_Servo::payload_mass() const float Gripper_Servo::payload_mass() const
{ {
if (aircraft->hagl() < string_length) { if (altitude < string_length) {
return 0.0f; return 0.0f;
} }
return load_mass; return load_mass;

View File

@ -17,35 +17,35 @@
*/ */
#pragma once #pragma once
#include "stdint.h"
#include "SIM_Aircraft.h" #include <AP_Param/AP_Param.h>
#include "SITL_Input.h"
namespace SITL { namespace SITL {
class Gripper_Servo { class Gripper_Servo {
public: public:
const uint8_t gripper_servo; Gripper_Servo() {
AP_Param::setup_object_defaults(this, var_info);
Gripper_Servo(const uint8_t _gripper_servo) : };
gripper_servo(_gripper_servo)
{}
// update Gripper state // update Gripper state
void update(const struct Aircraft::sitl_input &input); void update(const struct sitl_input &input);
float payload_mass() const; // kg float payload_mass() const; // kg
void set_aircraft(Aircraft *_aircraft) { aircraft = _aircraft; } void set_alt(float alt) {altitude = alt;};
static const struct AP_Param::GroupInfo var_info[];
bool is_enabled() const {return static_cast<bool>(gripper_enable);}
private: private:
AP_Int8 gripper_enable; // enable gripper sim
Aircraft *aircraft; AP_Int8 gripper_servo_pin;
const uint32_t report_interval = 1000000; // microseconds const uint32_t report_interval = 1000000; // microseconds
uint64_t last_report_us; uint64_t last_report_us;
const float gap = 30; // mm const float gap = 30; // mm
float altitude;
float position; // percentage float position; // percentage
float position_slew_rate = 35; // percentage float position_slew_rate = 35; // percentage
float reported_position = -1; // unlikely float reported_position = -1; // unlikely

View File

@ -24,7 +24,7 @@ using namespace SITL;
/* /*
update engine state, returning power output from 0 to 1 update engine state, returning power output from 0 to 1
*/ */
float ICEngine::update(const Aircraft::sitl_input &input) float ICEngine::update(const struct sitl_input &input)
{ {
bool have_ignition = ignition_servo>=0; bool have_ignition = ignition_servo>=0;
bool have_choke = choke_servo>=0; bool have_choke = choke_servo>=0;

View File

@ -39,7 +39,7 @@ public:
{} {}
// update motor state // update motor state
float update(const struct Aircraft::sitl_input &input); float update(const struct sitl_input &input);
private: private:
float last_output; float last_output;

View File

@ -22,7 +22,7 @@
using namespace SITL; using namespace SITL;
// calculate rotational accel and thrust for a motor // calculate rotational accel and thrust for a motor
void Motor::calculate_forces(const Aircraft::sitl_input &input, void Motor::calculate_forces(const struct sitl_input &input,
const float thrust_scale, const float thrust_scale,
uint8_t motor_offset, uint8_t motor_offset,
Vector3f &rot_accel, Vector3f &rot_accel,

View File

@ -69,7 +69,7 @@ public:
pitch_max(_pitch_max) pitch_max(_pitch_max)
{} {}
void calculate_forces(const Aircraft::sitl_input &input, void calculate_forces(const struct sitl_input &input,
float thrust_scale, float thrust_scale,
uint8_t motor_offset, uint8_t motor_offset,
Vector3f &rot_accel, // rad/sec Vector3f &rot_accel, // rad/sec

View File

@ -29,8 +29,6 @@ MultiCopter::MultiCopter(const char *home_str, const char *frame_str) :
{ {
mass = 1.5f; mass = 1.5f;
gripper.set_aircraft(this);
frame = Frame::find_frame(frame_str); frame = Frame::find_frame(frame_str);
if (frame == nullptr) { if (frame == nullptr) {
printf("Frame '%s' not found", frame_str); printf("Frame '%s' not found", frame_str);
@ -66,6 +64,7 @@ void MultiCopter::update(const struct sitl_input &input)
calculate_forces(input, rot_accel, accel_body); calculate_forces(input, rot_accel, accel_body);
update_dynamics(rot_accel); update_dynamics(rot_accel);
update_external_payload(input);
// update lat/lon/altitude // update lat/lon/altitude
update_position(); update_position();
@ -73,16 +72,4 @@ void MultiCopter::update(const struct sitl_input &input)
// update magnetic field // update magnetic field
update_mag_field_bf(); update_mag_field_bf();
// update sprayer
sprayer.update(input);
// update gripper
gripper.update(input);
gripper_epm.update(input);
}
float MultiCopter::gross_mass() const
{
return Aircraft::gross_mass() + sprayer.payload_mass() + gripper.payload_mass();
} }

View File

@ -22,10 +22,6 @@
#include "SIM_Motor.h" #include "SIM_Motor.h"
#include "SIM_Frame.h" #include "SIM_Frame.h"
#include "SIM_Sprayer.h"
#include "SIM_Gripper_Servo.h"
#include "SIM_Gripper_EPM.h"
namespace SITL { namespace SITL {
/* /*
@ -47,14 +43,6 @@ protected:
// calculate rotational and linear accelerations // calculate rotational and linear accelerations
void calculate_forces(const struct sitl_input &input, Vector3f &rot_accel, Vector3f &body_accel); void calculate_forces(const struct sitl_input &input, Vector3f &rot_accel, Vector3f &body_accel);
Frame *frame; Frame *frame;
// The numbers below are the pwm output channels with "0" meaning the first output (aka RC1)
Sprayer sprayer{6, 7};
Gripper_Servo gripper{8};
Gripper_EPM gripper_epm{9};
float gross_mass() const override;
}; };
} }

View File

@ -17,56 +17,89 @@
*/ */
#include "SIM_Sprayer.h" #include "SIM_Sprayer.h"
#include <stdio.h> #include "AP_HAL/AP_HAL.h"
#include "AP_Math/AP_Math.h"
using namespace SITL; using namespace SITL;
// table of user settable parameters
const AP_Param::GroupInfo Sprayer::var_info[] = {
// @Param: ENABLE
// @DisplayName: Gripper servo Sim enable/disable
// @Description: Allows you to enable (1) or disable (0) the gripper servo simulation
// @Values: 0:Disabled,1:Enabled
// @User: Advanced
AP_GROUPINFO("ENABLE", 0, Sprayer, sprayer_enable, 0),
// @Param: PUMP
// @DisplayName: Sprayer pump pin
// @Description: The pin number that the Sprayer pump is connected to. (start at 1)
// @Range: 0 15
// @User: Advanced
AP_GROUPINFO("PUMP", 1, Sprayer, sprayer_pump_pin, -1),
// @Param: SPIN
// @DisplayName: Sprayer spinner servo pin
// @Description: The pin number that the Sprayer spinner servo is connected to. (start at 1)
// @Range: 0 15
// @User: Advanced
AP_GROUPINFO("SPIN", 2, Sprayer, sprayer_spin_pin, -1),
AP_GROUPEND
};
/* /*
update sprayer state update sprayer state
*/ */
void Sprayer::update(const Aircraft::sitl_input &input) void Sprayer::update(const struct sitl_input &input)
{ {
const int16_t pump_pwm = sprayer_pump_pin >= 1 ? input.servos[sprayer_pump_pin-1] : -1;
const int16_t spinner_pwm = sprayer_spin_pin >= 1 ? input.servos[sprayer_spin_pin-1] : -1;
const uint64_t now = AP_HAL::micros64(); const uint64_t now = AP_HAL::micros64();
const float dt = (now - last_update_us) * 1.0e-6f; const float dt = (now - last_update_us) * 1.0e-6f;
if (pump_pwm >= 0) {
// update remaining payload // update remaining payload
if (capacity > 0) { if (capacity > 0) {
const double delta = last_pump_output * pump_max_rate * dt; const double delta = last_pump_output * pump_max_rate * dt;
capacity -= delta; capacity -= delta;
if (capacity < 0) { if (capacity < 0) {
capacity = 0.0f; capacity = 0.0f;
}
} }
}
// update pump // update pump
float pump_demand = (input.servos[pump_servo]-1000) * 0.001f; float pump_demand = (pump_pwm - 1000) * 0.001f;
// ::fprintf(stderr, "pump_demand=%f\n", pump_demand); // ::fprintf(stderr, "pump_demand=%f\n", pump_demand);
if (pump_demand < 0) { // never updated if (pump_demand < 0) { // never updated
pump_demand = 0; pump_demand = 0;
}
const float pump_max_change = pump_slew_rate / 100.0f * dt;
last_pump_output =
constrain_float(pump_demand, last_pump_output - pump_max_change, last_pump_output + pump_max_change);
last_pump_output = constrain_float(last_pump_output, 0, 1);
} else {
last_pump_output = 0.0f;
} }
const float pump_max_change = pump_slew_rate/100.0f * dt;
last_pump_output = constrain_float(pump_demand, last_pump_output-pump_max_change, last_pump_output+pump_max_change);
last_pump_output = constrain_float(last_pump_output, 0, 1);
// update spinner (if any) // update spinner (if any)
if (spinner_servo >= 0) { if (spinner_pwm >= 0) {
const float spinner_demand = (input.servos[spinner_servo]-1000) * 0.001f; const float spinner_demand = (spinner_pwm - 1000) * 0.001f;
const float spinner_max_change = spinner_slew_rate * 0.01f * dt; const float spinner_max_change = spinner_slew_rate * 0.01f * dt;
last_spinner_output = constrain_float(spinner_demand, last_spinner_output-spinner_max_change, last_spinner_output+spinner_max_change); last_spinner_output = constrain_float(spinner_demand,
last_spinner_output - spinner_max_change,
last_spinner_output + spinner_max_change);
last_spinner_output = constrain_float(last_spinner_output, 0, 1); last_spinner_output = constrain_float(last_spinner_output, 0, 1);
} }
if (should_report()) { if (should_report()) {
printf("Remaining: %f litres\n", capacity); printf("Remaining: %f litres\n", capacity);
printf("Pump: %f l/s\n", last_pump_output * pump_max_rate); printf("Pump: %f l/s\n", last_pump_output * pump_max_rate);
if (spinner_servo >= 0) { if (spinner_pwm >= 0) {
printf("Spinner: %f rev/s\n", (last_spinner_output * spinner_max_rate)/360.0f); printf("Spinner: %f rev/s\n", (last_spinner_output * spinner_max_rate) / 360.0f);
} }
last_report_us = now; last_report_us = now;
} }
last_update_us = now; last_update_us = now;
return;
} }
bool Sprayer::should_report() bool Sprayer::should_report()

View File

@ -18,36 +18,41 @@
#pragma once #pragma once
#include "SIM_Aircraft.h" #include "stdint.h"
#include <AP_Param/AP_Param.h>
#include "SITL_Input.h"
namespace SITL { namespace SITL {
class Sprayer { class Sprayer {
public: public:
const uint8_t pump_servo; Sprayer() {
const int8_t spinner_servo; AP_Param::setup_object_defaults(this, var_info);
};
Sprayer(const uint8_t _pump_servo, int8_t _spinner_servo) :
pump_servo(_pump_servo),
spinner_servo(_spinner_servo)
{}
// update sprayer state // update sprayer state
void update(const struct Aircraft::sitl_input &input); void update(const struct sitl_input &input);
float payload_mass() const { return capacity; }; // kg; water, so kg=l float payload_mass() const { return static_cast<float>(capacity); }; // kg; water, so kg=l
private: static const struct AP_Param::GroupInfo var_info[];
bool is_enabled() const {return static_cast<bool>(sprayer_enable);}
private:
AP_Int8 sprayer_enable; // enable sprayer sim
AP_Int8 sprayer_pump_pin;
AP_Int8 sprayer_spin_pin;
const uint32_t report_interval = 1000000; // microseconds const uint32_t report_interval = 1000000; // microseconds
uint64_t last_report_us; uint64_t last_report_us;
const float pump_max_rate = 0.01; // litres/second const float pump_max_rate = 0.01f; // litres/second
const float pump_slew_rate = 20; // percent/scond const float pump_slew_rate = 20.0f; // percent/second
float last_pump_output; // percentage float last_pump_output; // percentage
const float spinner_max_rate = 3600; // degrees/second const float spinner_max_rate = 3600.0f; // degrees/second
const float spinner_slew_rate = 20; // percent/second const float spinner_slew_rate = 20.0f; // percent/second
float last_spinner_output; // percentage float last_spinner_output; // percentage
double capacity = 0.25; // litres double capacity = 0.25; // litres

View File

@ -122,6 +122,16 @@ const AP_Param::GroupInfo SITL::var_info2[] = {
AP_GROUPINFO("MAG_ODI", 19, SITL, mag_offdiag, 0), AP_GROUPINFO("MAG_ODI", 19, SITL, mag_offdiag, 0),
AP_GROUPINFO("MAG_ORIENT", 20, SITL, mag_orient, 0), AP_GROUPINFO("MAG_ORIENT", 20, SITL, mag_orient, 0),
AP_GROUPINFO("RC_CHANCOUNT",21, SITL, rc_chancount, 16), AP_GROUPINFO("RC_CHANCOUNT",21, SITL, rc_chancount, 16),
// @Group: SPR_
// @Path: ./SIM_Sprayer.cpp
AP_SUBGROUPINFO(sprayer_sim, "SPR_", 22, SITL, Sprayer),
// @Group: GRPS_
// @Path: ./SIM_Gripper_Servo.cpp
AP_SUBGROUPINFO(gripper_sim, "GRPS_", 23, SITL, Gripper_Servo),
// @Group: GRPE_
// @Path: ./SIM_Gripper_EPM.cpp
AP_SUBGROUPINFO(gripper_epm_sim, "GRPE_", 24, SITL, Gripper_EPM),
AP_GROUPEND AP_GROUPEND
}; };

View File

@ -3,6 +3,10 @@
#include <AP_Math/AP_Math.h> #include <AP_Math/AP_Math.h>
#include <GCS_MAVLink/GCS_MAVLink.h> #include <GCS_MAVLink/GCS_MAVLink.h>
#include "SIM_Sprayer.h"
#include "SIM_Gripper_Servo.h"
#include "SIM_Gripper_EPM.h"
class DataFlash_Class; class DataFlash_Class;
namespace SITL { namespace SITL {
@ -144,7 +148,7 @@ public:
AP_Int16 pin_mask; // for GPIO emulation AP_Int16 pin_mask; // for GPIO emulation
AP_Float speedup; // simulation speedup AP_Float speedup; // simulation speedup
AP_Int8 odom_enable; // enable visual odomotry data AP_Int8 odom_enable; // enable visual odomotry data
// wind control // wind control
enum WindType { enum WindType {
WIND_TYPE_SQRT = 0, WIND_TYPE_SQRT = 0,
@ -206,6 +210,11 @@ public:
// convert a set of roll rates from body frame to earth frame // convert a set of roll rates from body frame to earth frame
static Vector3f convert_earth_frame(const Matrix3f &dcm, const Vector3f &gyro); static Vector3f convert_earth_frame(const Matrix3f &dcm, const Vector3f &gyro);
Sprayer sprayer_sim;
Gripper_Servo gripper_sim;
Gripper_EPM gripper_epm_sim;
}; };
} // namespace SITL } // namespace SITL

View File

@ -0,0 +1,18 @@
#pragma once
#include <stdint.h>
/*
structure passed in giving servo positions as PWM values in
microseconds
*/
struct sitl_input {
uint16_t servos[16];
struct {
float speed; // m/s
float direction; // degrees 0..360
float turbulence;
float dir_z; //degrees -90..90
} wind;
};