приложил код моей библиотеки оптимизации роботов-м...

Tạo vào: 8 tháng 10, 2026

Trả lời bằng GPT-6 Thinking bởi Chat01

Câu hỏi

sobol.tables

приложил код моей библиотеки оптимизации роботов-манипуляторов - проблема сейчас в том что при включенном режиме transition, который предполагает построение траектории из начальной точки в конечную манипулятор всегда игнорирует конечную точку и траектория каждый раз идёт из начальной точки - которую алгоритм каждый раз идентифицирует правильно до полностью выпрямленного горизонтального положения - то есть начальную точку алгоритм каждый раз узнаёт и оптимизация идёт из неё как и должна - а вот конечную точку какую не поставь - она в любом случае будет проигнорирована и манипулятор всегда будет стремиться выпрямиться в прямую линию горизонта, из-за этой проблемы режим transition с препятствиями не может работать корректно - он просто намертво зависает так как не существует часто траектории обходящей препятствия чтобы манипулятор по итогу выпрямился в горизонталь, такие зависания при принудительном выключении программы сопровождаются ошибками: "C:\Users\maxim>mpiexec -n 1 E:\TEST_AGP\x64\Release\TEST_AGP.exe

Необработанное исключение: System.AccessViolationException: Попытка чтения или записи в защищенную память. Это часто свидетельствует о том, что другая память повреждена.
в TESTAGP.MyForm.BuildPoseFromState(Single* state, Boolean varLen, Single baseLength, PoseSnapshot& pose) в E:\TEST_AGP\MyForm.h:строка 1188
в TESTAGP.MyForm.RunTrajectoryWithAGP() в E:\TEST_AGP\MyForm.h:строка 1456
в TESTAGP.MyForm.RunTrajectoryPlanningMode() в E:\TEST_AGP\MyForm.h:строка 1179
в TESTAGP.MyForm.OnOptimizeClick(Object sender, EventArgs e) в E:\TEST_AGP\MyForm.h:строка 2042
в System.Windows.Forms.Control.OnClick(EventArgs e)
в System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
в System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
в System.Windows.Forms.Control.WndProc(Message& m)
в System.Windows.Forms.ButtonBase.WndProc(Message& m)
в System.Windows.Forms.Button.WndProc(Message& m)
в System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
в System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
в System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
в System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
в System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
в main() в E:\TEST_AGP\MyForm.cpp:строка 20
в mainCRTStartup()

job aborted:
[ranks] message

[0] process exited without calling finalize

---- error analysis -----

[0] on DESKTOP-C1VT6JF
E:\TEST_AGP\x64\Release\TEST_AGP.exe ended prematurely and may have crashed. exit code 0xc0000005" или: "C:\Users\maxim>mpiexec -n 1 E:\TEST_AGP\x64\Release\TEST_AGP.exe

job aborted:
[ranks] message

[0] process exited without calling finalize

---- error analysis -----

[0] on DESKTOP-C1VT6JF
E:\TEST_AGP\x64\Release\TEST_AGP.exe ended prematurely and may have crashed. exit code 0xcfffffff", при этом режим позиционирования всегда работает корректно и с препятствиями и без - то есть проблема специфичная именно для transition режима, также стоит сказать, что логика в общем скорее всего верна почти везде так как не так давно алгоритм корректно работал и в режиме transition, в том числе с препятствиями, скорее всего есть скрытый баг или проблемы с передачей конечного положения куда нужно прийти или уничтожение этого конечного положения или его зануление - что вероятно, т. к. полностью выпрямленный горизонтально манипулятор соответствует занулению всех обобщённых координат, вот код демо для понимания контекста как происходят вызовы: "#pragma once

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <cmath>
#include <vector>
#include <memory>

#include <kdl/chain.hpp>
#include <kdl/jntarray.hpp>
#include <kdl/frames.hpp>
#include <kdl/joint.hpp>
#include <kdl/segment.hpp>
#include <trac_ik/trac_ik.hpp>

using namespace System;
using namespace System::Drawing;
using namespace System::Windows::Forms;
using namespace System::Collections::Generic;
using namespace System::Drawing::Drawing2D;
using namespace System::Runtime::CompilerServices;
using namespace System::Runtime::InteropServices;

typedef void(__cdecl* P_MANIP)(int, bool, float, float, float, float, int, float, float, unsigned int, float, float, const float*, int, float**, float*, float*, float*, float*, size_t*, float*, int, const float*);
typedef void(__cdecl* P_START)(int, bool, float, float, float, float, int, float, float, unsigned int, float, float, const float*, int, int, const float*, const float*);
typedef void(__cdecl* P_BUILD_TRAJECTORY)(int, bool, float, const float*, const float*, int, float, float, unsigned int, float, float, const float*, int, float**, int*, size_t*);

class TracIkRunner final
{
private:
int nSegments_;
unsigned int nJoints_;
double baseLength_;
double maxTheta_;
double maxTime_;
double eps_;

text
KDL::Chain chain_; KDL::JntArray qMin_; KDL::JntArray qMax_; KDL::JntArray qInit_; KDL::JntArray qOut_; std::unique_ptr<trac_ik::TRAC_IK> solver_; LARGE_INTEGER frequency_; static double WrapPi(double a) { const double pi = 3.1415926535897932384626433832795; const double twoPi = 2.0 * pi; while (a > pi) a -= twoPi; while (a < -pi) a += twoPi; return a; }

public:
TracIkRunner(
int nSegments,
double baseLength,
double maxTheta,
double maxTime,
double eps)
:
nSegments_(nSegments),
nJoints_(0),
baseLength_(baseLength),
maxTheta_(maxTheta),
maxTime_(maxTime),
eps_(eps)
{
for (int i = 0; i < nSegments_; ++i)
{
chain_.addSegment(
KDL::Segment(
KDL::Joint(KDL::Joint::RotZ),
KDL::Frame(
KDL::Vector(
baseLength_,
0.0,
0.0
)
)
)
);
}

text
nJoints_ = chain_.getNrOfJoints(); qMin_.resize(nJoints_); qMax_.resize(nJoints_); qInit_.resize(nJoints_); qOut_.resize(nJoints_); for (unsigned int i = 0; i < nJoints_; ++i) { qMin_(i) = -maxTheta_; qMax_(i) = maxTheta_; qInit_(i) = 0.0; qOut_(i) = 0.0; } solver_ = std::make_unique<trac_ik::TRAC_IK>( chain_, qMin_, qMax_, maxTime_, eps_, trac_ik::SolveType::Speed ); QueryPerformanceFrequency(&frequency_); } TracIkRunner(const TracIkRunner&) = delete; TracIkRunner& operator=(const TracIkRunner&) = delete; bool Matches( int nSegments, double baseLength, double maxTheta, double maxTime, double eps) const { return nSegments_ == nSegments && baseLength_ == baseLength && maxTheta_ == maxTheta && maxTime_ == maxTime && eps_ == eps; } bool Solve( float targetX, float targetY, float targetAngle, double& outBestF, double& outBestX, double& outBestY, double& outBestA, double& outMillis) { for (unsigned int i = 0; i < nJoints_; ++i) { qInit_(i) = 0.0; qOut_(i) = 0.0; } KDL::Frame target( KDL::Rotation::RotZ( static_cast<double>(targetAngle) ), KDL::Vector( static_cast<double>(targetX), static_cast<double>(targetY), 0.0 ) ); KDL::Twist tolerances( KDL::Vector( eps_, eps_, 0.0 ), KDL::Vector( 0.0, 0.0, eps_ ) ); LARGE_INTEGER t0; LARGE_INTEGER t1; QueryPerformanceCounter(&t0); const int result = solver_->CartToJnt( qInit_, target, qOut_, tolerances ); QueryPerformanceCounter(&t1); outMillis = 1.0e3 * static_cast<double>( t1.QuadPart - t0.QuadPart ) / static_cast<double>( frequency_.QuadPart ); double x = 0.0; double y = 0.0; double phi = 0.0; for (unsigned int i = 0; i < nJoints_; ++i) { phi += qOut_(i); x += baseLength_ * std::cos(phi); y += baseLength_ * std::sin(phi); } const double dx = x - static_cast<double>(targetX); const double dy = y - static_cast<double>(targetY); const double da = WrapPi( phi - static_cast<double>(targetAngle) ); outBestF = std::sqrt( dx * dx + dy * dy + da * da ); outBestX = x; outBestY = y; outBestA = WrapPi(phi); return result >= 0; } const KDL::JntArray& GetSolution() const { return qOut_; }

};

