新增四类连杆统一仿真接口
This commit is contained in:
@@ -444,6 +444,65 @@ func
|
|||||||
- `trajectory`:B 点整段轨迹
|
- `trajectory`:B 点整段轨迹
|
||||||
- `slider_trajectory`:S 点整段滑块轨迹
|
- `slider_trajectory`:S 点整段滑块轨迹
|
||||||
|
|
||||||
|
### 6.3 `Cmd_FourBar_Simulate`
|
||||||
|
|
||||||
|
用途:
|
||||||
|
|
||||||
|
- 统一仿真 PDPS 连杆定义界面中的 `PRRR / RPRR / RRRP / RRRR` 四类结构
|
||||||
|
- 输入机构类型、起始输入、结束输入、总时长和步长时间
|
||||||
|
- 一次性返回逐帧点位、姿态、角度和轨迹,适合前端 Three.js 播放和 ECharts 曲线验证
|
||||||
|
|
||||||
|
调用履历:
|
||||||
|
|
||||||
|
```text
|
||||||
|
func
|
||||||
|
-> dispatchCommand
|
||||||
|
-> handleFourBarCommand
|
||||||
|
-> simulateUnifiedFourBar
|
||||||
|
-> 按 mechanismType 创建或调用对应机构类
|
||||||
|
-> validateParameters
|
||||||
|
-> for each frame:
|
||||||
|
-> calculate(currentInput)
|
||||||
|
-> 组装 frames / trajectory / parameters
|
||||||
|
```
|
||||||
|
|
||||||
|
类型映射:
|
||||||
|
|
||||||
|
- `RRRP`:调用 `CrankSliderMechanism`,角度驱动曲柄滑块正解
|
||||||
|
- `PRRR`:调用 `SliderCrankMechanism`,滑块位移驱动曲柄滑块逆解
|
||||||
|
- `RPRR`:调用 `CrankRockingBlockMechanism_Forward`,当前按曲柄摇块正解承接
|
||||||
|
- `RRRR`:调用 `FourBarMechanism`,角度驱动四转副四杆正解
|
||||||
|
|
||||||
|
主要公共入参:
|
||||||
|
|
||||||
|
- `mechanismType`:`PRRR`、`RPRR`、`RRRP`、`RRRR`
|
||||||
|
- `startValue` / `endValue`:统一输入范围,角度驱动类型表示角度,`PRRR` 表示滑块 X
|
||||||
|
- `duration`:仿真总时长,单位秒
|
||||||
|
- `stepTime`:仿真步长时间,单位秒
|
||||||
|
|
||||||
|
各类型参数:
|
||||||
|
|
||||||
|
- `RRRP`:`L_AB`、`L_BS`、`S_OFS`
|
||||||
|
- `PRRR`:`L_AB`、`L_BS`、`S_OFS`,也可使用 `startSliderX` / `endSliderX`
|
||||||
|
- `RPRR`:`OA`、`AB`、`OC`
|
||||||
|
- `RRRR`:`L1`、`L2`、`L3`、`L4`
|
||||||
|
|
||||||
|
主要出参:
|
||||||
|
|
||||||
|
- `mechanismType`:实际仿真的机构类型
|
||||||
|
- `inputName`:当前输入字段名,`angleDeg` 或 `sliderX`
|
||||||
|
- `frames[]`:逐帧仿真数据,每帧包含 `frame`、`time`、`inputValue`、`points`、`poses`、`angles`
|
||||||
|
- `trajectory`:主运动点轨迹
|
||||||
|
- `slider_trajectory`:滑块轨迹,适用于 `RRRP / PRRR`
|
||||||
|
- `alternative_trajectory`:备选逆解轨迹,适用于 `PRRR`
|
||||||
|
- `trajectory_c`:C 点轨迹,适用于 `RRRR`
|
||||||
|
- `crank_circle`:曲柄端点轨迹,适用于 `RPRR / RRRR`
|
||||||
|
- `rocker_trajectory`:摇块轨迹,适用于 `RPRR`
|
||||||
|
|
||||||
|
注意:
|
||||||
|
|
||||||
|
- `RPRR` 当前先复用现有曲柄摇块正解类,PDPS 中输入/输出链节的方向、坐标系和安装约定后续如有更精确资料,可继续对齐参数语义。
|
||||||
|
|
||||||
## 7. 四足机器人接口履历
|
## 7. 四足机器人接口履历
|
||||||
|
|
||||||
命令文件:
|
命令文件:
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -418,6 +418,71 @@ const suite = [
|
|||||||
{ path: "res_data.slider_trajectory", lengthEquals: 5 },
|
{ path: "res_data.slider_trajectory", lengthEquals: 5 },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "fourbar_unified_rrrp",
|
||||||
|
type: "static",
|
||||||
|
requestFile: "tests/testdata/fourbar/simulate_rrrp.json",
|
||||||
|
assertions: [
|
||||||
|
{ path: "success", equals: true },
|
||||||
|
{ path: "res_data.success", equals: true },
|
||||||
|
{ path: "res_data.mechanismType", equals: "RRRP" },
|
||||||
|
{ path: "res_data.frame_count", equals: 5 },
|
||||||
|
{ path: "res_data.frames", lengthEquals: 5 },
|
||||||
|
{ path: "res_data.frames.0.points.B.x", exists: true },
|
||||||
|
{ path: "res_data.frames.0.points.S.x", exists: true },
|
||||||
|
{ path: "res_data.trajectory", lengthEquals: 5 },
|
||||||
|
{ path: "res_data.slider_trajectory", lengthEquals: 5 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "fourbar_unified_prrr",
|
||||||
|
type: "static",
|
||||||
|
requestFile: "tests/testdata/fourbar/simulate_prrr.json",
|
||||||
|
assertions: [
|
||||||
|
{ path: "success", equals: true },
|
||||||
|
{ path: "res_data.success", equals: true },
|
||||||
|
{ path: "res_data.mechanismType", equals: "PRRR" },
|
||||||
|
{ path: "res_data.inputName", equals: "sliderX" },
|
||||||
|
{ path: "res_data.frame_count", equals: 5 },
|
||||||
|
{ path: "res_data.frames.0.points.B.x", exists: true },
|
||||||
|
{ path: "res_data.frames.0.points.S.x", exists: true },
|
||||||
|
{ path: "res_data.trajectory", lengthEquals: 5 },
|
||||||
|
{ path: "res_data.slider_trajectory", lengthEquals: 5 },
|
||||||
|
{ path: "res_data.alternative_trajectory", lengthEquals: 5 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "fourbar_unified_rprr",
|
||||||
|
type: "static",
|
||||||
|
requestFile: "tests/testdata/fourbar/simulate_rprr.json",
|
||||||
|
assertions: [
|
||||||
|
{ path: "success", equals: true },
|
||||||
|
{ path: "res_data.success", equals: true },
|
||||||
|
{ path: "res_data.mechanismType", equals: "RPRR" },
|
||||||
|
{ path: "res_data.frame_count", equals: 5 },
|
||||||
|
{ path: "res_data.frames.0.points.O.x", exists: true },
|
||||||
|
{ path: "res_data.frames.0.points.B.x", exists: true },
|
||||||
|
{ path: "res_data.trajectory", lengthEquals: 5 },
|
||||||
|
{ path: "res_data.crank_circle", lengthEquals: 5 },
|
||||||
|
{ path: "res_data.rocker_trajectory", lengthEquals: 5 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "fourbar_unified_rrrr",
|
||||||
|
type: "static",
|
||||||
|
requestFile: "tests/testdata/fourbar/simulate_rrrr.json",
|
||||||
|
assertions: [
|
||||||
|
{ path: "success", equals: true },
|
||||||
|
{ path: "res_data.success", equals: true },
|
||||||
|
{ path: "res_data.mechanismType", equals: "RRRR" },
|
||||||
|
{ path: "res_data.frame_count", equals: 5 },
|
||||||
|
{ path: "res_data.frames.0.points.A.x", exists: true },
|
||||||
|
{ path: "res_data.frames.0.points.D.x", exists: true },
|
||||||
|
{ path: "res_data.trajectory", lengthEquals: 5 },
|
||||||
|
{ path: "res_data.trajectory_c", lengthEquals: 5 },
|
||||||
|
{ path: "res_data.crank_circle", lengthEquals: 5 },
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "quadruped_points_from_motor_angles",
|
id: "quadruped_points_from_motor_angles",
|
||||||
type: "static",
|
type: "static",
|
||||||
|
|||||||
@@ -122,7 +122,8 @@ json KinematicsWebAPI::dispatchCommand(const std::string &req_cmd, const json &r
|
|||||||
return handleSpcCommand(req_cmd, req_param);
|
return handleSpcCommand(req_cmd, req_param);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req_cmd == "Cmd_FourBar_CrankSlider" ||
|
if (req_cmd == "Cmd_FourBar_Simulate" ||
|
||||||
|
req_cmd == "Cmd_FourBar_CrankSlider" ||
|
||||||
req_cmd == "Cmd_FourBar_CrankSlider_Simulate")
|
req_cmd == "Cmd_FourBar_CrankSlider_Simulate")
|
||||||
{
|
{
|
||||||
return handleFourBarCommand(req_cmd, req_param);
|
return handleFourBarCommand(req_cmd, req_param);
|
||||||
|
|||||||
@@ -1,9 +1,45 @@
|
|||||||
#include "KinematicsWebAPI.h"
|
#include "KinematicsWebAPI.h"
|
||||||
#include "FourBarMechanism/CrankSliderMechanism.h"
|
#include "FourBarMechanism/CrankSliderMechanism.h"
|
||||||
|
#include "FourBarMechanism/CrankRockingBlockMechanism_Forward.h"
|
||||||
|
#include "FourBarMechanism/FourBarMechanism.h"
|
||||||
|
#include "FourBarMechanism/SliderCrankMechanism.h"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
// 读取兼容字段,便于新统一接口沿用旧曲柄滑块参数名。
|
||||||
|
double valueAny(const json ¶m, std::initializer_list<const char *> keys, double defaultValue)
|
||||||
|
{
|
||||||
|
for (const char *key : keys)
|
||||||
|
{
|
||||||
|
if (param.contains(key) && param[key].is_number())
|
||||||
|
{
|
||||||
|
return param[key].get<double>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构造统一的业务失败返回,供四类连杆仿真复用。
|
||||||
|
json buildErrorJson(const std::string &error, const json &validationErrors = json::array(), const json &validationWarnings = json::array())
|
||||||
|
{
|
||||||
|
json result = {
|
||||||
|
{"success", false},
|
||||||
|
{"error", error}};
|
||||||
|
|
||||||
|
if (!validationErrors.empty())
|
||||||
|
{
|
||||||
|
result["validation_errors"] = validationErrors;
|
||||||
|
}
|
||||||
|
if (!validationWarnings.empty())
|
||||||
|
{
|
||||||
|
result["validation_warnings"] = validationWarnings;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// 将机构点位转换为接口统一 JSON。
|
// 将机构点位转换为接口统一 JSON。
|
||||||
json buildPointsJson(const MechanismState &state)
|
json buildPointsJson(const MechanismState &state)
|
||||||
{
|
{
|
||||||
@@ -60,12 +96,14 @@ json buildTrajectoryJson(const std::vector<Vector2D> &points)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 组装单帧机构状态,供实时接口和批量仿真接口复用。
|
// 组装单帧机构状态,供实时接口和批量仿真接口复用。
|
||||||
json buildFrameJson(const MechanismState &state, int frame, double time, double angleDeg)
|
json buildFrameJson(const MechanismState &state, int frame, double time, double inputValue, const std::string &inputName)
|
||||||
{
|
{
|
||||||
json frame_json;
|
json frame_json;
|
||||||
frame_json["frame"] = frame;
|
frame_json["frame"] = frame;
|
||||||
frame_json["time"] = time;
|
frame_json["time"] = time;
|
||||||
frame_json["angleDeg"] = angleDeg;
|
frame_json[inputName] = inputValue;
|
||||||
|
frame_json["inputName"] = inputName;
|
||||||
|
frame_json["inputValue"] = inputValue;
|
||||||
frame_json["input_value"] = state.InputValue;
|
frame_json["input_value"] = state.InputValue;
|
||||||
frame_json["points"] = buildPointsJson(state);
|
frame_json["points"] = buildPointsJson(state);
|
||||||
frame_json["poses"] = buildPosesJson(state);
|
frame_json["poses"] = buildPosesJson(state);
|
||||||
@@ -76,6 +114,260 @@ json buildFrameJson(const MechanismState &state, int frame, double time, double
|
|||||||
}
|
}
|
||||||
return frame_json;
|
return frame_json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 校验仿真时间参数并返回帧数。
|
||||||
|
json validateSimulationTimeline(double duration, double stepTime, int &frameCount)
|
||||||
|
{
|
||||||
|
if (duration <= 0.0)
|
||||||
|
{
|
||||||
|
return buildErrorJson("Invalid simulation parameters", json::array({"duration 必须大于 0"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stepTime <= 0.0 || stepTime > duration)
|
||||||
|
{
|
||||||
|
return buildErrorJson("Invalid simulation parameters", json::array({"stepTime 必须大于 0 且不能大于 duration"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
frameCount = static_cast<int>(std::ceil(duration / stepTime)) + 1;
|
||||||
|
if (frameCount < 2 || frameCount > 1000)
|
||||||
|
{
|
||||||
|
return buildErrorJson("Invalid simulation parameters", json::array({"仿真帧数必须在 2 到 1000 之间"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return json();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将 ValidationResult 转换为统一业务错误。
|
||||||
|
json validateOrError(const ValidationResult &validation)
|
||||||
|
{
|
||||||
|
if (validation.isValid())
|
||||||
|
{
|
||||||
|
return json();
|
||||||
|
}
|
||||||
|
|
||||||
|
return buildErrorJson("Invalid parameters", validation.Errors, validation.Warnings);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按统一格式生成逐帧仿真数据。
|
||||||
|
template <typename CalculateFunc>
|
||||||
|
json buildSimulationFrames(int frameCount, double duration, double stepTime, double startValue, double endValue, const std::string &inputName, CalculateFunc calculate)
|
||||||
|
{
|
||||||
|
json frames_json = json::array();
|
||||||
|
for (int frame = 0; frame < frameCount; ++frame)
|
||||||
|
{
|
||||||
|
const double currentTime = frame == frameCount - 1 ? duration : stepTime * frame;
|
||||||
|
const double progress = duration <= 0.0 ? 0.0 : currentTime / duration;
|
||||||
|
const double currentValue = startValue + (endValue - startValue) * progress;
|
||||||
|
MechanismState state = calculate(currentValue);
|
||||||
|
if (state.hasError())
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
{"success", false},
|
||||||
|
{"error", state.ErrorMessage},
|
||||||
|
{"failed_frame", frame},
|
||||||
|
{"failed_time", currentTime},
|
||||||
|
{"failed_input", currentValue},
|
||||||
|
{"failed_input_name", inputName}};
|
||||||
|
}
|
||||||
|
|
||||||
|
frames_json.push_back(buildFrameJson(state, frame, currentTime, currentValue, inputName));
|
||||||
|
}
|
||||||
|
|
||||||
|
return frames_json;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统一四连杆仿真接口,覆盖 PDPS 的 PRRR/RPRR/RRRP/RRRR 四类结构。
|
||||||
|
json simulateUnifiedFourBar(const json &req_param)
|
||||||
|
{
|
||||||
|
const std::string mechanismType = req_param.value("mechanismType", "RRRP");
|
||||||
|
const double duration = req_param.value("duration", 2.0);
|
||||||
|
const double stepTime = req_param.value("stepTime", 0.02);
|
||||||
|
int frameCount = 0;
|
||||||
|
|
||||||
|
json timelineError = validateSimulationTimeline(duration, stepTime, frameCount);
|
||||||
|
if (!timelineError.is_null())
|
||||||
|
{
|
||||||
|
return timelineError;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mechanismType == "RRRP")
|
||||||
|
{
|
||||||
|
const double L_AB = req_param.value("L_AB", 0.5);
|
||||||
|
const double L_BS = req_param.value("L_BS", 2.0);
|
||||||
|
const double S_OFS = req_param.value("S_OFS", 0.0);
|
||||||
|
const double startAngleDeg = valueAny(req_param, {"startAngleDeg", "startValue", "angleDeg"}, 0.0);
|
||||||
|
const double endAngleDeg = valueAny(req_param, {"endAngleDeg", "endValue"}, 360.0);
|
||||||
|
|
||||||
|
std::unique_ptr<CrankSliderMechanism> mechanism(createCrankSliderMechanism());
|
||||||
|
mechanism->setL_AB(L_AB);
|
||||||
|
mechanism->setL_BS(L_BS);
|
||||||
|
mechanism->setS_OFS(S_OFS);
|
||||||
|
|
||||||
|
json validationError = validateOrError(mechanism->validateParameters());
|
||||||
|
if (!validationError.is_null())
|
||||||
|
{
|
||||||
|
return validationError;
|
||||||
|
}
|
||||||
|
|
||||||
|
json frames_json = buildSimulationFrames(frameCount, duration, stepTime, startAngleDeg, endAngleDeg, "angleDeg", [&](double value) {
|
||||||
|
return mechanism->calculate(value);
|
||||||
|
});
|
||||||
|
if (!frames_json.is_array())
|
||||||
|
{
|
||||||
|
return frames_json;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
{"success", true},
|
||||||
|
{"mechanismType", mechanismType},
|
||||||
|
{"inputName", "angleDeg"},
|
||||||
|
{"frames", frames_json},
|
||||||
|
{"frame_count", frameCount},
|
||||||
|
{"duration", duration},
|
||||||
|
{"stepTime", stepTime},
|
||||||
|
{"startValue", startAngleDeg},
|
||||||
|
{"endValue", endAngleDeg},
|
||||||
|
{"startAngleDeg", startAngleDeg},
|
||||||
|
{"endAngleDeg", endAngleDeg},
|
||||||
|
{"trajectory", buildTrajectoryJson(mechanism->getTrajectoryPoints())},
|
||||||
|
{"slider_trajectory", buildTrajectoryJson(mechanism->getSliderTrajectory())},
|
||||||
|
{"parameters", {{"mechanismType", mechanismType}, {"L_AB", L_AB}, {"L_BS", L_BS}, {"S_OFS", S_OFS}, {"startAngleDeg", startAngleDeg}, {"endAngleDeg", endAngleDeg}, {"duration", duration}, {"stepTime", stepTime}}}};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mechanismType == "PRRR")
|
||||||
|
{
|
||||||
|
const double L_AB = req_param.value("L_AB", 0.5);
|
||||||
|
const double L_BS = req_param.value("L_BS", 2.0);
|
||||||
|
const double S_OFS = req_param.value("S_OFS", 0.0);
|
||||||
|
|
||||||
|
std::unique_ptr<SliderCrankMechanism> mechanism(createSliderCrankMechanism());
|
||||||
|
mechanism->setLink(L_AB, L_BS, S_OFS);
|
||||||
|
|
||||||
|
json validationError = validateOrError(mechanism->validateParameters());
|
||||||
|
if (!validationError.is_null())
|
||||||
|
{
|
||||||
|
return validationError;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto inputRange = mechanism->getInputRange();
|
||||||
|
const double startSliderX = valueAny(req_param, {"startSliderX", "startValue", "sliderX"}, inputRange.first);
|
||||||
|
const double endSliderX = valueAny(req_param, {"endSliderX", "endValue"}, inputRange.second);
|
||||||
|
json frames_json = buildSimulationFrames(frameCount, duration, stepTime, startSliderX, endSliderX, "sliderX", [&](double value) {
|
||||||
|
return mechanism->calculate(value);
|
||||||
|
});
|
||||||
|
if (!frames_json.is_array())
|
||||||
|
{
|
||||||
|
return frames_json;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
{"success", true},
|
||||||
|
{"mechanismType", mechanismType},
|
||||||
|
{"inputName", "sliderX"},
|
||||||
|
{"inputRange", {{"min", inputRange.first}, {"max", inputRange.second}}},
|
||||||
|
{"frames", frames_json},
|
||||||
|
{"frame_count", frameCount},
|
||||||
|
{"duration", duration},
|
||||||
|
{"stepTime", stepTime},
|
||||||
|
{"startValue", startSliderX},
|
||||||
|
{"endValue", endSliderX},
|
||||||
|
{"startSliderX", startSliderX},
|
||||||
|
{"endSliderX", endSliderX},
|
||||||
|
{"trajectory", buildTrajectoryJson(mechanism->getTrajectoryPoints())},
|
||||||
|
{"slider_trajectory", buildTrajectoryJson(mechanism->getSliderTrajectory())},
|
||||||
|
{"alternative_trajectory", buildTrajectoryJson(mechanism->getAlternativeTrajectory())},
|
||||||
|
{"parameters", {{"mechanismType", mechanismType}, {"L_AB", L_AB}, {"L_BS", L_BS}, {"S_OFS", S_OFS}, {"startSliderX", startSliderX}, {"endSliderX", endSliderX}, {"duration", duration}, {"stepTime", stepTime}}}};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mechanismType == "RRRR")
|
||||||
|
{
|
||||||
|
const double L1 = valueAny(req_param, {"L1", "L_AB"}, 1.0);
|
||||||
|
const double L2 = valueAny(req_param, {"L2", "L_BS"}, 3.0);
|
||||||
|
const double L3 = req_param.value("L3", 2.5);
|
||||||
|
const double L4 = req_param.value("L4", 3.5);
|
||||||
|
const double startAngleDeg = valueAny(req_param, {"startAngleDeg", "startValue", "angleDeg"}, 0.0);
|
||||||
|
const double endAngleDeg = valueAny(req_param, {"endAngleDeg", "endValue"}, 180.0);
|
||||||
|
|
||||||
|
std::unique_ptr<FourBarMechanism> mechanism(createFourBarMechanism());
|
||||||
|
mechanism->setLink(L1, L2, L3, L4);
|
||||||
|
|
||||||
|
json validationError = validateOrError(mechanism->validateParameters());
|
||||||
|
if (!validationError.is_null())
|
||||||
|
{
|
||||||
|
return validationError;
|
||||||
|
}
|
||||||
|
|
||||||
|
json frames_json = buildSimulationFrames(frameCount, duration, stepTime, startAngleDeg, endAngleDeg, "angleDeg", [&](double value) {
|
||||||
|
return mechanism->calculate(value);
|
||||||
|
});
|
||||||
|
if (!frames_json.is_array())
|
||||||
|
{
|
||||||
|
return frames_json;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
{"success", true},
|
||||||
|
{"mechanismType", mechanismType},
|
||||||
|
{"inputName", "angleDeg"},
|
||||||
|
{"frames", frames_json},
|
||||||
|
{"frame_count", frameCount},
|
||||||
|
{"duration", duration},
|
||||||
|
{"stepTime", stepTime},
|
||||||
|
{"startValue", startAngleDeg},
|
||||||
|
{"endValue", endAngleDeg},
|
||||||
|
{"startAngleDeg", startAngleDeg},
|
||||||
|
{"endAngleDeg", endAngleDeg},
|
||||||
|
{"trajectory", buildTrajectoryJson(mechanism->getTrajectoryPoints())},
|
||||||
|
{"trajectory_c", buildTrajectoryJson(mechanism->getTrajectoryC())},
|
||||||
|
{"crank_circle", buildTrajectoryJson(mechanism->getCrankCirclePoints())},
|
||||||
|
{"parameters", {{"mechanismType", mechanismType}, {"L1", L1}, {"L2", L2}, {"L3", L3}, {"L4", L4}, {"startAngleDeg", startAngleDeg}, {"endAngleDeg", endAngleDeg}, {"duration", duration}, {"stepTime", stepTime}}}};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mechanismType == "RPRR")
|
||||||
|
{
|
||||||
|
const double OA = valueAny(req_param, {"OA", "L_AB"}, 1.0);
|
||||||
|
const double AB = valueAny(req_param, {"AB", "L_BS"}, 3.0);
|
||||||
|
const double OC = valueAny(req_param, {"OC", "L4"}, 3.0);
|
||||||
|
const double startAngleDeg = valueAny(req_param, {"startAngleDeg", "startValue", "angleDeg"}, 0.0);
|
||||||
|
const double endAngleDeg = valueAny(req_param, {"endAngleDeg", "endValue"}, 180.0);
|
||||||
|
|
||||||
|
CrankRockingBlockMechanism_Forward mechanism;
|
||||||
|
mechanism.setLink(OA, AB, OC);
|
||||||
|
|
||||||
|
json validationError = validateOrError(mechanism.validateParameters());
|
||||||
|
if (!validationError.is_null())
|
||||||
|
{
|
||||||
|
return validationError;
|
||||||
|
}
|
||||||
|
|
||||||
|
json frames_json = buildSimulationFrames(frameCount, duration, stepTime, startAngleDeg, endAngleDeg, "angleDeg", [&](double value) {
|
||||||
|
return mechanism.calculate(value);
|
||||||
|
});
|
||||||
|
if (!frames_json.is_array())
|
||||||
|
{
|
||||||
|
return frames_json;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
{"success", true},
|
||||||
|
{"mechanismType", mechanismType},
|
||||||
|
{"inputName", "angleDeg"},
|
||||||
|
{"frames", frames_json},
|
||||||
|
{"frame_count", frameCount},
|
||||||
|
{"duration", duration},
|
||||||
|
{"stepTime", stepTime},
|
||||||
|
{"startValue", startAngleDeg},
|
||||||
|
{"endValue", endAngleDeg},
|
||||||
|
{"startAngleDeg", startAngleDeg},
|
||||||
|
{"endAngleDeg", endAngleDeg},
|
||||||
|
{"trajectory", buildTrajectoryJson(mechanism.getTrajectoryPoints())},
|
||||||
|
{"crank_circle", buildTrajectoryJson(mechanism.getCrankCirclePoints())},
|
||||||
|
{"rocker_trajectory", buildTrajectoryJson(mechanism.getRockerTrajectory())},
|
||||||
|
{"parameters", {{"mechanismType", mechanismType}, {"OA", OA}, {"AB", AB}, {"OC", OC}, {"startAngleDeg", startAngleDeg}, {"endAngleDeg", endAngleDeg}, {"duration", duration}, {"stepTime", stepTime}}}};
|
||||||
|
}
|
||||||
|
|
||||||
|
return buildErrorJson("Unsupported mechanismType: " + mechanismType, json::array({"mechanismType 必须是 PRRR、RPRR、RRRP、RRRR 之一"}));
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
json KinematicsWebAPI::handleFourBarCommand(const std::string &req_cmd, const json &req_param)
|
json KinematicsWebAPI::handleFourBarCommand(const std::string &req_cmd, const json &req_param)
|
||||||
@@ -84,6 +376,11 @@ json KinematicsWebAPI::handleFourBarCommand(const std::string &req_cmd, const js
|
|||||||
{
|
{
|
||||||
log("Handling " + req_cmd + " command");
|
log("Handling " + req_cmd + " command");
|
||||||
|
|
||||||
|
if (req_cmd == "Cmd_FourBar_Simulate")
|
||||||
|
{
|
||||||
|
return simulateUnifiedFourBar(req_param);
|
||||||
|
}
|
||||||
|
|
||||||
double L_AB = req_param.value("L_AB", 0.5);
|
double L_AB = req_param.value("L_AB", 0.5);
|
||||||
double L_BS = req_param.value("L_BS", 2.0);
|
double L_BS = req_param.value("L_BS", 2.0);
|
||||||
double S_OFS = req_param.value("S_OFS", 0.0);
|
double S_OFS = req_param.value("S_OFS", 0.0);
|
||||||
@@ -164,7 +461,7 @@ json KinematicsWebAPI::handleFourBarCommand(const std::string &req_cmd, const js
|
|||||||
{"failed_angleDeg", currentAngleDeg}};
|
{"failed_angleDeg", currentAngleDeg}};
|
||||||
}
|
}
|
||||||
|
|
||||||
frames_json.push_back(buildFrameJson(state, frame, currentTime, currentAngleDeg));
|
frames_json.push_back(buildFrameJson(state, frame, currentTime, currentAngleDeg, "angleDeg"));
|
||||||
}
|
}
|
||||||
|
|
||||||
json result;
|
json result;
|
||||||
|
|||||||
16
tests/testdata/fourbar/simulate_prrr.json
vendored
Normal file
16
tests/testdata/fourbar/simulate_prrr.json
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"msg": "fourbar unified simulate PRRR",
|
||||||
|
"req_code": "CASE_FB_UNIFIED_PRRR",
|
||||||
|
"req_from": "wasm_test",
|
||||||
|
"req_cmd": "Cmd_FourBar_Simulate",
|
||||||
|
"req_param": {
|
||||||
|
"mechanismType": "PRRR",
|
||||||
|
"L_AB": 0.5,
|
||||||
|
"L_BS": 2.0,
|
||||||
|
"S_OFS": 0.0,
|
||||||
|
"startSliderX": 1.5,
|
||||||
|
"endSliderX": 2.5,
|
||||||
|
"duration": 1.0,
|
||||||
|
"stepTime": 0.25
|
||||||
|
}
|
||||||
|
}
|
||||||
16
tests/testdata/fourbar/simulate_rprr.json
vendored
Normal file
16
tests/testdata/fourbar/simulate_rprr.json
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"msg": "fourbar unified simulate RPRR",
|
||||||
|
"req_code": "CASE_FB_UNIFIED_RPRR",
|
||||||
|
"req_from": "wasm_test",
|
||||||
|
"req_cmd": "Cmd_FourBar_Simulate",
|
||||||
|
"req_param": {
|
||||||
|
"mechanismType": "RPRR",
|
||||||
|
"OA": 1.0,
|
||||||
|
"AB": 3.0,
|
||||||
|
"OC": 3.0,
|
||||||
|
"startAngleDeg": 0.0,
|
||||||
|
"endAngleDeg": 180.0,
|
||||||
|
"duration": 1.0,
|
||||||
|
"stepTime": 0.25
|
||||||
|
}
|
||||||
|
}
|
||||||
16
tests/testdata/fourbar/simulate_rrrp.json
vendored
Normal file
16
tests/testdata/fourbar/simulate_rrrp.json
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"msg": "fourbar unified simulate RRRP",
|
||||||
|
"req_code": "CASE_FB_UNIFIED_RRRP",
|
||||||
|
"req_from": "wasm_test",
|
||||||
|
"req_cmd": "Cmd_FourBar_Simulate",
|
||||||
|
"req_param": {
|
||||||
|
"mechanismType": "RRRP",
|
||||||
|
"L_AB": 0.5,
|
||||||
|
"L_BS": 2.0,
|
||||||
|
"S_OFS": 0.0,
|
||||||
|
"startAngleDeg": 0.0,
|
||||||
|
"endAngleDeg": 180.0,
|
||||||
|
"duration": 1.0,
|
||||||
|
"stepTime": 0.25
|
||||||
|
}
|
||||||
|
}
|
||||||
17
tests/testdata/fourbar/simulate_rrrr.json
vendored
Normal file
17
tests/testdata/fourbar/simulate_rrrr.json
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"msg": "fourbar unified simulate RRRR",
|
||||||
|
"req_code": "CASE_FB_UNIFIED_RRRR",
|
||||||
|
"req_from": "wasm_test",
|
||||||
|
"req_cmd": "Cmd_FourBar_Simulate",
|
||||||
|
"req_param": {
|
||||||
|
"mechanismType": "RRRR",
|
||||||
|
"L1": 1.0,
|
||||||
|
"L2": 3.0,
|
||||||
|
"L3": 2.5,
|
||||||
|
"L4": 3.5,
|
||||||
|
"startAngleDeg": 0.0,
|
||||||
|
"endAngleDeg": 180.0,
|
||||||
|
"duration": 1.0,
|
||||||
|
"stepTime": 0.25
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user