171 lines
5.4 KiB
C#
171 lines
5.4 KiB
C#
using FundamentalLib;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Numerics;
|
||
using System.Text;
|
||
using System.Diagnostics;
|
||
|
||
namespace CommonUsage.Chassis
|
||
{
|
||
public class DifferentialChassis : AbstractChassis
|
||
{
|
||
public void SetLeftRightWheels(Wheel wheelL, Wheel wheelR)
|
||
{
|
||
_leftWheel = wheelL;
|
||
_rightWheel = wheelR;
|
||
_halfWheelTrack = Math.Abs(_leftWheel.Position.Y);
|
||
}
|
||
|
||
public override void Visualize()
|
||
{
|
||
|
||
}
|
||
|
||
public override CarSpeed GetCarSpeed(bool isActual = false)
|
||
{
|
||
if (!isActual)
|
||
{
|
||
return new CarSpeed()
|
||
{
|
||
Vx = (_speedL + _speedR) / 2f,
|
||
Vw = (_speedR - _speedL) / Math.Abs(_leftWheel.Position.Y - _rightWheel.Position.Y) /
|
||
(float)Math.PI * 180f * 1000f,
|
||
Vy = 0
|
||
};
|
||
}
|
||
else
|
||
{
|
||
return new CarSpeed()
|
||
{
|
||
Vx = GetLinearSpeed(),
|
||
Vw = (_rightWheel.ReadSpeed() - _leftWheel.ReadSpeed()) /
|
||
Math.Abs(_leftWheel.Position.Y - _rightWheel.Position.Y) /
|
||
(float)Math.PI * 180f * 1000f,
|
||
Vy = 0
|
||
};
|
||
}
|
||
|
||
}
|
||
|
||
public (Wheel,Wheel) GetWheels()
|
||
{
|
||
return (_leftWheel, _rightWheel);
|
||
}
|
||
|
||
public float GetLinearSpeed()
|
||
{
|
||
return (_leftWheel.ReadSpeed() + _rightWheel.ReadSpeed()) / 2f;
|
||
}
|
||
|
||
public override void Initialize()
|
||
{
|
||
GeometricControlPoints.Add(new GeometricControlPoint(new Vector2(0, 0)));
|
||
Valid = true;
|
||
}
|
||
|
||
public override void AfterDirectionChanged()
|
||
{
|
||
|
||
}
|
||
|
||
public override void PredefinedDriveStop()
|
||
{
|
||
if (!Valid) return;
|
||
_sendSpeedL = _sendSpeedR = 0;
|
||
_speedL = _speedR = 0;
|
||
_leftWheel.WriteSpeed(_sendSpeedL);
|
||
_rightWheel.WriteSpeed(_sendSpeedR);
|
||
GoingActive = false;
|
||
RotatingActive = false;
|
||
}
|
||
|
||
protected override void DefineGeometricWheelComputation(float speed)
|
||
{
|
||
var now = DateTime.Now;
|
||
if (!GoingActive) LastMoveTime = now;
|
||
|
||
SendSpeed(speed, GeometricControlPoints[0].Theta, now - LastMoveTime);
|
||
|
||
GoingActive = true;
|
||
RotatingActive = false;
|
||
}
|
||
|
||
public override bool ComputeRotateWheels(float rotSpeed)
|
||
{
|
||
if (!RotatingActive) LastMoveTime = DateTime.Now;
|
||
|
||
SendSpeed(0, rotSpeed);
|
||
|
||
GoingActive = false;
|
||
RotatingActive = true;
|
||
return true;
|
||
}
|
||
|
||
public override float CalculateTurningSpeedDecayFac(float turn)
|
||
{
|
||
return 1 - Math.Min(turn, MaxTurnThreshold) / MaxTurnThreshold * MinTurnSpeedFac;
|
||
}
|
||
|
||
public void SendSpeed(float linearSpeed, float angularSpeed, TimeSpan? deltaTime = null)
|
||
{
|
||
var edgeLinearSpeed = (float)(angularSpeed / 180f * Math.PI * _halfWheelTrack / 1000);
|
||
var vl = linearSpeed - edgeLinearSpeed;
|
||
var vr = linearSpeed + edgeLinearSpeed;
|
||
_speedL = vl;
|
||
_speedR = vr;
|
||
AccumulateSpeed(vl, vr, deltaTime);
|
||
LastMoveTime = DateTime.Now;
|
||
}
|
||
|
||
private void AccumulateSpeed(float vl, float vr, TimeSpan? deltaTime = null)
|
||
{
|
||
// var dTime = (float)(deltaTime ?? DateTime.Now - LastMoveTime).TotalSeconds;
|
||
//
|
||
// var speedSignL = Math.Sign(vl - _sendSpeedL);
|
||
// var accL = Math.Abs(vl) > Math.Abs(_sendSpeedL) ? AccPerSecond : DeAccPerSecond;
|
||
// _sendSpeedL += speedSignL * Math.Min(Math.Abs(vl - _sendSpeedL), accL * dTime);
|
||
// _leftWheel.WriteSpeed(_sendSpeedL);
|
||
//
|
||
// var speedSignR = Math.Sign(vr - _sendSpeedR);
|
||
// var accR = Math.Abs(vr) > Math.Abs(_sendSpeedR) ? AccPerSecond : DeAccPerSecond;
|
||
// _sendSpeedR += speedSignR * Math.Min(Math.Abs(vr - _sendSpeedR), accR * dTime);
|
||
// _rightWheel.WriteSpeed(_sendSpeedR);
|
||
|
||
// if (Debug)
|
||
// Console.WriteLine($"DiffChassis, target:{v:0.00},send:{_sendSpeed:0.0}");
|
||
// var dTime = (float)(deltaTime ?? DateTime.Now - LastMoveTime).TotalSeconds;
|
||
var dTime = (float)(deltaTime ?? DateTime.Now - LastMoveTime).TotalSeconds;
|
||
float diffL = vl - _sendSpeedL;
|
||
float diffR = vr - _sendSpeedR;
|
||
|
||
float accL = Math.Abs(vl) > Math.Abs(_sendSpeedL) ? AccPerSecond : DeAccPerSecond;
|
||
float accR = Math.Abs(vr) > Math.Abs(_sendSpeedR) ? AccPerSecond : DeAccPerSecond;
|
||
|
||
float maxDeltaL = accL * dTime;
|
||
float maxDeltaR = accR * dTime;
|
||
|
||
float factorL = Math.Abs(diffL) > maxDeltaL ? maxDeltaL / Math.Abs(diffL) : 1.0f;
|
||
float factorR = Math.Abs(diffR) > maxDeltaR ? maxDeltaR / Math.Abs(diffR) : 1.0f;
|
||
|
||
float factor = Math.Min(factorL, factorR);
|
||
|
||
_sendSpeedL += diffL * factor;
|
||
_sendSpeedR += diffR * factor;
|
||
|
||
_leftWheel.WriteSpeed(_sendSpeedL);
|
||
_rightWheel.WriteSpeed(_sendSpeedR);
|
||
// Console.WriteLine($"DiffChassis, target:{vl:0.00},send:{_sendSpeedL:0.00} dTime:{dTime} diffL:{diffL} factor:{factor}" );
|
||
}
|
||
|
||
private Wheel _leftWheel;
|
||
private Wheel _rightWheel;
|
||
private float _halfWheelTrack; // millimeter
|
||
|
||
private float _sendSpeedL;
|
||
private float _sendSpeedR;
|
||
private int _direction = 1; // 1 forward, -1 backward
|
||
private float _speedL;
|
||
private float _speedR;
|
||
}
|
||
}
|