namespace TESTAGP
{
public enum class DemoMode { Positioning = 0, TrajectoryPlanning = 1 };
public enum class DragHandle { None = 0, Target = 1, Start = 2, AngleTarget = 3, AngleStart = 4 };

text
public ref class PoseSnapshot sealed { public: PoseSnapshot(int n) { Angles = gcnew array<float>(n); Lengths = gcnew array<float>(n); EndX = EndY = EndA = BestF = 0.0f; Iterations = 0; AchievedEps = Millis = 0.0f; } array<float>^ Angles; array<float>^ Lengths; float EndX, EndY, EndA, BestF; int Iterations; float AchievedEps, Millis; }; public ref class MyForm sealed : public Form { public: MyForm(HMODULE hLib) : hLib(hLib), tracIkRunner(nullptr) { this->SetStyle(ControlStyles::AllPaintingInWmPaint | ControlStyles::UserPaint | ControlStyles::OptimizedDoubleBuffer, true); this->Text = L"AGP Manipulator 2D"; this->ClientSize = System::Drawing::Size(1200, 800); this->Resize += gcnew EventHandler(this, &MyForm::OnResize); this->MouseDown += gcnew MouseEventHandler(this, &MyForm::OnMouseDownPoint); this->MouseMove += gcnew MouseEventHandler(this, &MyForm::OnMouseMovePoint); this->MouseUp += gcnew MouseEventHandler(this, &MyForm::OnMouseUpPoint); fManip = (P_MANIP)GetProcAddress(hLib, "AGP_Manip2D"); pStart = (P_START)GetProcAddress(hLib, "AgpStartManipND"); pBuildTrajectory = (P_BUILD_TRAJECTORY)GetProcAddress(hLib, "AGP_BuildTransitionTrajectory"); angles = gcnew List<float>(8); lengths = gcnew List<float>(8); obstacleX = gcnew List<float>(4); obstacleY = gcnew List<float>(4); obstacleHalf = gcnew List<float>(4); plannedPoses = gcnew List<PoseSnapshot^>(); animationFrames = gcnew List<PoseSnapshot^>(); trajectoryPathWorld = gcnew List<PointF>(); demoMode = DemoMode::Positioning; InitGraphicsResources(); InitAnimation(); InitUI(); ResetRandomConfig(); SetDefaultStartPoint(true); UpdateTrajectoryUiState(); } ~MyForm() { this->!MyForm(); } !MyForm() { if (tracIkRunner != nullptr) { delete tracIkRunner; tracIkRunner = nullptr; } } private: literal float ObstacleClearance = 0.05f; literal float PI = 3.14159265358979323846f; literal float TWO_PI = 6.28318530717958647692f; literal int AnimationFramesPerSegment = 10; literal int AnimationIntervalMs = 16; literal float TransitionLengthEnergyWeight = 0.35f; literal float TransitionPrefixEnergyWeight = 0.175f; ComboBox^ cbDemoMode; ComboBox^ cbBackend; CheckBox^ cbVarLen; NumericUpDown^ nudMaxTheta; NumericUpDown^ nudBaseLength; NumericUpDown^ nudStretchFactor; NumericUpDown^ nudTargetX; NumericUpDown^ nudTargetY; NumericUpDown^ nudTargetAngle; NumericUpDown^ nudStartX; NumericUpDown^ nudStartY; NumericUpDown^ nudStartAngle; NumericUpDown^ nudMaxIter; NumericUpDown^ nudR; TextBox^ txtEps; float currentEps = 1e-9f; Button^ btnAdd; Button^ btnRem; Button^ btnOptimize; Button^ btnGenerateObstacles; Button^ btnClearObstacles; Label^ lblInfo; Label^ lblStartX; Label^ lblStartY; Label^ lblTargetAngle; Label^ lblStartAngle; P_BUILD_TRAJECTORY pBuildTrajectory; HMODULE hLib; P_MANIP fManip; P_START pStart; TracIkRunner* tracIkRunner; Pen^ obstaclePen; Pen^ obstacleMarginPen; SolidBrush^ obstacleBrush; Pen^ wallPen; Pen^ dashedPen; Pen^ targetPen; Pen^ startPen; Pen^ pathPen; Pen^ penRod; SolidBrush^ jointBrush; SolidBrush^ waypointBrush; HatchBrush^ wallHatchBrush; Pen^ angleTargetPen; Pen^ angleStartPen; System::Drawing::Font^ uiFontBold11; System::Drawing::Font^ uiFontTextBox; System::Drawing::Font^ uiFontBold10; Timer^ animationTimer; DemoMode demoMode; int nSegments = 1; bool variableLengths = false; List<float>^ angles; List<float>^ lengths; List<float>^ obstacleX; List<float>^ obstacleY; List<float>^ obstacleHalf; List<PoseSnapshot^>^ plannedPoses; List<PoseSnapshot^>^ animationFrames; List<PointF>^ trajectoryPathWorld; UInt32 rngState = 0xA5C39E0Du; DragHandle activeDragHandle = DragHandle::None; bool updatingFromMouse = false; bool syncingDefaultStartPoint = false; bool startPointCustomized = false; int animationFrameIndex = 0; bool animationRunning = false; bool angleTargetDrag = false; bool angleStartDrag = false; static float WrapPi(float a) { while (a > PI) a -= TWO_PI; while (a < -PI) a += TWO_PI; return a; } static float WrappedDelta(float from, float to) { return WrapPi(to - from); } static float LerpWrappedAngle(float from, float to, float t) { return WrapPi(from + t * WrappedDelta(from, to)); } static float DistanceSquared(PointF a, PointF b) { float dx = a.X - b.X; float dy = a.Y - b.Y; return dx * dx + dy * dy; } [MethodImpl(MethodImplOptions::AggressiveInlining)] PointF GetBasePoint() { int drawAreaTop = 180; int drawAreaHeight = this->ClientSize.Height - 180; int leftWallX = this->ClientSize.Width * 25 / 100; return PointF((float)leftWallX, (float)(drawAreaTop + drawAreaHeight / 2)); } TracIkRunner* GetTracIkRunner() { const double maxTime = 0.002; const double baseLengthValue = static_cast<double>((float)nudBaseLength->Value); const double maxThetaValue = static_cast<double>((float)nudMaxTheta->Value); const double epsValue = static_cast<double>(currentEps); if (tracIkRunner == nullptr || !tracIkRunner->Matches( nSegments, baseLengthValue, maxThetaValue, maxTime, epsValue)) { if (tracIkRunner != nullptr) { delete tracIkRunner; tracIkRunner = nullptr; } tracIkRunner = new TracIkRunner( nSegments, baseLengthValue, maxThetaValue, maxTime, epsValue ); } return tracIkRunner; } void InitGraphicsResources() { uiFontBold11 = gcnew System::Drawing::Font("Yu Gothic UI", 11, FontStyle::Bold); uiFontBold10 = gcnew System::Drawing::Font("Yu Gothic UI", 10, FontStyle::Bold); uiFontTextBox = gcnew System::Drawing::Font("Yu Gothic UI", 11, FontStyle::Bold); wallPen = gcnew Pen(Color::Black, 2.0f); dashedPen = gcnew Pen(Color::Black, 2.0f); dashedPen->DashStyle = DashStyle::Dash; targetPen = gcnew Pen(Color::Green, 3.0f); targetPen->DashStyle = DashStyle::Dot; startPen = gcnew Pen(Color::FromArgb(255, 140, 0), 3.0f); startPen->DashStyle = DashStyle::Dot; pathPen = gcnew Pen(Color::FromArgb(40, 90, 180), 2.5f); pathPen->DashStyle = DashStyle::Dash; penRod = gcnew Pen(Color::Red, 6.0f); jointBrush = gcnew SolidBrush(Color::Blue); waypointBrush = gcnew SolidBrush(Color::FromArgb(40, 90, 180)); wallHatchBrush = gcnew HatchBrush(HatchStyle::BackwardDiagonal, Color::LightGray, Color::White); obstaclePen = gcnew Pen(Color::FromArgb(90, 30, 30), 2.0f); obstacleMarginPen = gcnew Pen(Color::FromArgb(215, 140, 0), 2.0f); obstacleMarginPen->DashStyle = DashStyle::Dash; obstacleBrush = gcnew SolidBrush(Color::FromArgb(180, 120, 120, 120)); angleTargetPen = gcnew Pen(Color::Red, 2.0f); angleTargetPen->DashStyle = DashStyle::Dash; angleStartPen = gcnew Pen(Color::DarkOrange, 2.0f); angleStartPen->DashStyle = DashStyle::Dash; } void InitAnimation() { animationTimer = gcnew Timer(); animationTimer->Interval = AnimationIntervalMs; animationTimer->Tick += gcnew EventHandler(this, &MyForm::OnAnimationTick); } void InitUI() { cbDemoMode = gcnew ComboBox(); cbDemoMode->Location = Point(920, 20); cbDemoMode->Width = 260; cbDemoMode->Height = 28; cbDemoMode->DropDownStyle = ComboBoxStyle::DropDownList; cbDemoMode->Font = uiFontBold11; cbDemoMode->BackColor = SystemColors::Info; cbDemoMode->FlatStyle = FlatStyle::Flat; cbDemoMode->Items->Add(L"Позиционирование"); cbDemoMode->Items->Add(L"Планирование траектории"); cbDemoMode->SelectedIndex = 0; cbDemoMode->SelectedIndexChanged += gcnew EventHandler(this, &MyForm::OnDemoModeChanged); this->Controls->Add(cbDemoMode); cbBackend = gcnew ComboBox(); cbBackend->Location = Point(920, 54); cbBackend->Width = 260; cbBackend->Height = 28; cbBackend->DropDownStyle = ComboBoxStyle::DropDownList; cbBackend->Font = uiFontBold11; cbBackend->BackColor = SystemColors::Info; cbBackend->FlatStyle = FlatStyle::Flat; cbBackend->Items->Add(L"AGP"); cbBackend->Items->Add(L"TRAC-IK"); cbBackend->SelectedIndex = 0; cbBackend->SelectedIndexChanged += gcnew EventHandler(this, &MyForm::OnBackendChanged); this->Controls->Add(cbBackend); Label^ L = gcnew Label(); L->Text = L"Макс. угол (рад.)"; L->Location = Point(20, 20); L->Width = 200; L->Font = uiFontBold11; this->Controls->Add(L); nudMaxTheta = gcnew NumericUpDown(); nudMaxTheta->Location = Point(20, 52); nudMaxTheta->Width = 200; nudMaxTheta->DecimalPlaces = 3; nudMaxTheta->Minimum = Decimal(0.01); nudMaxTheta->Maximum = Decimal(3.14159); nudMaxTheta->Value = Decimal(2.0); nudMaxTheta->Font = uiFontTextBox; nudMaxTheta->ValueChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(nudMaxTheta); L = gcnew Label(); L->Text = L"Базовая длина"; L->Location = Point(245, 20); L->Width = 200; L->Font = uiFontBold11; this->Controls->Add(L); nudBaseLength = gcnew NumericUpDown(); nudBaseLength->Location = Point(245, 52); nudBaseLength->Width = 200; nudBaseLength->DecimalPlaces = 2; nudBaseLength->Minimum = Decimal(0.5); nudBaseLength->Maximum = Decimal(2.0); nudBaseLength->Value = Decimal(1.0); nudBaseLength->Font = uiFontTextBox; nudBaseLength->ValueChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(nudBaseLength); L = gcnew Label(); L->Text = L"Макс. коэфф. растяжения/сжатия"; L->Location = Point(470, 20); L->Width = 300; L->Font = uiFontBold11; this->Controls->Add(L); nudStretchFactor = gcnew NumericUpDown(); nudStretchFactor->Location = Point(470, 52); nudStretchFactor->Width = 200; nudStretchFactor->DecimalPlaces = 2; nudStretchFactor->Minimum = Decimal(1.0); nudStretchFactor->Maximum = Decimal(1.5); nudStretchFactor->Increment = Decimal(0.01); nudStretchFactor->Value = Decimal(1.5); nudStretchFactor->Font = uiFontTextBox; nudStretchFactor->ValueChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(nudStretchFactor); cbVarLen = gcnew CheckBox(); cbVarLen->Text = L"Переменные длины"; cbVarLen->Location = Point(695, 52); cbVarLen->Width = 200; cbVarLen->Checked = false; cbVarLen->Font = uiFontBold11; cbVarLen->CheckedChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(cbVarLen); L = gcnew Label(); L->Text = L"Цель X"; L->Location = Point(20, 107); L->Width = 200; L->Font = uiFontBold11; this->Controls->Add(L); nudTargetX = gcnew NumericUpDown(); nudTargetX->Location = Point(20, 139); nudTargetX->Width = 200; nudTargetX->DecimalPlaces = 2; nudTargetX->Minimum = Decimal(-10.0); nudTargetX->Maximum = Decimal(10.0); nudTargetX->Value = Decimal(2.5); nudTargetX->Font = uiFontTextBox; nudTargetX->ValueChanged += gcnew EventHandler(this, &MyForm::OnTargetChanged); this->Controls->Add(nudTargetX); L = gcnew Label(); L->Text = L"Цель Y"; L->Location = Point(245, 107); L->Width = 200; L->Font = uiFontBold11; this->Controls->Add(L); nudTargetY = gcnew NumericUpDown(); nudTargetY->Location = Point(245, 139); nudTargetY->Width = 200; nudTargetY->DecimalPlaces = 2; nudTargetY->Minimum = Decimal(-10.0); nudTargetY->Maximum = Decimal(10.0); nudTargetY->Value = Decimal(-1.0); nudTargetY->Font = uiFontTextBox; nudTargetY->ValueChanged += gcnew EventHandler(this, &MyForm::OnTargetChanged); this->Controls->Add(nudTargetY); lblTargetAngle = gcnew Label(); lblTargetAngle->Text = L"Цель угол (рад.)"; lblTargetAngle->Location = Point(20, 194); lblTargetAngle->Width = 200; lblTargetAngle->Font = uiFontBold11; this->Controls->Add(lblTargetAngle); nudTargetAngle = gcnew NumericUpDown(); nudTargetAngle->Location = Point(20, 226); nudTargetAngle->Width = 200; nudTargetAngle->DecimalPlaces = 3; nudTargetAngle->Minimum = Decimal(-1000); nudTargetAngle->Maximum = Decimal(1000); nudTargetAngle->Increment = Decimal(0.1); nudTargetAngle->Value = Decimal(0); nudTargetAngle->Font = uiFontTextBox; nudTargetAngle->ValueChanged += gcnew EventHandler(this, &MyForm::OnAngleChanged); this->Controls->Add(nudTargetAngle); L = gcnew Label(); L->Text = L"Надежность (r)"; L->Location = Point(470, 107); L->Width = 200; L->Font = uiFontBold11; this->Controls->Add(L); nudR = gcnew NumericUpDown(); nudR->Location = Point(470, 139); nudR->Width = 200; nudR->DecimalPlaces = 2; nudR->Minimum = Decimal(1.0); nudR->Maximum = Decimal(20.0); nudR->Value = Decimal(1.05); nudR->Font = uiFontTextBox; nudR->ValueChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(nudR); L = gcnew Label(); L->Text = L"Точность"; L->Location = Point(695, 107); L->Width = 100; L->Font = uiFontBold11; this->Controls->Add(L); txtEps = gcnew TextBox(); txtEps->Location = Point(695, 139); txtEps->Width = 80; txtEps->Font = uiFontTextBox; txtEps->Text = L"1E-09"; txtEps->TextChanged += gcnew EventHandler(this, &MyForm::OnEpsTextChanged); this->Controls->Add(txtEps); Button^ btnEpsUp = gcnew Button(); btnEpsUp->Text = L"×10"; btnEpsUp->Location = Point(780, 139); btnEpsUp->Width = 32; btnEpsUp->Height = 26; btnEpsUp->Font = uiFontBold11; btnEpsUp->TextAlign = ContentAlignment::TopRight; btnEpsUp->Padding = System::Windows::Forms::Padding(0, 0, 2, 3); btnEpsUp->Click += gcnew EventHandler(this, &MyForm::OnEpsOrderUp); this->Controls->Add(btnEpsUp); Button^ btnEpsDown = gcnew Button(); btnEpsDown->Text = L"÷10"; btnEpsDown->Location = Point(816, 139); btnEpsDown->Width = 32; btnEpsDown->Height = 26; btnEpsDown->Font = uiFontBold11; btnEpsDown->TextAlign = ContentAlignment::TopRight; btnEpsDown->Padding = System::Windows::Forms::Padding(0, 0, 2, 3); btnEpsDown->Click += gcnew EventHandler(this, &MyForm::OnEpsOrderDown); this->Controls->Add(btnEpsDown); L = gcnew Label(); L->Text = L"Макс. итераций"; L->Location = Point(860, 107); L->Width = 130; L->Font = uiFontBold11; this->Controls->Add(L); nudMaxIter = gcnew NumericUpDown(); nudMaxIter->Location = Point(860, 139); nudMaxIter->Width = 120; nudMaxIter->Minimum = 10; nudMaxIter->Maximum = 500000; nudMaxIter->Value = 1000; nudMaxIter->Font = uiFontTextBox; nudMaxIter->Increment = 100; nudMaxIter->ValueChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(nudMaxIter); btnAdd = gcnew Button(); btnAdd->Text = L"+ Звено"; btnAdd->Location = Point(465, 211); btnAdd->Width = 90; btnAdd->Height = 35; btnAdd->BackColor = SystemColors::Info; btnAdd->Cursor = Cursors::Hand; btnAdd->FlatAppearance->BorderColor = Color::FromArgb(64, 64, 64); btnAdd->FlatAppearance->BorderSize = 3; btnAdd->FlatAppearance->MouseDownBackColor = Color::FromArgb(128, 128, 255); btnAdd->FlatAppearance->MouseOverBackColor = Color::FromArgb(192, 192, 255); btnAdd->FlatStyle = FlatStyle::Flat; btnAdd->Font = uiFontBold11; btnAdd->ForeColor = SystemColors::ControlDarkDark; btnAdd->Click += gcnew EventHandler(this, &MyForm::OnAddClick); this->Controls->Add(btnAdd); btnRem = gcnew Button(); btnRem->Text = L"- Звено"; btnRem->Location = Point(560, 211); btnRem->Width = 90; btnRem->Height = 35; btnRem->BackColor = SystemColors::Info; btnRem->Cursor = Cursors::Hand; btnRem->FlatAppearance->BorderColor = Color::FromArgb(64, 64, 64); btnRem->FlatAppearance->BorderSize = 3; btnRem->FlatAppearance->MouseDownBackColor = Color::FromArgb(128, 128, 255); btnRem->FlatAppearance->MouseOverBackColor = Color::FromArgb(192, 192, 255); btnRem->FlatStyle = FlatStyle::Flat; btnRem->Font = uiFontBold11; btnRem->ForeColor = SystemColors::ControlDarkDark; btnRem->Click += gcnew EventHandler(this, &MyForm::OnRemClick); this->Controls->Add(btnRem); btnOptimize = gcnew Button(); btnOptimize->Text = L"Оптимизировать"; btnOptimize->Location = Point(680, 211); btnOptimize->Width = 150; btnOptimize->Height = 35; btnOptimize->BackColor = SystemColors::Info; btnOptimize->Cursor = Cursors::Hand; btnOptimize->FlatAppearance->BorderColor = Color::FromArgb(64, 64, 64); btnOptimize->FlatAppearance->BorderSize = 3; btnOptimize->FlatAppearance->MouseDownBackColor = Color::FromArgb(128, 128, 255); btnOptimize->FlatAppearance->MouseOverBackColor = Color::FromArgb(192, 192, 255); btnOptimize->FlatStyle = FlatStyle::Flat; btnOptimize->Font = uiFontBold11; btnOptimize->ForeColor = SystemColors::ControlDarkDark; btnOptimize->Click += gcnew EventHandler(this, &MyForm::OnOptimizeClick); this->Controls->Add(btnOptimize); btnGenerateObstacles = gcnew Button(); btnGenerateObstacles->Location = Point(465, 257); btnGenerateObstacles->Width = 365; btnGenerateObstacles->Height = 35; btnGenerateObstacles->BackColor = SystemColors::Info; btnGenerateObstacles->Cursor = Cursors::Hand; btnGenerateObstacles->FlatAppearance->BorderColor = Color::FromArgb(64, 64, 64); btnGenerateObstacles->FlatAppearance->BorderSize = 3; btnGenerateObstacles->FlatAppearance->MouseDownBackColor = Color::FromArgb(128, 128, 255); btnGenerateObstacles->FlatAppearance->MouseOverBackColor = Color::FromArgb(192, 192, 255); btnGenerateObstacles->FlatStyle = FlatStyle::Flat; btnGenerateObstacles->Font = uiFontBold11; btnGenerateObstacles->ForeColor = SystemColors::ControlDarkDark; btnGenerateObstacles->Click += gcnew EventHandler(this, &MyForm::OnGenerateObstaclesClick); this->Controls->Add(btnGenerateObstacles); btnClearObstacles = gcnew Button(); btnClearObstacles->Location = Point(465, 304); btnClearObstacles->Width = 365; btnClearObstacles->Height = 35; btnClearObstacles->BackColor = SystemColors::Info; btnClearObstacles->Cursor = Cursors::Hand; btnClearObstacles->FlatAppearance->BorderColor = Color::FromArgb(64, 64, 64); btnClearObstacles->FlatAppearance->BorderSize = 3; btnClearObstacles->FlatAppearance->MouseDownBackColor = Color::FromArgb(128, 128, 255); btnClearObstacles->FlatAppearance->MouseOverBackColor = Color::FromArgb(192, 192, 255); btnClearObstacles->FlatStyle = FlatStyle::Flat; btnClearObstacles->Font = uiFontBold11; btnClearObstacles->ForeColor = SystemColors::ControlDarkDark; btnClearObstacles->Text = L"Очистить"; btnClearObstacles->Click += gcnew EventHandler(this, &MyForm::OnClearObstaclesClick); this->Controls->Add(btnClearObstacles); lblInfo = gcnew Label(); lblInfo->Location = Point(835, 194); lblInfo->Size = System::Drawing::Size(275, 145); lblInfo->BorderStyle = BorderStyle::FixedSingle; lblInfo->Font = uiFontBold10; this->Controls->Add(lblInfo); lblStartX = gcnew Label(); lblStartX->Text = L"Начало X"; lblStartX->Location = Point(20, 272); lblStartX->Width = 200; lblStartX->Font = uiFontBold11; this->Controls->Add(lblStartX); nudStartX = gcnew NumericUpDown(); nudStartX->Location = Point(20, 304); nudStartX->Width = 200; nudStartX->DecimalPlaces = 2; nudStartX->Minimum = Decimal(-10.0); nudStartX->Maximum = Decimal(10.0); nudStartX->Value = Decimal(1.25); nudStartX->Font = uiFontTextBox; nudStartX->ValueChanged += gcnew EventHandler(this, &MyForm::OnStartPointChanged); this->Controls->Add(nudStartX); lblStartY = gcnew Label(); lblStartY->Text = L"Начало Y"; lblStartY->Location = Point(245, 272); lblStartY->Width = 200; lblStartY->Font = uiFontBold11; this->Controls->Add(lblStartY); nudStartY = gcnew NumericUpDown(); nudStartY->Location = Point(245, 304); nudStartY->Width = 200; nudStartY->DecimalPlaces = 2; nudStartY->Minimum = Decimal(-10.0); nudStartY->Maximum = Decimal(10.0); nudStartY->Value = Decimal(-0.5); nudStartY->Font = uiFontTextBox; nudStartY->ValueChanged += gcnew EventHandler(this, &MyForm::OnStartPointChanged); this->Controls->Add(nudStartY); lblStartAngle = gcnew Label(); lblStartAngle->Text = L"Нач. угол (рад.)"; lblStartAngle->Location = Point(20, 340); lblStartAngle->Width = 200; lblStartAngle->Font = uiFontBold11; this->Controls->Add(lblStartAngle); nudStartAngle = gcnew NumericUpDown(); nudStartAngle->Location = Point(20, 372); nudStartAngle->Width = 200; nudStartAngle->DecimalPlaces = 3; nudStartAngle->Minimum = Decimal(-1000); nudStartAngle->Maximum = Decimal(1000); nudStartAngle->Increment = Decimal(0.1); nudStartAngle->Value = Decimal(0); nudStartAngle->Font = uiFontTextBox; nudStartAngle->ValueChanged += gcnew EventHandler(this, &MyForm::OnStartAngleChanged); this->Controls->Add(nudStartAngle); UpdateBackendUiState(); UpdateTrajectoryUiState(); } void UpdateBackendUiState() { bool tracIkSelected = (cbBackend->SelectedIndex == 1); bool obstaclesEnabled = !tracIkSelected; btnGenerateObstacles->Enabled = obstaclesEnabled; btnClearObstacles->Enabled = obstaclesEnabled; if (tracIkSelected) { btnGenerateObstacles->Text = L"Препятствия отключены"; btnGenerateObstacles->ForeColor = Color::Gold; btnGenerateObstacles->BackColor = SystemColors::Control; btnClearObstacles->BackColor = SystemColors::Control; if (obstacleX->Count > 0) { obstacleX->Clear(); obstacleY->Clear(); obstacleHalf->Clear(); ClearTrajectoryCache(); this->Invalidate(); } } else { btnGenerateObstacles->Text = L"Сгенерировать препятствия"; btnGenerateObstacles->ForeColor = SystemColors::ControlDarkDark; btnGenerateObstacles->BackColor = SystemColors::Info; btnClearObstacles->BackColor = SystemColors::Info; } } void UpdateTrajectoryUiState() { bool trajectoryMode = IsTrajectoryMode(); lblStartX->Visible = trajectoryMode; lblStartY->Visible = trajectoryMode; nudStartX->Visible = trajectoryMode; nudStartY->Visible = trajectoryMode; lblStartX->Enabled = trajectoryMode; lblStartY->Enabled = trajectoryMode; nudStartX->Enabled = trajectoryMode; nudStartY->Enabled = trajectoryMode; if (trajectoryMode) { lblStartAngle->Location = Point(245, 194); lblStartAngle->Width = 200; nudStartAngle->Location = Point(245, 226); nudStartAngle->Width = 200; lblStartAngle->Visible = true; nudStartAngle->Visible = true; lblStartAngle->Enabled = true; nudStartAngle->Enabled = true; } else { lblStartAngle->Location = Point(20, 340); lblStartAngle->Width = 200; nudStartAngle->Location = Point(20, 372); nudStartAngle->Width = 200; lblStartAngle->Visible = false; nudStartAngle->Visible = false; lblStartAngle->Enabled = false; nudStartAngle->Enabled = false; } if (!trajectoryMode) { ClearTrajectoryCache(); nudStartAngle->Value = Decimal(0); } this->Invalidate(); } void ResetRandomConfig() { nSegments = 1; angles->Clear(); lengths->Clear(); obstacleX->Clear(); obstacleY->Clear(); obstacleHalf->Clear(); angles->Add(0.0f); lengths->Add((float)nudBaseLength->Value); variableLengths = false; ClearTrajectoryCache(); this->Invalidate(); } void ClearTrajectoryCache() { StopAnimation(); plannedPoses->Clear(); animationFrames->Clear(); trajectoryPathWorld->Clear(); } void StopAnimation() { if (animationTimer) animationTimer->Stop(); animationFrameIndex = 0; animationRunning = false; } void ClearObstacles() { obstacleX->Clear(); obstacleY->Clear(); obstacleHalf->Clear(); ClearTrajectoryCache(); this->Invalidate(); } [MethodImpl(MethodImplOptions::AggressiveInlining)] float Rand01() { rngState ^= rngState << 13; rngState ^= rngState >> 17; rngState ^= rngState << 5; return (float)(rngState) * 2.3283064e-10f; } [MethodImpl(MethodImplOptions::AggressiveInlining)] float Lerp(float a, float b, float t) { return a + (b - a) * t; } [MethodImpl(MethodImplOptions::AggressiveInlining)] bool IsTrajectoryMode() { return demoMode == DemoMode::TrajectoryPlanning; } void SetDefaultStartPoint(bool forceResetCustomization) { if (forceResetCustomization) startPointCustomized = false; if (startPointCustomized) return; syncingDefaultStartPoint = true; nudStartX->Value = Decimal((double)((float)nudTargetX->Value * 0.5f)); nudStartY->Value = Decimal((double)((float)nudTargetY->Value * 0.5f)); syncingDefaultStartPoint = false; } array<float>^ BuildObstacleBuffer() { int count = obstacleX->Count; array<float>^ data = gcnew array<float>(count * 3); for (int i = 0; i < count; ++i) { data[3 * i] = obstacleX[i]; data[3 * i + 1] = obstacleY[i]; data[3 * i + 2] = obstacleHalf[i]; } return data; } void GenerateRandomObstacles() { obstacleX->Clear(); obstacleY->Clear(); obstacleHalf->Clear(); bool varLen = cbVarLen->Checked; float baseLength = (float)nudBaseLength->Value; float stretchFactor = (float)nudStretchFactor->Value; float tx = (float)nudTargetX->Value; float ty = (float)nudTargetY->Value; float dist = (float)Math::Sqrt(tx * tx + ty * ty); if (dist <= 1e-6f) { ClearTrajectoryCache(); this->Invalidate(); return; } float maxReach = nSegments * (varLen ? baseLength * stretchFactor : baseLength); float slack = maxReach - dist; float halfMin = Math::Max(0.14f * baseLength, 0.12f); float halfMax = Math::Min(0.26f * baseLength + 0.05f * (slack / (baseLength + 1e-6f)), 0.32f); if (halfMax < halfMin + 0.03f) halfMax = halfMin + 0.03f; float alongMargin = Math::Max(0.55f * baseLength, 1.5f * (halfMax + ObstacleClearance)); alongMargin = Math::Max(alongMargin, 0.35f); float usableLen = dist - 2.0f * alongMargin; int obstacleCountToCreate = 2 + (int)(Rand01() * 3.0f); if (nSegments == 2 && obstacleCountToCreate > 3) obstacleCountToCreate = 3; if (slack < 0.35f * baseLength && obstacleCountToCreate > 2) obstacleCountToCreate = 2; while (obstacleCountToCreate > 2) { float gapTest = usableLen / (obstacleCountToCreate + 1); if (gapTest >= 2.2f * halfMax) break; --obstacleCountToCreate; } float ux = tx / dist; float uy = ty / dist; float nx = -uy; float ny = ux; float gap = usableLen / (obstacleCountToCreate + 1); float firstSide = (Rand01() < 0.5f) ? -1.0f : 1.0f; for (int i = 0; i < obstacleCountToCreate; ++i) { float nominalS = alongMargin + gap * (i + 1); float jitter = (Rand01() - 0.5f) * gap * 0.18f; float s = nominalS + jitter; float half = halfMin + (halfMax - halfMin) * Rand01(); float side = ((i & 1) == 0) ? firstSide : -firstSide; float offsetMag = half * (0.18f + 0.28f * Rand01()); obstacleX->Add(ux * s + nx * side * offsetMag); obstacleY->Add(uy * s + ny * side * offsetMag); obstacleHalf->Add(half); } ClearTrajectoryCache(); this->Invalidate(); } void UpdateEpsDisplay() { String^ value = currentEps.ToString("E3", System::Globalization::CultureInfo::InvariantCulture); if (txtEps->Text != value) txtEps->Text = value; } void OnEpsTextChanged(Object^ sender, EventArgs^ e) { float val; if (float::TryParse(txtEps->Text, System::Globalization::NumberStyles::Float, System::Globalization::CultureInfo::InvariantCulture, val)) { if (val < 1e-9f) val = 1e-9f; if (val > 1e-1f) val = 1e-1f; currentEps = val; UpdateEpsDisplay(); OnAnyChanged(nullptr, nullptr); } else { UpdateEpsDisplay(); } } void OnEpsOrderUp(Object^ sender, EventArgs^ e) { float newVal = currentEps * 10.0f; if (newVal > 1e-1f) newVal = 1e-1f; currentEps = newVal; UpdateEpsDisplay(); OnAnyChanged(nullptr, nullptr); } void OnEpsOrderDown(Object^ sender, EventArgs^ e) { float newVal = currentEps / 10.0f; if (newVal < 1e-9f) newVal = 1e-9f; currentEps = newVal; UpdateEpsDisplay(); OnAnyChanged(nullptr, nullptr); } void OnAngleChanged(Object^ sender, EventArgs^ e) { if (updatingFromMouse) return; float val = WrapPi((float)nudTargetAngle->Value); Decimal wrapped = Decimal((double)val); if (nudTargetAngle->Value != wrapped) nudTargetAngle->Value = wrapped; ClearTrajectoryCache(); this->Invalidate(); } void OnStartAngleChanged(Object^ sender, EventArgs^ e) { if (updatingFromMouse) return; float val = WrapPi((float)nudStartAngle->Value); Decimal wrapped = Decimal((double)val); if (nudStartAngle->Value != wrapped) nudStartAngle->Value = wrapped; ClearTrajectoryCache(); this->Invalidate(); } void OnClearObstaclesClick(Object^ sender, EventArgs^ e) { ClearObstacles(); } void OnGenerateObstaclesClick(Object^ sender, EventArgs^ e) { GenerateRandomObstacles(); } void ApplyPoseToManipulator(PoseSnapshot^ pose) { angles->Clear(); lengths->Clear(); for (int i = 0; i < nSegments; ++i) { angles->Add(pose->Angles[i]); lengths->Add(pose->Lengths[i]); } } void ComputeEndEffector(array<float>^ poseAngles, array<float>^ poseLengths, float% outX, float% outY, float% outA) { float x = 0; float y = 0; float phi = 0; int count = Math::Min(poseAngles->Length, poseLengths->Length); for (int i = 0; i < count; ++i) { phi += poseAngles[i]; x += poseLengths[i] * (float)Math::Cos(phi); y += poseLengths[i] * (float)Math::Sin(phi); } outX = x; outY = y; outA = WrapPi(phi); } PoseSnapshot^ RunAgpCppAtPoint(float tx, float ty, float ta) { variableLengths = cbVarLen->Checked; float maxTheta = (float)nudMaxTheta->Value; int maxIter = (int)nudMaxIter->Value; float r_param = (float)nudR->Value; float eps = currentEps; unsigned int seed = (unsigned int)GetTickCount(); float baseLength = (float)nudBaseLength->Value; float stretchFactor = (float)nudStretchFactor->Value; array<float>^ obstacleData = BuildObstacleBuffer(); pin_ptr<float> pinnedObstacles = nullptr; const float* pObstacleData = nullptr; if (obstacleData->Length > 0) { pinnedObstacles = &obstacleData[0]; pObstacleData = pinnedObstacles; } int obstacleCount = obstacleX->Count; pStart( nSegments, variableLengths, maxTheta, tx, ty, ta, maxIter, r_param, eps, seed, baseLength, stretchFactor, pObstacleData, obstacleCount, 0, nullptr, nullptr ); float* bestQ; float bestX; float bestY; float bestA; float bestF; size_t actualIterations; float achievedEps; LARGE_INTEGER t0; LARGE_INTEGER t1; LARGE_INTEGER fq; QueryPerformanceFrequency(&fq); QueryPerformanceCounter(&t0); fManip( nSegments, variableLengths, maxTheta, tx, ty, ta, maxIter, r_param, eps, seed, baseLength, stretchFactor, pObstacleData, obstacleCount, &bestQ, &bestX, &bestY, &bestA, &bestF, &actualIterations, &achievedEps, 0, nullptr ); QueryPerformanceCounter(&t1); PoseSnapshot^ pose = gcnew PoseSnapshot(nSegments); for (int i = 0; i < nSegments; ++i) pose->Angles[i] = bestQ[i]; if (variableLengths) { for (int i = 0; i < nSegments; ++i) pose->Lengths[i] = bestQ[nSegments + i]; } else { for (int i = 0; i < nSegments; ++i) pose->Lengths[i] = baseLength; } Marshal::FreeCoTaskMem(IntPtr(bestQ)); pose->EndX = bestX; pose->EndY = bestY; pose->EndA = WrapPi(bestA); pose->BestF = bestF; pose->Iterations = (int)actualIterations; pose->AchievedEps = achievedEps; pose->Millis = (float)( 1.0e3 * (double)(t1.QuadPart - t0.QuadPart) / (double)fq.QuadPart ); return pose; } PoseSnapshot^ RunTracIkPositioning(float tx, float ty, float ta) { float baseLength = (float)nudBaseLength->Value; TracIkRunner* runner = GetTracIkRunner(); double bestF = 0.0; double bestX = 0.0; double bestY = 0.0; double bestA = 0.0; double millis = 0.0; runner->Solve( tx, ty, ta, bestF, bestX, bestY, bestA, millis ); const KDL::JntArray& qOut = runner->GetSolution(); PoseSnapshot^ pose = gcnew PoseSnapshot(nSegments); for (int i = 0; i < nSegments; ++i) { pose->Angles[i] = (float)qOut(i); pose->Lengths[i] = baseLength; } pose->EndX = (float)bestX; pose->EndY = (float)bestY; pose->EndA = (float)bestA; pose->BestF = (float)bestF; pose->Iterations = -1; pose->AchievedEps = -1.0f; pose->Millis = (float)millis; return pose; } void UpdatePositioningStats(PoseSnapshot^ pose, float tx, float ty, float ta, bool isTracIk) { float dx = pose->EndX - tx; float dy = pose->EndY - ty; float distance = sqrtf(dx * dx + dy * dy); String^ iterationsStr = isTracIk ? "—" : pose->Iterations.ToString(); String^ epsStr = isTracIk ? "—" : pose->AchievedEps.ToString("E3"); lblInfo->Text = String::Format( L"Функционал: {0:F6}\nБлизость захвата: {1:F5}\nДостигнутая точка: ({2:F3}, {3:F3})\nДостигнутый угол: {4:F3} рад.\nВремя: {5:F3} мс\nЧисло шагов: {6}\nДостигнутая точность: {7}", pose->BestF, distance, pose->EndX, pose->EndY, pose->EndA, pose->Millis, iterationsStr, epsStr ); } void UpdateTrajectoryStats(List<PoseSnapshot^>^ poses, float totalMillis, size_t totalIterations, float finalAchievedEps, bool isTracIk) { if (poses->Count == 0) { lblInfo->Text = L"Траектория не построена"; return; } float totalEnergy = 0; for (int i = 1; i < poses->Count; ++i) totalEnergy += ComputeTransitionEnergy(poses[i - 1], poses[i]); PoseSnapshot^ lastPose = poses[poses->Count - 1]; float rawTargetX = (float)nudTargetX->Value; float rawTargetY = (float)nudTargetY->Value; float finalDx = lastPose->EndX - rawTargetX; float finalDy = lastPose->EndY - rawTargetY; float finalDistance = sqrtf(finalDx * finalDx + finalDy * finalDy); int actualIntermediateCount = Math::Max(0, poses->Count - 2); String^ iterationsStr = isTracIk ? "—" : totalIterations.ToString(); String^ epsStr = isTracIk ? "—" : finalAchievedEps.ToString("E3"); lblInfo->Text = String::Format( L"Промежуточных точек: {0}\nФункционал траектории: {1:F6}\nБлизость финиша: {2:F5}\nДостигнутый угол: {3:F3} рад.\nВремя: {4:F3} мс\nЧисло шагов: {5}\nДостигнутая точность: {6}", actualIntermediateCount, totalEnergy, finalDistance, lastPose->EndA, totalMillis, iterationsStr, epsStr ); } float ComputeTransitionEnergy(PoseSnapshot^ prevPose, PoseSnapshot^ nextPose) { float total = 0; float prevPrefix = 0; float nextPrefix = 0; for (int i = 0; i < prevPose->Angles->Length; ++i) { float d = WrappedDelta(prevPose->Angles[i], nextPose->Angles[i]); total += d * d; prevPrefix += prevPose->Angles[i]; nextPrefix += nextPose->Angles[i]; float dp = WrappedDelta(prevPrefix, nextPrefix); total += TransitionPrefixEnergyWeight * dp * dp; } if (variableLengths) { for (int i = 0; i < prevPose->Lengths->Length; ++i) { float dl = nextPose->Lengths[i] - prevPose->Lengths[i]; total += TransitionLengthEnergyWeight * dl * dl; } } return total; } void RunTrajectoryPlanningMode() { if (cbBackend->SelectedIndex == 1) RunTrajectoryWithTracIk(); else RunTrajectoryWithAGP(); } bool BuildPoseFromState(const float* state, bool varLen, float baseLength, PoseSnapshot^% pose) { pose = gcnew PoseSnapshot(nSegments); for (int i = 0; i < nSegments; ++i) { pose->Angles[i] = state[i]; pose->Lengths[i] = varLen ? state[nSegments + i] : baseLength; } float x; float y; float a; ComputeEndEffector(pose->Angles, pose->Lengths, x, y, a); pose->EndX = x; pose->EndY = y; pose->EndA = a; return true; } void RunTrajectoryWithAGP() { ClearTrajectoryCache(); array<float>^ obsData = BuildObstacleBuffer(); pin_ptr<float> pinnedObs = nullptr; const float* pObs = nullptr; if (obsData->Length > 0) { pinnedObs = &obsData[0]; pObs = pinnedObs; } int obstacleCount = obstacleX->Count; float startX = (float)nudStartX->Value; float startY = (float)nudStartY->Value; float startA = (float)nudStartAngle->Value; float targetX = (float)nudTargetX->Value; float targetY = (float)nudTargetY->Value; float targetA = (float)nudTargetAngle->Value; float maxTheta = (float)nudMaxTheta->Value; float baseLength = (float)nudBaseLength->Value; float stretchFactor = (float)nudStretchFactor->Value; float r_param = (float)nudR->Value; float eps = currentEps; int maxIter = (int)nudMaxIter->Value; bool varLen = cbVarLen->Checked; unsigned int seed = (unsigned int)GetTickCount(); int stateDim = nSegments << 1; pStart( nSegments, varLen, maxTheta, startX, startY, startA, maxIter, r_param, eps, seed, baseLength, stretchFactor, pObs, obstacleCount, 0, nullptr, nullptr ); LARGE_INTEGER totalT0; LARGE_INTEGER totalT1; LARGE_INTEGER fq; QueryPerformanceFrequency(&fq); QueryPerformanceCounter(&totalT0); float* startQ; float startXOut; float startYOut; float startAOut; float startF; size_t startIterations; float startEps; fManip( nSegments, varLen, maxTheta, startX, startY, startA, maxIter, r_param, eps, seed, baseLength, stretchFactor, pObs, obstacleCount, &startQ, &startXOut, &startYOut, &startAOut, &startF, &startIterations, &startEps, 0, nullptr ); PoseSnapshot^ startPose; BuildPoseFromState(startQ, varLen, baseLength, startPose); startPose->EndX = startXOut; startPose->EndY = startYOut; startPose->EndA = WrapPi(startAOut); startPose->BestF = startF; startPose->Iterations = (int)startIterations; startPose->AchievedEps = startEps; std::vector<float> startState(stateDim); for (int i = 0; i < nSegments; ++i) { startState[i] = startPose->Angles[i]; startState[nSegments + i] = startPose->Lengths[i]; } Marshal::FreeCoTaskMem(IntPtr(startQ)); pStart( nSegments, varLen, maxTheta, targetX, targetY, targetA, maxIter, r_param, eps, seed, baseLength, stretchFactor, pObs, obstacleCount, 1, startState.data(), nullptr ); float* finalQ; float finalXOut; float finalYOut; float finalAOut; float finalF; size_t finalIterations; float finalEps; fManip( nSegments, varLen, maxTheta, targetX, targetY, targetA, maxIter, r_param, eps, seed, baseLength, stretchFactor, pObs, obstacleCount, &finalQ, &finalXOut, &finalYOut, &finalAOut, &finalF, &finalIterations, &finalEps, 1, startState.data() ); PoseSnapshot^ finalPose; BuildPoseFromState(finalQ, varLen, baseLength, finalPose); finalPose->EndX = finalXOut; finalPose->EndY = finalYOut; finalPose->EndA = WrapPi(finalAOut); finalPose->BestF = finalF; finalPose->Iterations = (int)finalIterations; finalPose->AchievedEps = finalEps; std::vector<float> finalState(stateDim); for (int i = 0; i < nSegments; ++i) { finalState[i] = finalPose->Angles[i]; finalState[nSegments + i] = finalPose->Lengths[i]; } Marshal::FreeCoTaskMem(IntPtr(finalQ)); pStart( nSegments, varLen, maxTheta, 0, 0, 0, maxIter, r_param, eps, seed, baseLength, stretchFactor, pObs, obstacleCount, 2, startState.data(), finalState.data() ); float* trajPoints; int pointCount; size_t trajectoryIterations; pBuildTrajectory( nSegments, varLen, maxTheta, startState.data(), finalState.data(), maxIter, r_param, eps, seed, baseLength, stretchFactor, pObs, obstacleCount, &trajPoints, &pointCount, &trajectoryIterations ); QueryPerformanceCounter(&totalT1); float millis = (float)( 1.0e3 * (double)(totalT1.QuadPart - totalT0.QuadPart) / (double)fq.QuadPart ); size_t totalIterations = trajectoryIterations + startIterations + finalIterations; plannedPoses->Clear(); for (int i = 0; i < pointCount; ++i) { const float* ptr = trajPoints + i * stateDim; PoseSnapshot^ pose; BuildPoseFromState(ptr, varLen, baseLength, pose); plannedPoses->Add(pose); } Marshal::FreeCoTaskMem(IntPtr(trajPoints)); plannedPoses[0]->EndX = startPose->EndX; plannedPoses[0]->EndY = startPose->EndY; plannedPoses[0]->EndA = startPose->EndA; plannedPoses[plannedPoses->Count - 1]->EndX = finalPose->EndX; plannedPoses[plannedPoses->Count - 1]->EndY = finalPose->EndY; plannedPoses[plannedPoses->Count - 1]->EndA = finalPose->EndA; UpdateTrajectoryStats( plannedPoses, millis, totalIterations, finalEps, false ); BuildAnimationFramesFromPlan(); ApplyPoseToManipulator(plannedPoses[0]); StartAnimationIfNeeded(); this->Invalidate(); } void RunTrajectoryWithTracIk() { ClearTrajectoryCache(); float startX = (float)nudStartX->Value; float startY = (float)nudStartY->Value; float startA = (float)nudStartAngle->Value; float targetX = (float)nudTargetX->Value; float targetY = (float)nudTargetY->Value; float targetA = (float)nudTargetAngle->Value; PoseSnapshot^ startPose = RunTracIkPositioning( startX, startY, startA ); PoseSnapshot^ endPose = RunTracIkPositioning( targetX, targetY, targetA ); float totalMillis = startPose->Millis + endPose->Millis; plannedPoses->Clear(); plannedPoses->Add(startPose); plannedPoses->Add(endPose); UpdateTrajectoryStats( plannedPoses, totalMillis, 0, -1.0f, true ); BuildAnimationFramesFromPlan(); ApplyPoseToManipulator(plannedPoses[0]); StartAnimationIfNeeded(); this->Invalidate(); } void RunPositioningMode() { StopAnimation(); float tx = (float)nudTargetX->Value; float ty = (float)nudTargetY->Value; float ta = (float)nudTargetAngle->Value; bool isTracIk = (cbBackend->SelectedIndex == 1); PoseSnapshot^ pose = isTracIk ? RunTracIkPositioning(tx, ty, ta) : RunAgpCppAtPoint(tx, ty, ta); ClearTrajectoryCache(); ApplyPoseToManipulator(pose); UpdatePositioningStats(pose, tx, ty, ta, isTracIk); this->Invalidate(); this->Refresh(); } void DrawTrajectorySegmentClipped(Graphics^ g, PointF aWorld, PointF bWorld) { float prevX = aWorld.X; float prevY = aWorld.Y; bool prevAllowed = IsDisplayPointAllowed(prevX, prevY); for (int s = 1; s <= 20; ++s) { float t = s / 20.0f; float currX = Lerp(aWorld.X, bWorld.X, t); float currY = Lerp(aWorld.Y, bWorld.Y, t); bool currAllowed = IsDisplayPointAllowed(currX, currY); if (prevAllowed && currAllowed) { PointF pa = WorldToPixel(prevX, prevY); PointF pb = WorldToPixel(currX, currY); g->DrawLine(pathPen, pa, pb); } prevX = currX; prevY = currY; prevAllowed = currAllowed; } } void DrawTrajectoryPath(Graphics^ g) { if (trajectoryPathWorld->Count < 2) return; for (int i = 1; i < trajectoryPathWorld->Count; ++i) DrawTrajectorySegmentClipped(g, trajectoryPathWorld[i - 1], trajectoryPathWorld[i]); if (plannedPoses->Count > 2) { for (int i = 1; i < plannedPoses->Count - 1; ++i) { if (!IsDisplayPointAllowed(plannedPoses[i]->EndX, plannedPoses[i]->EndY)) continue; PointF wp = WorldToPixel(plannedPoses[i]->EndX, plannedPoses[i]->EndY); g->FillEllipse(waypointBrush, wp.X - 4.0f, wp.Y - 4.0f, 8.0f, 8.0f); } } } void RebuildTrajectoryDisplayPathFromPlan() { trajectoryPathWorld->Clear(); if (animationFrames->Count > 0) { for (int i = 0; i < animationFrames->Count; ++i) { PointF p(animationFrames[i]->EndX, animationFrames[i]->EndY); if (trajectoryPathWorld->Count == 0 || DistanceSquared(trajectoryPathWorld[trajectoryPathWorld->Count - 1], p) > 1e-10f) { trajectoryPathWorld->Add(p); } } return; } for (int i = 0; i < plannedPoses->Count; ++i) { PointF p(plannedPoses[i]->EndX, plannedPoses[i]->EndY); if (trajectoryPathWorld->Count == 0 || DistanceSquared(trajectoryPathWorld[trajectoryPathWorld->Count - 1], p) > 1e-10f) { trajectoryPathWorld->Add(p); } } } void BuildAnimationFramesFromPlan() { animationFrames->Clear(); if (plannedPoses->Count == 0) { RebuildTrajectoryDisplayPathFromPlan(); return; } animationFrames->Add(plannedPoses[0]); for (int i = 0; i < plannedPoses->Count - 1; ++i) { PoseSnapshot^ firstPose = plannedPoses[i]; PoseSnapshot^ secondPose = plannedPoses[i + 1]; for (int frame = 1; frame <= AnimationFramesPerSegment; ++frame) { float t = frame / (float)AnimationFramesPerSegment; PoseSnapshot^ interp = gcnew PoseSnapshot(nSegments); for (int j = 0; j < nSegments; ++j) { interp->Angles[j] = LerpWrappedAngle( firstPose->Angles[j], secondPose->Angles[j], t ); interp->Lengths[j] = variableLengths ? firstPose->Lengths[j] + t * (secondPose->Lengths[j] - firstPose->Lengths[j]) : (float)nudBaseLength->Value; } float x; float y; float angle; ComputeEndEffector( interp->Angles, interp->Lengths, x, y, angle ); interp->EndX = x; interp->EndY = y; interp->EndA = angle; animationFrames->Add(interp); } } RebuildTrajectoryDisplayPathFromPlan(); } void StartAnimationIfNeeded() { if (animationFrames->Count <= 1) { animationRunning = false; this->Invalidate(); return; } animationFrameIndex = 0; animationRunning = true; animationTimer->Start(); } void OnAnimationTick(Object^ sender, EventArgs^ e) { if (!animationRunning || animationFrames->Count == 0) { StopAnimation(); return; } if (animationFrameIndex >= animationFrames->Count) { StopAnimation(); return; } ApplyPoseToManipulator(animationFrames[animationFrameIndex]); ++animationFrameIndex; this->Invalidate(); if (animationFrameIndex >= animationFrames->Count) StopAnimation(); } PointF WorldToPixel(float wx, float wy) { PointF basePoint = GetBasePoint(); return PointF(basePoint.X + wx * 160.0f, basePoint.Y - wy * 160.0f); } float GetCurrentMaxReach() { float baseLength = (float)nudBaseLength->Value; float stretchFactor = (float)nudStretchFactor->Value; return nSegments * (cbVarLen->Checked ? baseLength * stretchFactor : baseLength); } bool IsDisplayPointAllowed(float x, float y) { float maxReach = GetCurrentMaxReach(); if (x * x + y * y > (maxReach + 0.05f) * (maxReach + 0.05f)) { return false; } for (int i = 0; i < obstacleX->Count; ++i) { float half = obstacleHalf[i] + ObstacleClearance; if (x >= obstacleX[i] - half && x <= obstacleX[i] + half && y >= obstacleY[i] - half && y <= obstacleY[i] + half) { return false; } } return true; } [MethodImpl(MethodImplOptions::AggressiveInlining)] void OnMouseDownPoint(Object^ sender, MouseEventArgs^ e) { PointF basePoint = GetBasePoint(); float baseX = basePoint.X; float baseY = basePoint.Y; float targetX = (float)nudTargetX->Value; float targetY = (float)nudTargetY->Value; float targetA = (float)nudTargetAngle->Value; float pixelTargetX = baseX + targetX * 160.0f; float pixelTargetY = baseY - targetY * 160.0f; float angleLineLen = 25.0f; float endX = pixelTargetX + angleLineLen * (float)Math::Cos(targetA); float endY = pixelTargetY - angleLineLen * (float)Math::Sin(targetA); float dx = e->X - endX; float dy = e->Y - endY; if (dx * dx + dy * dy < 225.0f) { StopAnimation(); activeDragHandle = DragHandle::AngleTarget; angleTargetDrag = true; updatingFromMouse = true; this->Capture = true; return; } float bestDistSquared = 100.0f; activeDragHandle = DragHandle::None; if (IsTrajectoryMode()) { float startX = (float)nudStartX->Value; float startY = (float)nudStartY->Value; float startA = (float)nudStartAngle->Value; float pixelStartX = baseX + startX * 160.0f; float pixelStartY = baseY - startY * 160.0f; float sEndX = pixelStartX + angleLineLen * (float)Math::Cos(startA); float sEndY = pixelStartY - angleLineLen * (float)Math::Sin(startA); dx = e->X - sEndX; dy = e->Y - sEndY; if (dx * dx + dy * dy < 225.0f) { StopAnimation(); activeDragHandle = DragHandle::AngleStart; angleStartDrag = true; updatingFromMouse = true; this->Capture = true; return; } float dsx = e->X - pixelStartX; float dsy = e->Y - pixelStartY; float startDistSquared = dsx * dsx + dsy * dsy; if (startDistSquared < bestDistSquared) { bestDistSquared = startDistSquared; activeDragHandle = DragHandle::Start; } } float dtx = e->X - pixelTargetX; float dty = e->Y - pixelTargetY; float targetDistSquared = dtx * dtx + dty * dty; if (targetDistSquared < bestDistSquared) activeDragHandle = DragHandle::Target; if (activeDragHandle != DragHandle::None) { StopAnimation(); updatingFromMouse = true; this->Capture = true; } } [MethodImpl(MethodImplOptions::AggressiveInlining)] void OnMouseMovePoint(Object^ sender, MouseEventArgs^ e) { if (activeDragHandle == DragHandle::None && !angleTargetDrag && !angleStartDrag) { return; } PointF basePoint = GetBasePoint(); float baseX = basePoint.X; float baseY = basePoint.Y; if (angleTargetDrag) { float targetX = (float)nudTargetX->Value; float targetY = (float)nudTargetY->Value; float pixelTargetX = baseX + targetX * 160.0f; float pixelTargetY = baseY - targetY * 160.0f; float dx = e->X - pixelTargetX; float dy = e->Y - pixelTargetY; float angle = WrapPi(atan2f(-dy, dx)); nudTargetAngle->Value = Decimal((double)angle); ClearTrajectoryCache(); this->Invalidate(); return; } if (angleStartDrag && IsTrajectoryMode()) { float startX = (float)nudStartX->Value; float startY = (float)nudStartY->Value; float pixelStartX = baseX + startX * 160.0f; float pixelStartY = baseY - startY * 160.0f; float dx = e->X - pixelStartX; float dy = e->Y - pixelStartY; float angle = WrapPi(atan2f(-dy, dx)); nudStartAngle->Value = Decimal((double)angle); ClearTrajectoryCache(); this->Invalidate(); return; } if (activeDragHandle == DragHandle::None) return; float minX = (float)nudTargetX->Minimum; float maxX = (float)nudTargetX->Maximum; float minY = (float)nudTargetY->Minimum; float maxY = (float)nudTargetY->Maximum; float newX = (e->X - baseX) / 160.0f; float newY = (baseY - e->Y) / 160.0f; newX = Math::Max(minX, Math::Min(maxX, newX)); newY = Math::Max(minY, Math::Min(maxY, newY)); if (activeDragHandle == DragHandle::Target) { nudTargetX->Value = Decimal((double)newX); nudTargetY->Value = Decimal((double)newY); } else if (activeDragHandle == DragHandle::Start) { startPointCustomized = true; nudStartX->Value = Decimal((double)newX); nudStartY->Value = Decimal((double)newY); } ClearTrajectoryCache(); this->Invalidate(); } [MethodImpl(MethodImplOptions::AggressiveInlining)] void OnMouseUpPoint(Object^ sender, MouseEventArgs^ e) { if (activeDragHandle != DragHandle::None || angleTargetDrag || angleStartDrag) { activeDragHandle = DragHandle::None; angleTargetDrag = false; angleStartDrag = false; updatingFromMouse = false; this->Capture = false; } } void OnBackendChanged(Object^ sender, EventArgs^ e) { UpdateBackendUiState(); ClearTrajectoryCache(); this->Invalidate(); } void OnDemoModeChanged(Object^ sender, EventArgs^ e) { demoMode = (cbDemoMode->SelectedIndex == 0) ? DemoMode::Positioning : DemoMode::TrajectoryPlanning; if (demoMode == DemoMode::TrajectoryPlanning && !startPointCustomized) { SetDefaultStartPoint(false); } UpdateTrajectoryUiState(); } void OnResize(Object^ sender, EventArgs^ e) { this->Invalidate(); } void OnAnyChanged(Object^ sender, EventArgs^ e) { if (updatingFromMouse) return; ClearTrajectoryCache(); this->Invalidate(); } void OnTargetChanged(Object^ sender, EventArgs^ e) { if (updatingFromMouse) return; if (!startPointCustomized) SetDefaultStartPoint(false); ClearTrajectoryCache(); this->Invalidate(); } void OnStartPointChanged(Object^ sender, EventArgs^ e) { if (updatingFromMouse) return; if (!syncingDefaultStartPoint) startPointCustomized = true; ClearTrajectoryCache(); this->Invalidate(); } void OnAddClick(Object^ sender, EventArgs^ e) { ++nSegments; angles->Add(0.0f); lengths->Add((float)nudBaseLength->Value); ClearTrajectoryCache(); this->Invalidate(); } void OnRemClick(Object^ sender, EventArgs^ e) { if (nSegments > 1) { --nSegments; angles->RemoveAt(angles->Count - 1); lengths->RemoveAt(lengths->Count - 1); ClearTrajectoryCache(); this->Invalidate(); } } void OnOptimizeClick(Object^ sender, EventArgs^ e) { if (IsTrajectoryMode()) RunTrajectoryPlanningMode(); else RunPositioningMode(); } protected: [MethodImpl(MethodImplOptions::AggressiveInlining)] virtual void OnPaint(PaintEventArgs^ e) override { Form::OnPaint(e); Graphics^ g = e->Graphics; g->SmoothingMode = SmoothingMode::HighQuality; g->Clear(this->BackColor); int drawHeight = Math::Max(0, this->ClientSize.Height - 180); System::Drawing::Rectangle drawArea(0, 180, this->ClientSize.Width, drawHeight); g->FillRectangle(Brushes::White, drawArea); float targetX = (float)nudTargetX->Value; float targetY = (float)nudTargetY->Value; float targetA = (float)nudTargetAngle->Value; PointF basePoint = GetBasePoint(); int baseX = (int)basePoint.X; int baseY = (int)basePoint.Y; float pixelTargetX = baseX + targetX * 160.0f; float pixelTargetY = baseY - targetY * 160.0f; g->DrawLine(wallPen, baseX - 25, baseY + 8, baseX + 25, baseY + 8); g->FillRectangle(wallHatchBrush, baseX - 25, baseY + 8, 50, 12); g->DrawLine(dashedPen, pixelTargetX - 25, pixelTargetY + 8, pixelTargetX + 25, pixelTargetY + 8); g->FillRectangle(wallHatchBrush, (int)pixelTargetX - 25, (int)pixelTargetY + 8, 50, 12); g->DrawEllipse(targetPen, pixelTargetX - 8.0f, pixelTargetY - 8.0f, 16.0f, 16.0f); float angleLen = 25.0f; float endX = pixelTargetX + angleLen * (float)Math::Cos(targetA); float endY = pixelTargetY - angleLen * (float)Math::Sin(targetA); g->DrawLine(angleTargetPen, pixelTargetX, pixelTargetY, endX, endY); if (IsTrajectoryMode()) { float startX = (float)nudStartX->Value; float startY = (float)nudStartY->Value; float startA = (float)nudStartAngle->Value; float pixelStartX = baseX + startX * 160.0f; float pixelStartY = baseY - startY * 160.0f; g->DrawLine(dashedPen, pixelStartX - 25, pixelStartY + 8, pixelStartX + 25, pixelStartY + 8); g->FillRectangle(wallHatchBrush, (int)pixelStartX - 25, (int)pixelStartY + 8, 50, 12); g->DrawEllipse(startPen, pixelStartX - 8.0f, pixelStartY - 8.0f, 16.0f, 16.0f); float sEndX = pixelStartX + angleLen * (float)Math::Cos(startA); float sEndY = pixelStartY - angleLen * (float)Math::Sin(startA); g->DrawLine(angleStartPen, pixelStartX, pixelStartY, sEndX, sEndY); } if (trajectoryPathWorld->Count > 1 && IsTrajectoryMode()) DrawTrajectoryPath(g); if (obstacleX->Count > 0) { array<float>^ xs = obstacleX->ToArray(); array<float>^ ys = obstacleY->ToArray(); array<float>^ hs = obstacleHalf->ToArray(); int obstacleCount = Math::Min( xs->Length, Math::Min( ys->Length, hs->Length ) ); for (int obsIdx = 0; obsIdx < obstacleCount; ++obsIdx) { float cx = xs[obsIdx]; float cy = ys[obsIdx]; float half = hs[obsIdx]; float left = (float)baseX + (cx - half) * 160.0f; float top = (float)baseY - (cy + half) * 160.0f; float size = 2.0f * half * 160.0f; float marginLeft = (float)baseX + (cx - half - ObstacleClearance) * 160.0f; float marginTop = (float)baseY - (cy + half + ObstacleClearance) * 160.0f; float marginSize = 2.0f * (half + ObstacleClearance) * 160.0f; g->DrawRectangle(obstacleMarginPen, marginLeft, marginTop, marginSize, marginSize); g->FillRectangle(obstacleBrush, left, top, size, size); g->DrawRectangle(obstaclePen, left, top, size, size); } } int drawableSegments = Math::Min( nSegments, Math::Min( angles->Count, lengths->Count ) ); array<PointF>^ pts = gcnew array<PointF>( drawableSegments + 1 ); pts[0] = PointF((float)baseX, (float)baseY); float x = 0.0f; float y = 0.0f; float phi = 0.0f; array<float>^ localAngles = angles->ToArray(); array<float>^ localLengths = lengths->ToArray(); for (int i = 0; i < drawableSegments; ++i) { phi += localAngles[i]; x += localLengths[i] * (float)Math::Cos(phi); y += localLengths[i] * (float)Math::Sin(phi); pts[i + 1] = PointF( (float)baseX + x * 160.0f, (float)baseY - y * 160.0f ); } for (int i = 0; i < drawableSegments; ++i) g->DrawLine(penRod, pts[i], pts[i + 1]); for (int i = 0; i <= drawableSegments; ++i) g->FillEllipse(jointBrush, pts[i].X - 8.0f, pts[i].Y - 8.0f, 16.0f, 16.0f); } };

}". Найди баг и предложи конкретное решение в коде как его исправить не ломая существующую логику - код высокооптимизироан под скорость выполнения в реальном времени и скорость работы как и точность нужно сохранить - так что старайся не вмешиваться в логику без крайней необходимости - сама логика алгоритма верна как и логика построителя траектории, как и логика swept-проверок и рекурсивных валидаций - во всех этих местах всё должно быть хорошо логически но где-то в коде скорее всего есть не логическая ошибка а ошибка из-за недосмотренности и по забывчивости незаполненные например поля для конечного состояния или я мог не учесть один из путей выполнения когда конечное состояние уничтожается или зануляется по какой-то причине - твоя задача найти проблему и предложить элегантное решение, которое не скажется на скорости кода и не будет ломать текущие пути вычислений

