/// <summary> /// Return the velocity of the wheel on the ground to do the rotation, based on the angular velocity required /// </summary> /// <param name="robot">robot parameters, notably width and length</param> /// <param name="rv">the angular velocity in degrees per second</param> /// <returns></returns> private double RotationalToGround(RobotParams robot, double rv) { double diameter = Math.Sqrt(robot.Width * robot.Width + robot.Length * robot.Length); double circum = diameter * Math.PI; return(rv * circum / 360.0); }
private double GroundToRotational(RobotParams robot, double gr) { double diameter = Math.Sqrt(robot.Width * robot.Width + robot.Length * robot.Length); double circum = diameter * Math.PI; return(gr * 360.0 / circum); }
/// <summary> /// Returns the rotational speed profile to rotate the robot /// </summary> /// <param name="robot"></param> /// <param name="start"></param> /// <param name="end"></param> /// <returns></returns> private TrapezoidalProfile CreateRotationProfile(RobotParams robot, double start, double end, double time, double vel) { double accel = GroundToRotational(robot, robot.MaxAcceleration); double maxvel = GroundToRotational(robot, vel); double diff = end - start; if (diff > 180.0) { diff -= 360.0; } else if (diff <= -180.0) { diff += 360.0; } TrapezoidalProfile tp; tp = new TrapezoidalProfile(accel, maxvel); tp.Update(diff, 0.0, 0.0); if (tp.TotalTime > time) { throw new SwerveDriveModifier.VelocitySplitException(); } return(tp); }
/// <summary> /// Return a vector, perpendicular to the requested wheel (e.g. a rotational vector) with the /// magnitude given. /// </summary> /// <param name="robot">robot parameters, provides the width and length of the robot</param> /// <param name="w">the wheel of interest</param> /// <param name="magnitude">the magintude of the vector</param> /// <returns>vector perpendicular to the requested wheel</returns> private XeroVector GetWheelPerpendicularVector(RobotParams robot, Wheel w, double magnitude) { double dx = 0.0, dy = 0.0; switch (w) { case Wheel.FL: dx = robot.Length / 2.0; dy = robot.Width / 2.0; break; case Wheel.FR: dx = robot.Length / 2.0; dy = -robot.Width / 2.0; break; case Wheel.BL: dx = -robot.Length / 2.0; dy = robot.Width / 2.0; break; case Wheel.BR: dx = -robot.Length / 2.0; dy = -robot.Width / 2.0; break; } return(new XeroVector(dx, dy).Normalize().Perpendicular().Scale(magnitude)); }
private void GenerateSegmentsForPath(RobotParams robot, RobotPath path) { PathSegment[] segs = null; Dictionary <string, PathSegment[]> add = null; DriveModifier mod = null; double rotpercent = 0.0; bool running = true; if (robot.DriveType == RobotParams.TankDriveType) { mod = new TankDriveModifier(); } else if (robot.DriveType == RobotParams.SwerveDriveType) { mod = new SwerveDriveModifier(); } while (running) { RobotParams nrobot = new RobotParams(robot); nrobot.MaxVelocity = (1 - rotpercent) * robot.MaxVelocity; segs = GenerateDetailedPath(nrobot, path); try { add = mod.ModifyPath(robot, path, segs, rotpercent * robot.MaxVelocity); running = false; } catch (DriveModifier.VelocitySplitException) { rotpercent += 0.05; } } path.SetSegments(segs, add); }
public RobotParams(RobotParams p) { Width = p.Width; Length = p.Length; MaxVelocity = p.MaxVelocity; MaxAcceleration = p.MaxAcceleration; MaxJerk = p.MaxJerk; DriveType = p.DriveType; LengthUnits = p.LengthUnits; TimeStep = p.TimeStep; }
public PathFile(PathFile pf) { Robot = new RobotParams(pf.Robot); Groups = new PathGroup[pf.Groups.Length]; for (int i = 0; i < Groups.Length; i++) { Groups[i] = new PathGroup(pf.Groups[i]); } IsDirty = true; m_filename = pf.m_filename; }
public void GenerateSegments(RobotParams robot, RobotPath path) { PathGenerationStateChangeEvent args = null; Tuple <RobotParams, RobotPath> entry = new Tuple <RobotParams, RobotPath>(robot, path); lock (m_lock) { m_queue.Add(entry); int running = m_active ? 1 : 0; int queued = m_queue.Count; args = new PathGenerationStateChangeEvent(running, queued); } OnJobStateChanged(args); }
public void AddPath(RobotParams robot, string name) { RobotPath path = new RobotPath(name); path.MaxVelocity = robot.MaxVelocity; path.MaxAcceleration = robot.MaxAcceleration; path.MaxJerk = robot.MaxJerk; Array.Resize <RobotPath>(ref Paths, Paths.Length + 1); Paths[Paths.Length - 1] = path; double length = UnitConverter.Convert(100.0, "inches", robot.LengthUnits); path.AddPoint(new WayPoint(0.0, 0.0, 0.0, 0.0)); path.AddPoint(new WayPoint(length, 0.0, 0.0, 0.0)); }
public void GenerateSegments(RobotParams robot, PathGenerator gen) { bool needgen = false; lock (m_lock) { if (m_segments == null || m_segments_dirty) { needgen = true; m_segments = null; m_segments_dirty = false; } } if (needgen) { gen.GenerateSegments(robot, this); } }
public static void Diff(RobotParams p1, RobotParams p2, List <string> diff) { if (p1.DriveType != p2.DriveType) { diff.Add("DriveType:p1 = " + p1.DriveType + ", p2 = " + p2.DriveType); } if (p1.LengthUnits != p2.LengthUnits) { diff.Add("Units: p1 = " + p1.LengthUnits + ", p2 = " + p2.LengthUnits); } if (Math.Abs(p1.Length - p2.Length) > kEpsilon) { diff.Add("Length: p1 = " + p1.Length.ToString() + ", p2 = " + p2.Length.ToString()); } if (Math.Abs(p1.Width - p2.Width) > kEpsilon) { diff.Add("Width: p1 = " + p1.Width.ToString() + ", p2 = " + p2.Width.ToString()); } if (Math.Abs(p1.MaxVelocity - p2.MaxVelocity) > kEpsilon) { diff.Add("MaxVelocity: p1 = " + p1.MaxVelocity.ToString() + ", p2 = " + p2.MaxVelocity.ToString()); } if (Math.Abs(p1.MaxAcceleration - p2.MaxAcceleration) > kEpsilon) { diff.Add("MaxAcceleration: p1 = " + p1.MaxAcceleration.ToString() + ", p2 = " + p2.MaxAcceleration.ToString()); } if (Math.Abs(p1.MaxJerk - p2.MaxJerk) > kEpsilon) { diff.Add("MaxJerk: p1 = " + p1.MaxJerk.ToString() + ", p2 = " + p2.MaxJerk.ToString()); } if (Math.Abs(p1.TimeStep - p2.TimeStep) > kEpsilon) { diff.Add("TimeStep: p1 = " + p1.TimeStep.ToString() + ", p2 = " + p2.TimeStep.ToString()); } }
protected bool GeneratePathFile(RobotParams robot, RobotPath path, string filename) { bool ret = true; PathFile pf = new PathFile(); pf.Robot = robot; pf.AddPathGroup("tmp"); pf.AddPath("tmp", path); string json = JsonConvert.SerializeObject(pf); try { File.WriteAllText(filename, json); } catch (Exception) { ret = false; } return(ret); }
public PathFile() { Groups = new PathGroup[0]; Robot = new RobotParams(RobotParams.TankDriveType, "inches", "degrees", 0.02, 24.0, 32.0, 96.0, 96.0, 96.0); }
public abstract Dictionary <string, PathSegment[]> ModifyPath(RobotParams robot, RobotPath path, PathSegment[] segs, double rotvel);
public override Dictionary <string, PathSegment[]> ModifyPath(RobotParams robot, RobotPath path, PathSegment[] segs, double rotvel) { Dictionary <string, PathSegment[]> result = new Dictionary <string, PathSegment[]>(); if (segs == null) { return(null); } double total = segs[segs.Length - 1].GetValue("time"); double rtime = total - path.FacingAngleStartDelay - path.FacingAngleEndDelay; TrapezoidalProfile profile = CreateRotationProfile(robot, path.StartFacingAngle, path.EndFacingAngle, rtime, rotvel); if (profile == null) { throw new DriveModifier.VelocitySplitException(); } PathSegment[] fl = new PathSegment[segs.Length]; PathSegment[] fr = new PathSegment[segs.Length]; PathSegment[] bl = new PathSegment[segs.Length]; PathSegment[] br = new PathSegment[segs.Length]; result["fl"] = fl; result["fr"] = fr; result["bl"] = bl; result["br"] = br; for (int i = 0; i < segs.Length; i++) { // // The time in the path // double time = segs[i].GetValue("time"); // // The current facing angle based on the rotational trapezoidal profile // double current = XeroUtils.BoundDegrees(path.StartFacingAngle + profile.GetDistance(time - path.FacingAngleStartDelay)); // // Get the required velocity to perform the rotation. This is the // linear ground based velocity for the wheel that must be applied to // each wheel in direction perpendicular to the vector from the center of // the robot to the center of the wheel. // double rv = RotationalToGround(robot, profile.GetVelocity(time - path.FacingAngleStartDelay)); double ra = RotationalToGround(robot, profile.GetAcceleration(time - path.FacingAngleStartDelay)); // // Get the velocity vector and acceleration vector relative to each of the // wheels to rotate the robot based on the desired rotational velocity. // XeroVector rotflvel = GetWheelPerpendicularVector(robot, Wheel.FL, rv); XeroVector rotfrvel = GetWheelPerpendicularVector(robot, Wheel.FR, rv); XeroVector rotblvel = GetWheelPerpendicularVector(robot, Wheel.BL, rv); XeroVector rotbrvel = GetWheelPerpendicularVector(robot, Wheel.BR, rv); XeroVector rotflacc = GetWheelPerpendicularVector(robot, Wheel.FL, ra); XeroVector rotfracc = GetWheelPerpendicularVector(robot, Wheel.FR, ra); XeroVector rotblacc = GetWheelPerpendicularVector(robot, Wheel.BL, ra); XeroVector rotbracc = GetWheelPerpendicularVector(robot, Wheel.BR, ra); // // Get the translational velocity vector to follow the path // XeroVector pathvel = XeroVector.FromDegreesMagnitude(segs[i].GetValue("heading"), segs[i].GetValue("velocity")).RotateDegrees(-current); XeroVector pathacc = XeroVector.FromDegreesMagnitude(segs[i].GetValue("heading"), segs[i].GetValue("acceleration")).RotateDegrees(-current); // // For each wheel, the velocity vector is the sum of the rotational vector and the translational vector // XeroVector flv = rotflvel + pathvel; XeroVector frv = rotfrvel + pathvel; XeroVector blv = rotblvel + pathvel; XeroVector brv = rotbrvel + pathvel; XeroVector fla = rotflacc + pathvel; XeroVector fra = rotfracc + pathvel; XeroVector bla = rotblacc + pathvel; XeroVector bra = rotbracc + pathvel; // // Now calculate the wheel positions based on the path position and the // facing angle // XeroVector flpos = new XeroVector(robot.Length / 2.0, robot.Width / 2.0).RotateDegrees(current).Translate(segs[i].GetValue("x"), segs[i].GetValue("y")); XeroVector frpos = new XeroVector(robot.Length / 2.0, -robot.Width / 2.0).RotateDegrees(current).Translate(segs[i].GetValue("x"), segs[i].GetValue("y")); XeroVector blpos = new XeroVector(-robot.Length / 2.0, robot.Width / 2.0).RotateDegrees(current).Translate(segs[i].GetValue("x"), segs[i].GetValue("y")); XeroVector brpos = new XeroVector(-robot.Length / 2.0, -robot.Width / 2.0).RotateDegrees(current).Translate(segs[i].GetValue("x"), segs[i].GetValue("y")); PathSegment newseg = new PathSegment(segs[i]); newseg.SetValue("x", flpos.X); newseg.SetValue("y", flpos.Y); newseg.SetValue("velocity", flv.Magnitude()); newseg.SetValue("heading", flv.AngleDegrees()); newseg.SetValue("acceleration", fla.Magnitude()); fl[i] = newseg; newseg = new PathSegment(segs[i]); newseg.SetValue("x", frpos.X); newseg.SetValue("y", frpos.Y); newseg.SetValue("velocity", frv.Magnitude()); newseg.SetValue("heading", frv.AngleDegrees()); newseg.SetValue("acceleration", fra.Magnitude()); fr[i] = newseg; newseg = new PathSegment(segs[i]); newseg.SetValue("x", blpos.X); newseg.SetValue("y", blpos.Y); newseg.SetValue("velocity", blv.Magnitude()); newseg.SetValue("heading", blv.AngleDegrees()); newseg.SetValue("acceleration", bla.Magnitude()); bl[i] = newseg; newseg = new PathSegment(segs[i]); newseg.SetValue("x", brpos.X); newseg.SetValue("y", brpos.Y); newseg.SetValue("velocity", brv.Magnitude()); newseg.SetValue("heading", brv.AngleDegrees()); newseg.SetValue("acceleration", bra.Magnitude()); br[i] = newseg; } return(result); }
public override Dictionary <string, PathSegment[]> ModifyPath(RobotParams robot, RobotPath path, PathSegment[] segs, double rotvel) { Dictionary <string, PathSegment[]> result = new Dictionary <string, PathSegment[]>(); if (segs == null) { return(null); } double lvel, lacc, ljerk, lpos = 0.0; double rvel, racc, rjerk, rpos = 0.0; double plx = 0.0, ply = 0.0; double prx = 0.0, pry = 0.0; double plvel = 0.0, prvel = 0.0; double placc = 0.0, pracc = 0.0; PathSegment[] lsegs = new PathSegment[segs.Length]; PathSegment[] rsegs = new PathSegment[segs.Length]; result["left"] = lsegs; result["right"] = rsegs; for (int i = 0; i < segs.Length; i++) { double time = segs[i].GetValue("time"); double heading = XeroUtils.DegreesToRadians(segs[i].GetValue("heading")); double ca = Math.Cos(heading); double sa = Math.Sin(heading); double px = segs[i].GetValue("x"); double py = segs[i].GetValue("y"); double lx = px - robot.Width * sa / 2.0; double ly = py + robot.Width * ca / 2.0; double rx = px + robot.Width * sa / 2.0; double ry = py - robot.Width * ca / 2.0; if (i == 0) { lvel = 0.0; lacc = 0.0; lpos = 0.0; ljerk = 0.0; rvel = 0.0; racc = 0.0; rpos = 0.0; rjerk = 0.0; } else { double dt = segs[i].GetValue("time") - segs[i - 1].GetValue("time"); double ldist = Math.Sqrt((lx - plx) * (lx - plx) + (ly - ply) * (ly - ply)); double rdist = Math.Sqrt((rx - prx) * (rx - prx) + (ry - pry) * (ry - pry)); lvel = ldist / dt; rvel = rdist / dt; lacc = (lvel - plvel) / dt; racc = (rvel - prvel) / dt; ljerk = (lacc - placc) / dt; rjerk = (racc - pracc) / dt; lpos += ldist; rpos += rdist; } PathSegment left = new PathSegment(); left.SetValue("time", time); left.SetValue("x", lx); left.SetValue("y", ly); left.SetValue("heading", segs[i].GetValue("heading")); left.SetValue("position", lpos); left.SetValue("velocity", lvel); left.SetValue("acceleration", lacc); left.SetValue("jerk", ljerk); lsegs[i] = left; PathSegment right = new PathSegment(); right.SetValue("time", segs[i].GetValue("time")); right.SetValue("x", rx); right.SetValue("y", ry); right.SetValue("heading", segs[i].GetValue("heading")); right.SetValue("position", rpos); right.SetValue("velocity", rvel); right.SetValue("acceleration", racc); right.SetValue("jerk", rjerk); rsegs[i] = right; plx = lx; ply = ly; prx = rx; pry = ry; plvel = lvel; prvel = rvel; placc = lacc; pracc = racc; } return(result); }
public abstract PathSegment[] GenerateDetailedPath(RobotParams robot, RobotPath path);