Add Clumsy plugins and dual-vehicle fleet sync demo.

Restructure into DiffWheel/MultiWheel folders, add DiffWheelC and MultiWheelC with MovementTests, FleetRemote multi-vehicle manual sync, deploy templates, and documentation. Update dependency paths to D:\MDCS\Release and mirror motor feedback in MotorRoutine for simulation.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-28 15:04:55 +08:00
co-authored by Cursor
parent e5aeae9c33
commit 235c6c70ac
40 changed files with 2750 additions and 99 deletions
+18
View File
@@ -0,0 +1,18 @@
using System;
using MDCSToolBox.Clumsy.AgvInterfaces;
using MDCSToolBox.Clumsy.MotionControllers;
namespace DiffWheelC;
public class AGV : DiffWheelInterface
{
public override AbstractGeometricController GetController()
{
return new ChassisController().Get();
}
public override NaiveMagnetController GetNaiveMagnetController()
{
throw new NotImplementedException("Tutorial DiffWheelC does not implement magnetic tracking.");
}
}
+40
View File
@@ -0,0 +1,40 @@
using ClumsyCore;
using ClumsyCore.Pilot;
using MDCSToolBox.Clumsy.MotionControllers;
using MDCSToolBox.Clumsy.Pilot;
namespace DiffWheelC;
public class ChassisController : MovementDefinition<DiffWheelGeometricController>
{
public float BaseSpeed = Configuration.conf.basicSpeed;
public override DiffWheelGeometricController Get()
{
return new DiffWheelGeometricController
{
Chassis = BasicPilotBase.Chassis,
BaseSpeed = BaseSpeed,
SlowDistance = PilotDefinition.Conf.SlowDistance,
SlowingPow = PilotDefinition.Conf.SlowingPow,
FinishDistance = PilotDefinition.Conf.FinishDistance,
FinishSpeed = PilotDefinition.Conf.FinishSpeed,
FirstThAccuracy = PilotDefinition.Conf.FirstThAccuracy,
NotContinuousAngle = PilotDefinition.Conf.NotContinuousAngle,
FirstRotateSpeedFac = PilotDefinition.Conf.FirstRotateSpeedFac,
FirstRotateMaxSpeed = PilotDefinition.Conf.FirstRotateMaxSpeed,
DebugMode = PilotDefinition.Conf.MotionDebugPrint,
DebugCurvature = PilotDefinition.Conf.DebugCurvature,
MaxRotateAcc = PilotDefinition.Conf.MaxRotateAccCurveLimit,
MaxRotateSpeed = PilotDefinition.Conf.MaxRotateSpeedCurveLimit,
SpeedLimitCurveDiffMin = PilotDefinition.Conf.SpeedLimitCurveDiffMin,
SpeedLimitCurveMin = PilotDefinition.Conf.SpeedLimitCurveMin,
SpeedAccPerSecond = PilotDefinition.Conf.SpeedAccPerSecond,
SpeedDeAccPerSecond = PilotDefinition.Conf.SpeedDeAccPerSecond,
PowerSteeringLookAhead = PilotDefinition.Conf.PowerSteeringLookAhead,
SpeedLookAhead = PilotDefinition.Conf.SpeedLookAhead,
SpeedLookAheadCurveDiff = PilotDefinition.Conf.SpeedLookAheadCurveDiff,
SpeedLookBackCurveDiff = PilotDefinition.Conf.SpeedLookBackCurveDiff,
};
}
}
+45
View File
@@ -0,0 +1,45 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>10</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<OutputPath>..\..\build\Clumsy_diff\</OutputPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.Numerics.Vectors" Version="4.6.1" />
</ItemGroup>
<ItemGroup>
<Reference Include="ClumsyCore">
<HintPath>D:\MDCS\Release\Clumsy\RefClumsyCore.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="ClumsyDance">
<HintPath>D:\MDCS\Release\Clumsy\RefClumsyDance.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="CommonUsage">
<HintPath>D:\MDCS\Release\CommonUsage.dll</HintPath>
</Reference>
<Reference Include="FundamentalLib">
<HintPath>D:\MDCS\Release\deps\RefFundamentalLib.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="LessokajiWeaverUtilities">
<HintPath>D:\MDCS\Release\deps\LessokajiWeaverUtilities.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="MDCSToolBox">
<HintPath>D:\MDCS\Release\MDCSToolBox.dll</HintPath>
</Reference>
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="if not exist $(SolutionDir)build\Clumsy_diff mkdir $(SolutionDir)build\Clumsy_diff&#xD;&#xA;copy /Y D:\MDCS\Release\Clumsy\ClumsyLite.exe $(SolutionDir)build\Clumsy_diff\&#xD;&#xA;copy /Y D:\MDCS\Release\Clumsy\ClumsyLite.deps.json $(SolutionDir)build\Clumsy_diff\&#xD;&#xA;copy /Y D:\MDCS\Release\Clumsy\ClumsyLite.runtimeconfig.json $(SolutionDir)build\Clumsy_diff\&#xD;&#xA;copy /Y D:\MDCS\Release\Clumsy\RefClumsyCore.dll $(SolutionDir)build\Clumsy_diff\&#xD;&#xA;copy /Y D:\MDCS\Release\Clumsy\RefClumsyDance.dll $(SolutionDir)build\Clumsy_diff\&#xD;&#xA;copy /Y D:\MDCS\Release\MDCSToolBox.dll $(SolutionDir)build\Clumsy_diff\&#xD;&#xA;copy /Y D:\MDCS\Release\CommonUsage.dll $(SolutionDir)build\Clumsy_diff\" />
</Target>
</Project>
+76
View File
@@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.Threading;
using ClumsyCore;
using ClumsyCore.Pilot;
using CommonUsage.Chassis;
using MDCSToolBox.Clumsy.Movements;
using MDCSToolBox.Clumsy.Pilot;
namespace DiffWheelC;
public class DiffForwardTest : MovementDefinition
{
public float Speed = 0.2f;
public float DurationSeconds = 2f;
public override IEnumerable<bool> Get()
{
var chassis = (DifferentialChassis)BasicPilotBase.Chassis;
var end = DateTime.Now.AddSeconds(DurationSeconds);
while (DateTime.Now < end)
{
chassis.SendSpeed(Speed, 0);
yield return true;
}
chassis.SendSpeed(0, 0);
}
}
public class DiffRotateTest : MovementDefinition
{
public float AngularSpeed = 30f;
public float DurationSeconds = 2f;
public override IEnumerable<bool> Get()
{
var chassis = (DifferentialChassis)BasicPilotBase.Chassis;
var end = DateTime.Now.AddSeconds(DurationSeconds);
while (DateTime.Now < end)
{
chassis.SendSpeed(0, AngularSpeed);
yield return true;
}
chassis.SendSpeed(0, 0);
}
}
[MovementTest(name = "差速-前进2秒")]
public class DiffForwardMovementTest : MovementTest
{
private DriveTask _task;
public override void Test()
{
_task = new DriveTask(new DiffForwardTest().Get());
_task.Wait();
}
public override void TestStop() => _task?.Stop();
}
[MovementTest(name = "差速-原地旋转2秒")]
public class DiffRotateMovementTest : MovementTest
{
private DriveTask _task;
public override void Test()
{
_task = new DriveTask(new DiffRotateTest().Get());
_task.Wait();
}
public override void TestStop() => _task?.Stop();
}
+10
View File
@@ -0,0 +1,10 @@
using ClumsyCore;
using MDCSToolBox.Clumsy.Pilot.DiffWheel;
namespace DiffWheelC;
public class PilotConfig : DiffWheelPilotConfig
{
[FieldMember(desc = "差速车底盘轮距(mm)")] public float ChassisWidth = 600f;
[FieldMember(desc = "调度IP")] public string SimpleIp = "127.0.0.1";
}
+7
View File
@@ -0,0 +1,7 @@
using MDCSToolBox.Clumsy.Pilot.DiffWheel;
namespace DiffWheelC;
public class PilotDefinition : DiffWheelPilotDefinition<PilotConfig, PilotDefinition>
{
}
+32
View File
@@ -0,0 +1,32 @@
using CartActivator;
namespace DiffWheelM;
[UseManualController(manualController = typeof(Remote))]
[UseLadderLogic(logic = typeof(MotorRoutine), scanInterval = 50)]
public class CartDefinition : CartActivator.CartDefinition
{
[AsUpperIO(desc = "左轮下发速度", timeOutReset = true)]
[Playground]
public float SpeedLeft;
[AsUpperIO(desc = "右轮下发速度", timeOutReset = true)]
[Playground]
public float SpeedRight;
[AsLowerIO(desc = "左轮实际速度")]
[Playground]
public float ActualSpeedLeft;
[AsLowerIO(desc = "右轮实际速度")]
[Playground]
public float ActualSpeedRight;
[AsInitParam(desc = "手动最大轮速(m/s)")]
public float MaxManualSpeed = 0.3f;
public override void Init()
{
Console.WriteLine("[DiffWheelM] Minimal Medulla cart initialized.");
}
}
+31
View File
@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Platforms>AnyCPU</Platforms>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<OutputPath>..\..\build\Medulla\plugins\</OutputPath>
</PropertyGroup>
<ItemGroup>
<Reference Include="CartActivator">
<HintPath>D:\MDCS\Release\Medulla\RefCartActivator.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="MedullaCore">
<HintPath>D:\MDCS\Release\Medulla\RefMedullaCore.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Medulla">
<HintPath>D:\MDCS\Release\Medulla\RefMedulla2.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="FundamentalLib">
<HintPath>D:\MDCS\Release\deps\RefFundamentalLib.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
</Project>
+12
View File
@@ -0,0 +1,12 @@
using CartActivator;
namespace DiffWheelM;
public class MotorRoutine : LadderLogic<CartDefinition>
{
public override void Operation(int iteration)
{
cart.ActualSpeedLeft = cart.SpeedLeft;
cart.ActualSpeedRight = cart.SpeedRight;
}
}
+31
View File
@@ -0,0 +1,31 @@
using CartActivator;
namespace DiffWheelM;
public class Remote : ManualController<CartDefinition>
{
[AsControlItem(name = "速度摇杆", keyboard = "Up,Down,Left,Right", joystick = "Axis0,Axis1")]
public Stick Direction;
[AsControlItem(name = "速度比例", keyboard = "Q,W")]
public Throttle SpeedRatio;
public override void Operation()
{
var maxSpeed = Math.Max(0, cart.MaxManualSpeed);
var speedRatio = Math.Clamp(SpeedRatio.val, 0, 1);
var left = Direction.y - Direction.x;
var right = Direction.y + Direction.x;
var wheelScale = Math.Max(1, Math.Max(Math.Abs(left), Math.Abs(right)));
left = left / wheelScale * maxSpeed * speedRatio;
right = right / wheelScale * maxSpeed * speedRatio;
cart.SpeedLeft = Math.Clamp(left, -maxSpeed, maxSpeed);
cart.SpeedRight = Math.Clamp(right, -maxSpeed, maxSpeed);
statusText = $"L={cart.SpeedLeft:0.000}m/s, R={cart.SpeedRight:0.000}m/s";
}
}