Suy nghĩ

Оценивая сбой

Я вижу вероятную проблему не в BuildPoseFromState, а раньше: в mode=1 результат Manipulate может не записываться в states. Нужна проверка API и содержимого pManip, особенно указателей и размерности состояния.

Изолируя причину

Я проверяю два вызова Manipulate: если mode=0 работает, а mode=1 выдаёт нулевой finalQ, временно заменю второй вызов на проверенный путь и добавлю проверки указателей, размеров и кодов возврата.

Оценил сбой и изолировал причину

Trả lời

Проверю цепочку pStart → fManip → pBuildTrajectory и то, как передаются начальное и конечное состояния. Отдельно разберу AccessViolation: важно отличить потерю цели от чтения невалидного буфера после неудачной оптимизации. Постараюсь ограничить исправления местами передачи данных и проверки результата, не затрагивая геометрию и проверки столкновений.

Suy nghĩ

Проверяя целевое состояние

Я замечаю другое объяснение: нулевые углы могут быть корректным минимумом при неверно переданных координатах цели или размерности состояния. Сначала нужно вывести finalState, finalQ и коды возврата непосредственно после каждого вызова.

Проверено целевое состояние

Suy nghĩ

Проверяя переходы

I’m narrowing this to the transition-specific path: obstacle sweeping may reject every candidate, leaving a stale or default configuration. I’d first compare mode=0 and mode=1, then use the valid endpoint solution as a controlled fallback.

