ardupilot/Tools/ArdupilotMegaPlanner/HIL/FlashQuad.cs

365 lines
11 KiB
C#
Raw Normal View History

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;
}
}
}