You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
364 lines
11 KiB
364 lines
11 KiB
using System; |
|
using System.Collections.Generic; |
|
using System.Linq; |
|
using System.Text; |
|
using Sharp3D.Math.Core; |
|
|
|
namespace ArdupilotMega.HIL |
|
{ |
|
class FlashQuad |
|
{ |
|
public ahrsc ahrs = new ahrsc() ;// :AHRS; |
|
public Vector3D loc = new Vector3D() ;// :Location; |
|
public param g = new param() ;// :Parameters; |
|
//public var apm_rc :APM_RC; |
|
//public var motor_filter_0 :AverageFilter; |
|
//public var motor_filter_1 :AverageFilter; |
|
//public var motor_filter_2 :AverageFilter; |
|
//public var motor_filter_3 :AverageFilter; |
|
public Vector3D drag = new Vector3D();// :Vector3D; // |
|
public Vector3D airspeed = new Vector3D();// :Vector3D; // |
|
//public var thrust :Vector3D; // |
|
public Vector3D position = new Vector3D();// :Vector3D; // |
|
public Vector3D velocity = new Vector3D();// :Vector3D; |
|
//public var velocity_old :Vector3D; |
|
//public var wind :Point; // |
|
public Vector3D rot_accel = new Vector3D();// :Vector3D; // |
|
public Vector3D angle3D = new Vector3D();// :Vector3D; // |
|
//public var windGenerator :Wind; // |
|
|
|
public double gravity = 980.5; |
|
public double thrust_scale = 0.4; |
|
public double throttle = 500; |
|
public double rotation_bias = 1; |
|
|
|
private double _jump_z = 0; |
|
private Vector3D v3 = new Vector3D(); |
|
|
|
public class ahrsc |
|
{ |
|
public Matrix3D dcm = new Matrix3D(Matrix3D.Identity); |
|
public Vector3D gyro = new Vector3D(); |
|
public Vector3D omega = new Vector3D(); |
|
public Vector3D accel = new Vector3D(); |
|
public Vector3D rotation_speed = new Vector3D(); |
|
|
|
public double roll_sensor; |
|
public double pitch_sensor; |
|
public double yaw_sensor; |
|
} |
|
|
|
public class param |
|
{ |
|
// --------------------------------------------- |
|
// Sim Details controls |
|
// --------------------------------------------- |
|
public int sim_iterations = 99999; |
|
public int sim_speed = 1; |
|
|
|
public double windSpeedMin = 150; |
|
public double windSpeedMax = 200; |
|
public double windPeriod = 30000; |
|
public double windDir = 45; |
|
|
|
public double airDensity = 1.184; |
|
//public var crossSection :Number = 0.015; |
|
public double crossSection = 0.012; |
|
public double dragCE = 0.20; |
|
public double speed_filter_size = 2; |
|
public double motor_kv = 1000; |
|
public double moment = 3; |
|
public double mass = 500; |
|
public int esc_delay = 12; |
|
|
|
// ----------------------------------------- |
|
// Inertial control |
|
// ----------------------------------------- |
|
public double speed_correction_z = 0.0350; |
|
public double xy_speed_correction = 0.030; |
|
public double xy_offset_correction = 0.00001; |
|
public double xy_pos_correction = 0.08; |
|
|
|
public double z_offset_correction = 0.00004; |
|
public double z_pos_correction = 0.2; |
|
|
|
public double accel_bias_x = .9; |
|
public double accel_bias_z = .9; |
|
public double accel_bias_y = .9; |
|
} |
|
|
|
double scale_rc(int sn, float servo, float min, float max) |
|
{ |
|
float min_pwm = 1000; |
|
float max_pwm = 2000; |
|
//'''scale a PWM value''' # default to servo range of 1000 to 2000 |
|
if (MainV2.comPort.param.Count > 0) |
|
{ |
|
min_pwm = int.Parse(MainV2.comPort.param["RC3_MIN"].ToString()); |
|
max_pwm = int.Parse(MainV2.comPort.param["RC3_MAX"].ToString()); |
|
} |
|
|
|
float p = (servo - min_pwm) / (max_pwm - min_pwm); |
|
|
|
float v = min + p * (max - min); |
|
|
|
if (v < min) |
|
v = min; |
|
if (v > max) |
|
v = max; |
|
return v * 1000; |
|
} |
|
|
|
public void update(ref double[] motor_output, double dt) |
|
{ |
|
var _thrust = 0.0; |
|
rot_accel = new Vector3D(0,0,0); |
|
angle3D.X = angle3D.Y = 0; |
|
angle3D.Z = 1; |
|
|
|
// wind = windGenerator.read(); |
|
|
|
// ESC's moving average filter |
|
// var motor_output:Array = new Array(4); |
|
// motor_output[0] = motor_filter_0.apply(apm_rc.get_motor_output(0)); |
|
// motor_output[1] = motor_filter_1.apply(apm_rc.get_motor_output(1)); |
|
// motor_output[2] = motor_filter_2.apply(apm_rc.get_motor_output(2)); |
|
// motor_output[3] = motor_filter_3.apply(apm_rc.get_motor_output(3)); |
|
|
|
|
|
for (int i = 0; i < motor_output.Length; i++) |
|
{ |
|
if (motor_output[i] <= 0.0) |
|
{ |
|
motor_output[i] = 0; |
|
} |
|
else |
|
{ |
|
motor_output[i] = scale_rc(i, (float)motor_output[i], 0.0f, 1.0f); |
|
//servos[i] = motor_speed[i]; |
|
} |
|
} |
|
|
|
/* |
|
2 |
|
|
|
1 0 |
|
|
|
3 |
|
|
|
*/ |
|
|
|
// setup motor rotations |
|
rot_accel.X -= g.motor_kv * motor_output[0]; // roll |
|
rot_accel.X += g.motor_kv * motor_output[1]; |
|
rot_accel.Y -= g.motor_kv * motor_output[3]; |
|
rot_accel.Y += g.motor_kv * motor_output[2]; |
|
|
|
rot_accel.Z += g.motor_kv * motor_output[0] * .08; // YAW |
|
rot_accel.Z += g.motor_kv * motor_output[1] * .08; |
|
rot_accel.Z -= g.motor_kv * motor_output[2] * .08; |
|
rot_accel.Z -= g.motor_kv * motor_output[3] * .08; |
|
|
|
rot_accel.X /= g.moment; |
|
rot_accel.Y /= g.moment; |
|
rot_accel.Z /= g.moment; |
|
|
|
//# rotational air resistance |
|
|
|
// Gyro is the rotation speed in deg/s |
|
// update rotational rates in body frame |
|
ahrs.gyro.X += rot_accel.X * dt; |
|
ahrs.gyro.Y += rot_accel.Y * dt; |
|
ahrs.gyro.Z += rot_accel.Z * dt; |
|
|
|
//ahrs.gyro.z += 200; |
|
ahrs.gyro.Z *= .995;// some drag |
|
|
|
// ahrs.dcm = Matrix3D.Identity; |
|
|
|
// move earth frame to body frame |
|
Vector3D tmp = Matrix3D.Transform(ahrs.dcm,ahrs.gyro) ;//ahrs.dcm.transformVector(ahrs.gyro); |
|
|
|
// update attitude: |
|
ahrs.dcm += new Matrix3D(new Vector3D((tmp.X/100) * dt,0,0),new Vector3D(0,(tmp.Y/100) * dt,0),new Vector3D(0,0,(tmp.Z/100) * dt)); |
|
|
|
//ahrs.dcm.appendRotation((tmp.X/100) * dt, Vector3D.X_AXIS); // ROLL |
|
//ahrs.dcm.appendRotation((tmp.Y/100) * dt, Vector3D.Y_AXIS); // PITCH |
|
//ahrs.dcm.appendRotation((tmp.Z/100) * dt, Vector3D.Z_AXIS); // YAW |
|
|
|
// ------------------------------------ |
|
// calc thrust |
|
// ------------------------------------ |
|
|
|
//get_motor_output returns 0 : 1000 |
|
_thrust += motor_output[0] * thrust_scale; |
|
_thrust += motor_output[1] * thrust_scale; |
|
_thrust += motor_output[2] * thrust_scale; |
|
_thrust += motor_output[3] * thrust_scale; |
|
|
|
Vector3D accel_body = new Vector3D(0, 0, (_thrust * -.9) / g.mass); |
|
//var accel_body:Vector3D = new Vector3D(0, 0, 0); |
|
Vector3D accel_earth = Matrix3D.Transform(ahrs.dcm,(accel_body)); |
|
angle3D = Matrix3D.Transform(ahrs.dcm,(angle3D)); |
|
|
|
//trace(ahrs.gyro.y, accel_earth.x); |
|
|
|
//trace(ahrs.gyro.x, ahrs.gyro.y, ahrs.gyro.z); |
|
|
|
// ------------------------------------ |
|
// calc copter velocity |
|
// ------------------------------------ |
|
// calc Drag |
|
drag.X = .5 * g.airDensity * airspeed.X * airspeed.X * g.dragCE * g.crossSection; |
|
drag.Y = .5 * g.airDensity * airspeed.Y * airspeed.Y * g.dragCE * g.crossSection; |
|
drag.Z = .5 * g.airDensity * airspeed.Z * airspeed.Z * g.dragCE * g.crossSection; |
|
|
|
///* |
|
// this calulation includes wind |
|
if(airspeed.X >= 0) |
|
accel_earth.X -= drag.X; |
|
else |
|
accel_earth.X += drag.X; |
|
|
|
// Add in Drag |
|
if(airspeed.Y >= 0) |
|
accel_earth.Y -= drag.Y; |
|
else |
|
accel_earth.Y += drag.Y; |
|
|
|
if(airspeed.Z <= 0) |
|
accel_earth.Z -= drag.Z; |
|
else |
|
accel_earth.Z += drag.Z; |
|
//*/ |
|
|
|
// hacked vert disturbance |
|
accel_earth.Z += _jump_z * dt; |
|
_jump_z *= .999; |
|
|
|
|
|
// Add in Gravity |
|
accel_earth.Z += gravity; |
|
|
|
if(accel_earth.Z < 0) |
|
accel_earth.Z *=.9; |
|
|
|
|
|
if(position.Z <=.11 && accel_earth.Z > 0){ |
|
accel_earth.Z = 0; |
|
} |
|
|
|
velocity.X += (accel_earth.X * dt); // + : Forward (North) |
|
velocity.Y += (accel_earth.Y * dt); // + : Right (East) |
|
velocity.Z -= (accel_earth.Z * dt); // + : Up |
|
|
|
|
|
//trace(Math.floor(velocity.x),Math.floor(velocity.y),Math.floor(velocity.z)); |
|
|
|
// ------------------------------------ |
|
// calc inertia |
|
// ------------------------------------ |
|
|
|
// work out acceleration as seen by the accelerometers. It sees the kinematic |
|
// acceleration (ie. real movement), plus gravity |
|
Matrix3D dcm_t = ahrs.dcm.Clone(); |
|
dcm_t.Transpose(); |
|
double t = accel_earth.Z; |
|
accel_earth.Z -= gravity; |
|
ahrs.accel = Matrix3D.Transform(dcm_t,(accel_earth)); |
|
|
|
ahrs.accel *= 0.01; |
|
|
|
//ahrs.accel = accel_earth.clone(); |
|
ahrs.accel.X *= g.accel_bias_x; |
|
ahrs.accel.Y *= g.accel_bias_y; |
|
ahrs.accel.Z *= g.accel_bias_z; |
|
|
|
|
|
|
|
// ------------------------------------ |
|
// calc Position |
|
// ------------------------------------ |
|
position.Y += velocity.X * dt; |
|
position.X += velocity.Y * dt; |
|
position.Z += velocity.Z * dt; |
|
position.Z = Math.Min(position.Z, 4000); |
|
|
|
// XXX Force us to 3m above ground |
|
//position.z = 300; |
|
|
|
airspeed.X = (velocity.X);// - wind.x); |
|
airspeed.Y = (velocity.Y);// - wind.y); |
|
airspeed.Z = velocity.Z; |
|
|
|
// Altitude |
|
// -------- |
|
if(position.Z <=.1){ |
|
position.Z = .1; |
|
velocity.X = 0; |
|
velocity.Y = 0; |
|
velocity.Z = 0; |
|
airspeed.X = 0; |
|
airspeed.Y = 0; |
|
airspeed.Z = 0; |
|
//ahrs.init(); |
|
} |
|
|
|
|
|
// get omega - the simulated Gyro output |
|
ahrs.omega.X = radiansx100(ahrs.gyro.X); |
|
ahrs.omega.Y = radiansx100(ahrs.gyro.Y); |
|
ahrs.omega.Z = radiansx100(ahrs.gyro.Z); |
|
|
|
// get the Eulers output |
|
v3 = new Vector3D(Math.Atan2(-ahrs.dcm.M23, ahrs.dcm.M22), Math.Asin(ahrs.dcm.M21), Math.Atan2(-ahrs.dcm.M31, ahrs.dcm.M11));// ahrs.dcm.decompose(); |
|
ahrs.roll_sensor = Math.Floor(degrees(v3.X) * 100); |
|
ahrs.pitch_sensor = Math.Floor(degrees(v3.Y) * 100); |
|
ahrs.yaw_sensor = Math.Floor(degrees(v3.Z) * 100); |
|
|
|
// store the position for the GPS object |
|
loc.X = position.X; |
|
loc.Y = position.Y; |
|
loc.Z = position.Z; |
|
} |
|
|
|
public double constrain(double val, double min, double max) |
|
{ |
|
val = Math.Max(val, min); |
|
val = Math.Min(val, max); |
|
return val; |
|
} |
|
|
|
public double wrap_180(int error) |
|
{ |
|
if (error > 18000) error -= 36000; |
|
if (error < -18000) error += 36000; |
|
return error; |
|
} |
|
|
|
public int wrap_360(int error) |
|
{ |
|
if (error > 36000) error -= 36000; |
|
if (error < 0) error += 36000; |
|
return error; |
|
} |
|
|
|
public double radiansx100(double n) |
|
{ |
|
return 0.000174532925 * n; |
|
} |
|
|
|
public double degreesx100(double r) |
|
{ |
|
return r * 5729.57795; |
|
} |
|
public double degrees(double r) |
|
{ |
|
return r * 57.2957795; |
|
} |
|
public double radians(double n) |
|
{ |
|
return 0.0174532925 * n; |
|
} |
|
} |
|
}
|
|
|