Исправляя размер состояния

Я нашёл конкретную ошибку: при varLen=false библиотека хранит N значений на точку, а демон использует шаг 2N. Исправляю stateDim и копирование длин условно; чтение траектории перестанет уходить за границы и давать нули.

Trả lời

Нашёл конкретную ошибку, которая объясняет выпрямление манипулятора и AccessViolationException

В твоём коде действительно есть ошибка передачи состояния между## Нашёл конкретную ошибку, которая объясняет выпрямление манипулятора и AccessViolationException

В твоём коде действительно есть ошибка передачи состояния между библиотекой AGP и демонстрационным приложением. Причём она находится не в оптимизаторе, не в swept-проверках и не в рекурсивном построителе траектории, библиотекой AGP и демонстрационным приложением. Причём она находится не в оптимизаторе, не в swept-проверках и не в рекурсивном построителе траектории, а в несовпадении размерности состояния, которое возвращает библиотека, а в несовпадении размерности состояния, которое возвращает библиотека, и размерности, которую ожидает MyForm.h.

Это особенно и размерности, которую ожидает MyForm.h.

Это особенно хорошо объясняет ситуацию, когда манипулятор правильно начинает хорошо объясняет ситуацию, когда манипулятор правильно начинает движение, но в движение, но в конце выпрямляется горизонтально независимо от заданной цели.

1. Главная ошибка — неправильный stateDim

В RunTrajectoryWithAGP() у тебя написано:

Последняя строка конце выпрямляется горизонтально независимо от заданной цели.

1. Главная ошибка — неправильный stateDim

В RunTrajectoryWithAGP() у тебя написано:

Последняя строка безусловно устанавливает размерность 2 * nSegments.

Однако в приложенной библиотеке, внутри build_trajectory(), безусловно устанавливает размерность 2 * nSegments.

Однако в приложенной библиотеке, внутри build_trajectory(), размерность определяется иначе:

размерность определяется иначе:

И далее библиотека выделяет память под траекторию и записывает состоянияИ далее библиотека выделяет память под траекторию и записывает состояния именно с этим шагом:

Получается следующее:

| Режим | именно с этим шагом:

Получается следующее:

РежимБиблиотека записываетДемо ожидает
Постоянные длиныN чисел на состояние2N чисел
Перем Библиотека записываетДемо ожидает
---------
Постоянные длиныN чисел на состояние2N чисел
Переменные длины2N чисел на состояние2N чисел

**В режиме постоянных длин демонстрационная программа читает траекторию сенные длины | 2N чисел на состояние | 2N чисел |

В режиме постоянных длин демонстрационная программа читает траекторию с шагом вдвое больше правильного.

Вот проблемное место:

cpp
for (int i = 0; i < шагом вдвое больше правильного.** Вот проблемное место: Например, если ` pointCount; ++i) { const float* ptr = trajPoints + i * stateDim; PoseSnapshot^ pose; BuildPoseFromState(ptr, varLen, baseLength, pose); plannedPoses->Add(pose); }

Например, если nSegments = 4, а библиотека вернула три состояния, память выглядит так:

<box border radius="lg" padding={3} gap={2}> <textnSegments = 4`, а библиотека вернула три состояния, память выглядит так: <box border radius="lg" padding={3} gap={2}> <text weight="medium" size="sm">Фактический буфер библиотеки (4 числа на состояние)</text> <svg viewBox="0 0 340 108" width="100%" xmlns="http://www.w3.org/2000/svg"> {#each ["q weight="medium" size="sm">Фактический буфер библиотеки (4 числа на состояние)</text> <svg viewBox="0 0 340 108" width="100%" xmlns="http://www.w3.org/2000/svg"> {#each ["q₀", "q₁", "q₂"] as q, i} <rect x={12+i*106₀", "q₁", "q₂"] as q, i} <rect x={12+i*106} y="12" width="100" height="32" rx="5" fill={i===1?"#F0B45B":"#7CB0D6"} fillOpacity=".28" stroke={i===1?"#CB8B25":"#548DAF"}/> <text x={62+i*106} y="32" fontSize="13" textAnchor="middle" fill="currentColor">{q} (4 float)</text> {/each} <path d="M12 65 L12 46} y="12" width="100" height="32" rx="5" fill={i===1?"#F0B45B":"#7CB0D6"} fillOpacity=".28" stroke={i===1?"#CB8B25":"#548DAF"}/> <text x={62+i*106} y="32" fontSize="13" textAnchor="middle" fill="currentColor">{q} (4 float)</text> {/each} <path d="M12 65 L12 46 M224 65 L224 46" stroke="#DB7755" strokeWidth="1.8"/> <text x="12" M224 65 L224 46" stroke="#DB7755" strokeWidth="1.8"/> <text x="12" y="81" fontSize="12" fill="#DB7755">i=0</text> <text x="204" y="81" fontSize="12" fill="#DB7755">i=1</text> <path d="M325 63 L337 63" stroke="#DB7755" strokeWidth="1.8"/> <text x="335" y="99" fontSize="11 y="81" fontSize="12" fill="#DB7755">i=0</text> <text x="204" y="81" fontSize="12" fill="#DB7755">i=1</text> <path d="M325 63 L337 63" stroke="#DB7755" strokeWidth="1.8"/> <text x="335" y="99" fontSize="11" textAnchor="end" fill="#DB7755">i=2: за буфером →</text> </svg> <caption>При ошибочном шаге 8 вместо 4 программа пропускает второе" textAnchor="end" fill="#DB7755">i=2: за буфером →</text> </svg> <caption>При ошибочном шаге 8 вместо 4 программа пропускает второе состояние, а затем выходит за границы выделенной памяти.</caption> </box>

Отсюда возникают два эффекта:

  • Вместо правильной конечной конфигурации читаются другие данные или память за пределами массива. Если прочитанные углы оказываются нулевыми, манипулятор полностью выпрямляется.
  • При чтении недоступной памяти в BuildPoseFromState() возникает именно System.AccessViolationException с кодом 0xc0000005.

Это прямая ошибка согласования форматов данных, не требующая изменения алгоритма оптимизации.

состояние, а затем выходит за границы выделенной памяти.</caption> </box>

Отсюда возникают два эффекта:

  • Вместо правильной конечной конфигурации читаются другие данные или память за пределами массива. Если прочитанные углы оказываются нулевыми, манипулятор полностью выпрямляется.
  • При чтении недоступной памяти в BuildPoseFromState() возникает именно System.AccessViolationException с кодом 0xc0000005.

Это прямая ошибка согласования форматов данных, не требующая изменения алгоритма оптимизации.

Suy nghĩ

Fixing state handling

I found a concrete mismatch: fixed-length trajectories contain N values per point, but the demo always advances by 2N. I’m also updating variableLengths and conditionally copying lengths to prevent invalid reads and endpoint corruption.

Уточняя исправление

Главная причина — несовпадение размера состояния: при фиксированных длинах точка содержит N, а демон читает 2N. Это вызывает выход за границы, нулевые углы и AccessViolation. Исправление: использовать stateDim = varLen ? 2*N : N и условно копировать длины.

Checking the final fix

I’ve confirmed the primary fault: fixed-length output uses N floats per pose, while the demo advances by 2N. That causes out-of-bounds reads, zero-like angles, and the later access violation.

Fixed state handling and verified the final correction

Inspected Sobol trajectory planning, transitions, indexing, and goal handling bugs

Trả lời

Проверка исходника DLL подтвердила причину: при постоянных длинах построитель записывает ровно N координат на конфигурацию, а демо читает по 2N. Также нашёл два независимых дефекта, влияющих на качество результата в transition: несогласованный индекс полной допустимости для режима без препятствий и повторное использование кэша начальных приближений при вычислении конечной позы. Для них тоже есть точечные исправления без изменения вычислительного ядра.

Suy nghĩ

Фиксируя размер состояния

Я нашёл конкретную ошибку: при varLen=false библиотека возвращает N значений на точку, а демон шагает по 2N. Исправьте:

cpp
const bool varLen = cbVarLen->Checked; variableLengths = varLen; const int stateDim = varLen ? (nSegments << 1) : nSegments;

Создание состояний замените на:

cpp
std::vector<float> startState(stateDim); std::vector<float> finalState(stateDim); for (int i = 0; i < nSegments; ++i) { startState[i] = startPose->Angles[i]; finalState[i] = finalPose->Angles[i]; } if (varLen) { for (int i = 0; i < nSegments; ++i) { startState[nSegments + i] = startPose->Lengths[i]; finalState[nSegments + i] = finalPose->Lengths[i]; } }

Чтение траектории должно использовать тот же размер:

cpp
const float* point = trajPoints + static_cast<size_t>(i) * stateDim; BuildPoseFromState(point, nSegments, varLen);

Сейчас при фиксированных длинах второй кадр читается за пределами выделенного блока. Обычно там оказываются нули, поэтому манипулятор становится горизонтальным; позднее это приводит к AccessViolation.

Также исправьте поле состояния перед построением:

cpp
variableLengths = varLen;

Инициализируйте параметры нулями:

cpp
RunParams p{};

В библиотеке полезно заменить вычисление полного индекса ограничений:

cpp
const unsigned int fullConstraintIndex = cost.total_constraints() + (cost.HasObstacles ? 1u : 0u);

Это нужно сделать в обоих местах, где сейчас безусловно добавляется +1. Иначе при отсутствии препятствий выбирается устаревший буфер конфигурации.

Для проверки добавьте после построения:

cpp
if (!trajPoints || pointCount < 2) { throw gcnew InvalidOperationException( "Trajectory generation returned no points."); }

Важно: если зависание происходит внутри построителя до его возврата, исправление stateDim не объясняет само зависание; оно объясняет горизонтальный результат и последующий сбой при чтении кадров.

Recorded the state size

Fixed AGP trajectory indexing and validated the Sobol patch library

Worked for 6m 46s

Trả lời

2. Точное исправление RunTrajectoryWithAGP()

Нужно изменить три небольших участка## 2. Точное исправление RunTrajectoryWithAGP()

Нужно изменить три небольших участка в MyForm.h.

Исправление №1 — размерность и ф в MyForm.h.

Исправление №1 — размерность и флаг переменных длин

Замени:

cpp
int maxIter = (int)nudMaxIter->Value; лаг переменных длин Замени: ```cpp int maxIter = (int)nudMaxIter->Value; bool varLen = cbVarLen->Checked; unsigned int seed = (unsigned int)GetTickCount(); int stateDim = nbool varLen = cbVarLen->Checked; unsigned int seed = (unsigned int)GetTickCount(); int stateDim = nSegments << 1;

На:

cpp
int maxIter = (int)nudMaxIter->Value; const bool varLen = cbVarLen->Checked; variableLengths = varLen; const unsigned int seed = (unsigned int)GetTickCount(); const int stateDim = Segments << 1;

На:

Обрати внимание на variableLengths = varLen;. Это ещё один проп varLen ? (nSegments << 1) : nSegments;

text
Обрати внимание на `variableLengths = varLen;`. Это ещё один пропуск в демо: `BuildAnimationFramesFromPlan()` использует поле класса `variableLengths`, но `RunTrajectoryуск в демо: `BuildAnimationFramesFromPlan()` использует поле класса `variableLengths`, но `RunTrajectoryWithAGP()` его не обновляет. Поэтому при включённых переменных длинах анимация может ошибочно использовать базовые длины вместо вычисленных оптимизатором. ### Исправление №2 — заполнение `WithAGP()` его не обновляет. Поэтому при включённых переменных длинах анимация может ошибочно использовать базовые длины вместо вычисленных оптимизатором. ### Исправление №2 — заполнение `startState` и `finalState` Это обязательная часть исправления. Если поменять только `stateDim`, оставив старое заполнение массивов, появstartState` и `finalState` Это обязательная часть исправления. Если поменять только `stateDim`, оставив старое заполнение массивов, появится уже **запись за пределы `std::vector`**. Найди: ```cpp std::vector<float> startState(stateDim); for (ится уже **запись за пределы `std::vector`**. Найди: Замени на: Замени на: ```cpp std::vector<float> startState(stateDim); for (int i = 0; i < nSegments; ++i) startState[i] = startPose->Angles[i]; if (varLen) { for (int i = 0; i < nSegments; ++i) startState[nSegments + i]int i = 0; i < nSegments; ++i) startState[i] = startPose->Angles[i]; if (varLen) { for (int i = 0; i < nSegments; ++i) startState[nSegments + i] = startPose->Lengths[i]; }

Аналогично найди:

Замени = startPose->Lengths[i]; }

text
Аналогично найди: Замени на: ```cpp std::vector<float> finalState(stateDim); for (int i = 0; i < nSegments; ++i) finalState[i] = finalPose->Angles[i]; if (varLen) { for (int i = 0; i < nSegments; ++ на: Теперь размерности всех трёх представлений состояния — `startState`, `finalState` и `trajPoints` — совпадаютi) finalState[nSegments + i] = finalPose->Lengths[i]; }

Теперь размерности всех трёх представлений состояния — startState, finalState и trajPoints — совпадают с контрактом библиотеки.

Исправление №3 — чтение результата и защита от пустого буфера

Рекомендую за с контрактом библиотеки.

Исправление №3 — чтение результата и защита от пустого буфера

Рекомендую заодно инициализировать выходные параметры:

Вызодно инициализировать выходные параметры:

Вызов pBuildTrajectory(...) оставь прежним.

Непосредственно после его возврата добавь:

cpp
if (trajPoints == nullptr || pointCount < 2) { if (trajPoints != nullptr) Marshalов `pBuildTrajectory(...)` оставь прежним. Непосредственно после его возврата добавь: А цикл чтения запиши так: ```cpp plannedPoses::FreeCoTaskMem(IntPtr(trajPoints)); lblInfo->Text = L"AGP: траектория не построена"; return; }

А цикл чтения запиши так:

cpp
plannedPoses->Clear(); for (int i = 0; i < pointCount; ++i) { const float* ptr = trajPoints + static_cast<size_t>(i) * stateDim; PoseSnapshot^ pose; BuildPoseFromState( ptr, ->Clear(); for (int i = 0; i < pointCount; ++i) { const float* ptr = trajPoints + static_cast<size_t>(i) * stateDim; PoseSnapshot^ pose; BuildPoseFromState( ptr, varLen, baseLength, pose ); plannedPoses->Add(pose); } Marshal::FreeCoTaskMem(IntPtr(trajPoints));

Это не меняет работу оптимизатора и не добавляет вычислений в его varLen, baseLength, pose );

plannedPoses->Add(pose);

}

Marshal::FreeCoTaskMem(IntPtr(trajPoints));

text
Это не меняет работу оптимизатора и не добавляет вычислений в его внутренние итерации. Меняется только правильная интерпретация результата на стороне демо. --- ## 3. Ещё одна настоящая ошибка — индекс внутренние итерации. Меняется только правильная интерпретация результата на стороне демо. --- ## 3. Ещё одна настоящая ошибка — индекс допустимости в DLL При чтении самой библиотеки обнаружился второй независимый дефект. Его тоже допустимости в DLL При чтении самой библиотеки обнаружился второй независимый дефект. Его тоже рекомендую исправить, поскольку он непосредственно затрагивает `transition` без препятствий. В функции `AGP_Manip2D_specialized()` для `mode == 1` и для следующ рекомендую исправить, поскольку он непосредственно затрагивает `transition` без препятствий. В функции `AGP_Manip2D_specialized()` для `mode == 1` и для следующей ветки `else` у тебя написано: При этом внутри `agp_run_branch_mpi()` добавей ветки `else` у тебя написано: При этом внутри `agp_run_branch_mpi()` добавление единицы выполняется **только когда одновременно включены препятствия и режим transition**: ```cpp unsigned fullConstraintIndex = cost.total_constraints(); if constexpr (HasObstacles && IsTransition) { ление единицы выполняется **только когда одновременно включены препятствия и режим transition**: Получается несогласованность между внутренним алгоритмом и экспортируемой функцией. В режиме без препят ++fullConstraintIndex; // ... }

Получается несогласованность между внутренним алгоритмом и экспортируемой функцией. В режиме без препятствий они используют разные значения индекса полностью допустимого решения.

Это влияет на строку:

В результате можетствий они используют разные значения индекса полностью допустимого решения.

Это влияет на строку:

В результате может возвращаться bestQIndexed вместо bestQ, даже когда оптимизатор нашёл полноценное допустимое решение. Это потенциально теряет улучшение, полученное на заключ возвращаться bestQIndexed вместо bestQ, даже когда оптимизатор нашёл полноценное допустимое решение. Это потенциально теряет улучшение, полученное на заключительном этапе оптимизации.

Исправь оба вхождения в AGP_Manip2D_specialized():

cpp
fullConstraintIndex = cost.total_constraints() + (HasObstacles ? ительном этапе оптимизации. **Исправь оба вхождения** в `AGP_Manip2D_specialized()`: Такой код согласован с внутренним индексом, поскольку обе ветки `mode == 1` и `else`1u : 0u);

Такой код согласован с внутренним индексом, поскольку обе ветки mode == 1 и else запускают алгоритм с IsTransition = true.

Поскольку HasObstacles — шаблонный параметр времени компиляции, эта поправка не требует дополнительной проверки условия на запускают алгоритм с IsTransition = true.

Поскольку HasObstacles — шаблонный параметр времени компиляции, эта поправка не требует дополнительной проверки условия на каждой итерации.

Я подготовил исправление непосредственно для приложенного исходника библиотеки:

<box border каждой итерации.

Я подготовил исправление непосредственно для приложенного исходника библиотеки:

<box border radius="lg" padding={3} gap={3}> <row align="center" gap={2}> <icon name="file-code" color="secondary" size="lg"/> <box flex="1" gap=1> **[ radius="lg" padding={3} gap={3}> <row align="center" gap={2}> <icon name="file-code" color="secondary" size="lg"/> <box flex="1" gap=1> **[Скачать минимальный патч DLL]** <caption>Два точечных изменения, без изменения остальных функций</caption> </box> <icon name="download" color="Скачать минимальный патч DLL](sandbox:/mnt/data/sobol_transition_index_fix.diff)** <caption>Два точечных изменения, без изменения остальных функций</caption> </box> <icon name="download" color="secondary"/> </row> <divider color="subtle"/> <row align="center" gap={2}> <icon name="file-text" color="secondary" size="lg"/> <box flex="1" gap=1> **[Исправленный исходник библиотеки](sandboxsecondary"/> </row> <divider color="subtle"/> <row align="center" gap={2}> <icon name="file-text" color="secondary" size="lg"/> <box flex="1" gap=1> **[Исправленный исходник библиотеки]** <caption>Полная копия приложенного файла с исправленными индексами</caption> </box> <icon name="download" color="secondary"/> </row> </box>

Проверка:/mnt/data/sobol_transition_index_fixed.tables)** <caption>Полная копия приложенного файла с исправленными индексами</caption> </box> <icon name="download" color="secondary"/> </row> </box>

Проверка применения патча к исходному файлу прошла успешно. <CodeCite tool="container" citation_id="9AcCcB" line_range_start={1} line_range_end={2} применения патча к исходному файлу прошла успешно. <CodeCite tool="container" citation_id="9AcCcB" line_range_start={1} line_range_end={2} />

4. Скрытая проблема с одинаковым seed для начала и конца

Это третья проблема, которая может ухудшать точность и скорость сходимости при переходе между различ />

4. Скрытая проблема с одинаковым seed для начала и конца

Это третья проблема, которая может ухудшать точность и скорость сходимости при переходе между различными целями.

В библиотеке начальные приближения кэшируются по условию:

cpp
if (g_seeds_seed_sig != seed) { g_seedCnt = generate_heuristic_seeds( cost, map, dim, ными целями. В библиотеке начальные приближения кэшируются по условию: Но в демо один tl_seeds.data(), AGP_SEED_STRIDE, seed + 7919u * static_cast<unsigned>(rank) ); g_seeds_seed_sig = seed; }

Но в демо один и тот же seed используется и при расчёте начальной конфигурации, и при расчёте конечной.

Поэтому при вычислении финиша библиотека может повторно использовать начальные приближения, созданные для предыдущей цел и тот же seed используется и при расчёте начальной конфигурации, и при расчёте конечной.

Поэтому при вычислении финиша библиотека может повторно использовать начальные приближения, созданные для предыдущей целевой точки. Сам функционал при этом по-прежнему получает правильные координаты цели, но качество поиска может ухудшаться.

Миниевой точки. Сам функционал при этом по-прежнему получает правильные координаты цели, но качество поиска может ухудшаться.

Минимальная поправка в RunTrajectoryWithAGP():

мальная поправка в RunTrajectoryWithAGP():

Далее в двух вызовах, относящихся именно к вычислению конечного положения, используй finalSeed вместо seed:

  • Далее в двух вызовах, относящихся именно к вычислению конечного положения, используй finalSeedвместоseed`:

  • pStart(...), где передаются targetX, targetY, targetA и mode = 1;

  • fManip(...), где передаются те же координpStart(...), где передаются targetX, targetY, targetAиmode = 1`;

  • fManip(...), где передаются те же координаты и mode = 1.

Начальный расчёт и построитель траектории оставь с исходным seed.

Это сохраняет прежнюю логику оптимизации иаты и mode = 1.

Начальный расчёт и построитель траектории оставь с исходным seed.

Это сохраняет прежнюю логику оптимизации и обеспечивает генерацию приближений для новой цели. Дополнительная генерация происходит обеспечивает генерацию приближений для новой цели. Дополнительная генерация происходит при смене целевой задачи, а не на каждом шаге оптимизатора.


5. Как проверить, что конечная конфигурация больше не теряется

Можно при смене целевой задачи, а не на каждом шаге оптимизатора.


5. Как проверить, что конечная конфигурация больше не теряется

Можно добавить очень дешёвую отладочную проверку непосредственно после вызова pBuildTrajectory(...), перед преобразованием результата в PoseSnapshot.

cpp
#ifdef _DEBUG if (trajPoints != nullptr && pointCount >= добавить очень дешёвую отладочную проверку непосредственно после вызова `pBuildTrajectory(...)`, перед преобразованием результата в `PoseSnapshot`. ```cpp #ifdef _DEBUG if (trajPoints != nullptr && pointCount >= 2) { const float* returnedFinal = trajPoints + static_cast<size_t>(pointCount - 1) * stateDim; for (int i = 0; i < stateDim; ++i) { System::Diagnostics::Debug::Assert( fabsf(returnedFinal[i] - finalState[i]) 2) { const float* returnedFinal = trajPoints + static_cast<size_t>(pointCount - 1) * stateDim; for (int i = 0; i < stateDim; ++i) { System::Diagnostics::Debug::Assert( fabsf(returnedFinal[i] - finalState[i]) < 1e-6f, "AGP trajectory endpoint mismatch" ); } } #endif

В предоставленном исходнике построитель получает finalState через ` < 1e-6f, "AGP trajectory endpoint mismatch" ); } }

#endif

text
В предоставленном исходнике построитель получает `finalState` через `TrajConfig endConfig(finalState, total)` и использует его в качестве правой границы построения. Поэтому последнее состояние корректно сформированной траектории должно совпадTrajConfig endConfig(finalState, total)` и использует его в качестве правой границы построения. Поэтому последнее состояние корректно сформированной траектории должно совпадать с переданным конечным состоянием. Если проверка проходит, но финиш находится не там, гдеать с переданным конечным состоянием. Если проверка проходит, но финиш находится не там, где задана декартова цель, искать следующую причину нужно уже в вычислении `finalQ`, а не в передаче данных через задана декартова цель, искать следующую причину нужно уже в вычислении `finalQ`, а не в передаче данных через построитель. Особенно полезно сравнить координаты, вычисленные напрямую из `finalQ`, с `targetX`, `targetY`, `targetA` **до вызова `pBuildTrajectory`**. --- ## Ит построитель. Особенно полезно сравнить координаты, вычисленные напрямую из `finalQ`, с `targetX`, `targetY`, `targetA` **до вызова `pBuildTrajectory`**. --- ## Итог <box gap={2}> <row align="start" gap={3}> <icon name="check-circle-2" color="success" size="lg"/> <box flex="1" gap=1> **Главная найденог <box gap={2}> <row align="start" gap={3}> <icon name="check-circle-2" color="success" size="lg"/> <box flex="1" gap=1> **Главная найденная ошибка: `stateDim = 2N` вместо `N` при постоянных длинах.** Она непосредственно объясняет некорректное чтение конечнойная ошибка: `stateDim = 2N` вместо `N` при постоянных длинах.** Она непосредственно объясняет некорректное чтение конечной конфигурации и `AccessViolationException` в `BuildPoseFromState()`. </box> </row> <divider color="subtle"/> <row align="start" gap={3}> <icon name="check-circle-2" color="success" size=" конфигурации и `AccessViolationException` в `BuildPoseFromState()`. </box> </row> <divider color="subtle"/> <row align="start" gap={3}> <icon name="check-circle-2" color="success" size="lg"/> <box flex="1" gap=1> **Дополнительная ошибка библиотеки: несовпадающие `fullConstraintIndex`.** Исправляется двумя строками, без изменения вычисlg"/> <box flex="1" gap=1> **Дополнительная ошибка библиотеки: несовпадающие `fullConstraintIndex`.** Исправляется двумя строками, без изменения вычислительного алгоритма и без дополнительной стоимости во время выполнения. </box> </row> <divider color="subtle"/> <row align="start" gap={3}> <icon name="check-circle-2" color="лительного алгоритма и без дополнительной стоимости во время выполнения. </box> </row> <divider color="subtle"/> <row align="start" gap={3}> <icon name="check-circle-2" color="success" size="lg"/> <box flex="1" gap=1> **Дополнительные ошибки демо: устаревший кэш начальных приближений и несsuccess" size="lg"/> <box flex="1" gap=1> **Дополнительные ошибки демо: устаревший кэш начальных приближений и несинхронизированный `variableLengths`.** Исправляются локально, без вмешательства в swept-пинхронизированный `variableLengths`.** Исправляются локально, без вмешательства в swept-проверки, рекурсивные валидации и геометрию. </box> </row> </box> Есть важное разграничение: неправильный `stateDim` выполняроверки, рекурсивные валидации и геометрию. </box> </row> </box> Есть важное разграничение: неправильный `stateDim` выполняется при **чтении уже построенной траектории**. Если программа действительно зависает внутри `pBuildTrajectory()`ется при **чтении уже построенной траектории**. Если программа действительно зависает внутри `pBuildTrajectory()` и этот вызов вообще не возвращается, то зависание нужно исследовать отдельно. Оно не может быть непосредственно вызвано последующим неправильным шагом чтения буфера. В частности и этот вызов вообще не возвращается, то зависание нужно исследовать отдельно. Оно не может быть непосредственно вызвано последующим неправильным шагом чтения буфера. В частности, следует проверить качество `finalQ`, рассчитанного в `mode = 1` с препятствиями. Но для твоего основного симптома — правильная начальная поза, затем неожиданная горизонтальная, следует проверить качество `finalQ`, рассчитанного в `mode = 1` с препятствиями. Но для твоего основного симптома — правильная начальная поза, затем неожиданная горизонтальная конфигурация и авария на чтении `state` — обнаруженное несоответствие размерностей является конкретным, воспроизводимым по исходному коду объяснением. ** конфигурация и авария на чтении `state` — обнаруженное несоответствие размерностей является конкретным, воспроизводимым по исходному коду объяснением. **Я бы начал с трёх исправлений в `MyForm.h` из раздела 2, затем применил двухстрочный патч индекса в DLL иЯ бы начал с трёх исправлений в `MyForm.h` из раздела 2, затем применил двухстрочный патч индекса в DLL и разделил `seed` начального и конечного IK.** Эти изменения не требуют переп разделил `seed` начального и конечного IK.** Эти изменения не требуют переписывания оптимизатора и оставляют его горячие вычислительные пути практически нетронутыми. Проверка выполнисывания оптимизатора и оставляют его горячие вычислительные пути практически нетронутыми. Проверка выполнена по исходникам; фактическую сборку и запуск Windows DLL с MPI в этой среде я не проводил.ена по исходникам; фактическую сборку и запуск Windows DLL с MPI в этой среде я не проводил.

Chia sẻ Q&A này