Skip to content

Feature/feedback control#12

Merged
manumerous merged 19 commits intomainfrom
feature/feedback_control
Feb 3, 2026
Merged

Feature/feedback control#12
manumerous merged 19 commits intomainfrom
feature/feedback_control

Conversation

@manumerous
Copy link
Owner

@manumerous manumerous commented Feb 1, 2026

Summary by CodeRabbit

  • New Features

    • Unified PD controller supporting implicit and explicit modes.
  • Refactor

    • Control API now takes current and desired states and emits feedback-style joint actions.
    • Joint state fields renamed for brevity (position → q, velocity → v, measured_effort → effort).
    • Action types and hardware API renamed to emphasize feedback semantics.
    • Array/map utilities extended to support optional elements and round-trip vector conversions.
  • Documentation

    • HAL docs updated to reflect new exposed types.
  • Tests

    • Controller, state, array/map, and simulator tests added/updated for new APIs.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 1, 2026

📝 Walkthrough

Walkthrough

Replaces RobotJointAction with RobotJointFeedbackAction across model, HAL, drivers, simulator, and controller APIs; expands controller computeJointControlAction to accept current and desired RobotState; renames joint-state fields (position→q, velocity→v, measured_effort→effort); introduces templated JointPDController and tests.

Changes

Cohort / File(s) Summary
HAL & Driver API
motorium/motorium_hal/include/motorium_hal/DriverBase.h, motorium/motorium_hal/include/motorium_hal/RobotHardware.h
Public API renamed: setJointAction(RobotJointAction)setJointFeedbackAction(RobotJointFeedbackAction); includes and internal driver calls updated.
Controller base API
motorium/motorium_control/include/motorium_control/ControllerBase.h
computeJointControlAction signature changed to accept current_state and desired_state and output RobotJointFeedbackAction; include updated.
PD controller implementation & tests
motorium/motorium_control/include/motorium_control/JointPDController.h, motorium/motorium_control/src/JointPDController.cpp, motorium/motorium_control/test/testImplicitJointPDController.cpp, motorium/motorium_control/test/testExplicitJointPDController.cpp, motorium/motorium_control/BUILD.bazel, motorium/motorium_control/CMakeLists.txt
Replaces ImplicitPDController with templated JointPDController<IsImplicit> and JointPDControllerConfig; adds implicit/explicit code paths; update/add tests and build targets; adapt tests to new signatures and RobotJointFeedbackAction.
Model: joint feedback action
motorium/motorium_model/include/motorium_model/RobotJointFeedbackAction.h
Renames JointActionJointFeedbackAction and RobotJointActionRobotJointFeedbackAction; qd_desv_des; torque calc updated to use v_des.
Model: RobotState
motorium/motorium_model/include/motorium_model/RobotState.h, motorium/motorium_model/src/RobotState.cpp, motorium/motorium_model/test/testRobotState.cpp
Renames JointState fields positionq, velocityv, measured_efforteffort; adds RobotJointState type; updates accessors/mutators and tests.
Simulator integration
motorium/motorium_mujoco/include/motorium_mujoco/MujocoSimInterface.h, motorium/motorium_mujoco/src/MujocoSimInterface.cpp
Public setter renamed to setJointFeedbackAction(...); internal storage type changed to RobotJointFeedbackAction; actuator loop updated to use feedback-action fields.
FixedIDArray / JointIdMap API
motorium/motorium_model/include/motorium_model/FixedIDArray.h, motorium/motorium_model/include/motorium_model/JointIDMap.h
Adds is_optional trait, IDMapInserter concept, fromEigenVector and fromVector insertion APIs; toEigenVector updated to handle optional.
FixedIDArray tests
motorium/motorium_model/test/testFixedIDArray.cpp
Adds comprehensive tests for fromEigenVector / fromVector and round-trip behavior for scalar/struct/class/optional types.
Docs / README
README.md
HAL docs updated to reference RobotJointFeedbackAction in place of RobotJointAction.

Sequence Diagram(s)

sequenceDiagram
    participant Controller as Controller\n(JointPDController)
    participant RobotHardware as RobotHardware
    participant Driver as DriverBase
    participant Simulator as MujocoSimInterface

    rect rgba(200,230,255,0.5)
    Controller->>Controller: computeJointControlAction(current_state, desired_state)
    Controller-->>RobotHardware: RobotJointFeedbackAction (joint_action)
    end

    rect rgba(200,255,230,0.5)
    RobotHardware->>Driver: setJointFeedbackAction(joint_action)
    Driver->>Simulator: setJointFeedbackAction(joint_action)
    Simulator->>Simulator: apply feedback (actuator loop, compute torques)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Poem

🐰 I hop from q to v in moonlit code,
Current and desired in one neat node.
Feedback threads through driver, sim, and heart,
Templated PD hums — a rabbit's art. 🥕

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.41% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The PR title 'Feature/feedback control' is vague and generic. While it references 'feedback control' which relates to the main changes, it lacks specificity about what feedback control features are being introduced or modified. The title does not clearly communicate the primary changes: renaming action types from RobotJointAction to RobotJointFeedbackAction, refactoring controller APIs, and restructuring state parameters. Provide a more specific and descriptive title that clearly indicates the main change, such as 'Refactor PD controller to use feedback action type and split state parameters' or 'Introduce RobotJointFeedbackAction and update controller interfaces'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/feedback_control

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@motorium/motorium_mujoco/src/MujocoSimInterface.cpp`:
- Around line 367-368: The local variable name JointFeedbackAction shadows the
type motorium::model::JointFeedbackAction and violates naming conventions;
rename the local to a conventional variable name (e.g., jointFeedbackAction or
joint_feedback_action) where it is declared from action_internal_.at(idx) and
update its single usage in the mj_data_->ctrl assignment that calls
getTotalFeedbackTorque(...), keeping the same arguments (mj_data_->qpos[i + 7],
mj_data_->qvel[i + 6]) and leaving the rest of the expression unchanged.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
motorium/motorium_control/test/testImplicitPDController.cpp (1)

103-119: 🧹 Nitpick | 🔵 Trivial

Exercise the new desired_state path in tests.
Right now the tests pass the same state for current/desired and only verify gains; adding desired-state values and assertions for q_des/v_des/feed_forward_effort would lock in the new behavior.

✅ Suggested test enhancement
@@ TEST_F(ImplicitPDControllerTest, ComputeAction) {
-  RobotState state(*robot_description_);
-  RobotJointFeedbackAction action(*robot_description_);
-
-  controller.computeJointControlAction(0.0, state, state, action);
+  RobotState current_state(*robot_description_);
+  RobotState desired_state(*robot_description_);
+  joint_index_t idx1 = robot_description_->getJointIndex("joint1");
+  joint_index_t idx2 = robot_description_->getJointIndex("joint2");
+  desired_state.setJointPosition(idx1, 0.25);
+  desired_state.setJointVelocity(idx1, 0.5);
+  desired_state.setJointEffort(idx1, 3.0);
+  desired_state.setJointPosition(idx2, -0.1);
+  desired_state.setJointVelocity(idx2, 0.2);
+  desired_state.setJointEffort(idx2, 4.0);
+  RobotJointFeedbackAction action(*robot_description_);
+
+  controller.computeJointControlAction(0.0, current_state, desired_state, action);
@@
-  joint_index_t idx1 = robot_description_->getJointIndex("joint1");
   EXPECT_DOUBLE_EQ(action[idx1].kp, 10.0);
   EXPECT_DOUBLE_EQ(action[idx1].kd, 1.0);
+  EXPECT_DOUBLE_EQ(action[idx1].q_des, 0.25);
+  EXPECT_DOUBLE_EQ(action[idx1].v_des, 0.5);
+  EXPECT_DOUBLE_EQ(action[idx1].feed_forward_effort, 3.0);
@@
-  joint_index_t idx2 = robot_description_->getJointIndex("joint2");
   EXPECT_DOUBLE_EQ(action[idx2].kp, 20.0);
   EXPECT_DOUBLE_EQ(action[idx2].kd, 2.0);
+  EXPECT_DOUBLE_EQ(action[idx2].q_des, -0.1);
+  EXPECT_DOUBLE_EQ(action[idx2].v_des, 0.2);
+  EXPECT_DOUBLE_EQ(action[idx2].feed_forward_effort, 4.0);
 }
@@ TEST_F(ImplicitPDControllerTest, PartialControl) {
-  RobotState state(*robot_description_);
-  RobotJointFeedbackAction action(*robot_description_);
+  RobotState current_state(*robot_description_);
+  RobotState desired_state(*robot_description_);
+  joint_index_t idx1 = robot_description_->getJointIndex("joint1");
+  joint_index_t idx2 = robot_description_->getJointIndex("joint2");
+  desired_state.setJointPosition(idx2, 0.4);
+  desired_state.setJointVelocity(idx2, 0.6);
+  desired_state.setJointEffort(idx2, 2.5);
+  RobotJointFeedbackAction action(*robot_description_);
@@
-  joint_index_t idx1 = robot_description_->getJointIndex("joint1");
-  joint_index_t idx2 = robot_description_->getJointIndex("joint2");
   action[idx1].kp = 0.0;
   action[idx2].kp = 0.0;
@@
-  controller.computeJointControlAction(0.0, state, state, action);
+  controller.computeJointControlAction(0.0, current_state, desired_state, action);
@@
   EXPECT_DOUBLE_EQ(action[idx1].kp, 0.0);  // Should be untouched
   EXPECT_DOUBLE_EQ(action[idx2].kp, 5.0);
   EXPECT_DOUBLE_EQ(action[idx2].kd, 0.5);
+  EXPECT_DOUBLE_EQ(action[idx2].q_des, 0.4);
+  EXPECT_DOUBLE_EQ(action[idx2].v_des, 0.6);
+  EXPECT_DOUBLE_EQ(action[idx2].feed_forward_effort, 2.5);
 }

Also applies to: 134-147

🤖 Fix all issues with AI agents
In `@motorium/motorium_control/src/ImplicitPDController.cpp`:
- Around line 51-62: Rename the source file from ImplicitPDController.cpp to
ImplicitJointPDController.cpp to match the actual implementation name, and
update any references (build target, includes) accordingly; also mark the unused
parameter current_state in ImplicitJointPDController::computeJointControlAction
with [[maybe_unused]] (matching the existing annotation on time) so the
signature reads with both time and current_state annotated for clarity and
consistency.

In `@motorium/motorium_model/include/motorium_model/RobotState.h`:
- Around line 97-104: Change the parameter type for both getJointPositions and
getJointVelocities from std::vector<joint_index_t> (by-value) to const
std::vector<joint_index_t>& to avoid copying the vector; update the function
declarations and any callers if necessary, while keeping the body using
joint_state_map_.toVector(joint_ids, ...) unchanged (functions:
getJointPositions and getJointVelocities).
- Around line 83-93: Parameters in the RobotState setters use mixed naming
styles; make them consistent by renaming the parameters in setJointVelocity and
setJointEffort to snake_case (e.g., joint_velocity, joint_effort) to match
setJointPosition's joint_position, and update their uses inside the functions
(setJointVelocity -> joint_state_map_.at(joint_id).v = joint_velocity;
setJointEffort -> joint_state_map_.at(joint_id).effort = joint_effort) so
identifiers match; keep the getter signatures unchanged.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@motorium/motorium_control/src/ImplicitJointPDController.cpp`:
- Around line 52-55: Add a brief clarifying comment inside
ImplicitJointPDController::computeJointControlAction explaining why the
current_state parameter is intentionally unused: state that this controller only
sets gains and desired setpoints and that actual feedback computation is
performed at the driver level (via getTotalFeedbackTorque), so current_state is
not needed here. Place the comment near the function signature or at the top of
the function body and reference current_state and getTotalFeedbackTorque to make
the design intent explicit for future maintainers.

In `@motorium/motorium_control/test/testImplicitJointPDController.cpp`:
- Line 108: The test calls controller.computeJointControlAction(0.0, state,
state, action) using the same State for current and desired, so it doesn't
verify that desired q/v/ff are copied from desired_state; add new assertions by
creating a second State (e.g., desired_state) with different joint
positions/velocities/feed_forward_effort and call computeJointControlAction(0.0,
state, desired_state, action) (and similarly for PartialControl test), then
assert that action.q_des, action.v_des, and action.feed_forward_effort match the
values set in desired_state while control outputs reflect the difference between
current_state and desired_state.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@motorium/motorium_control/CMakeLists.txt`:
- Around line 64-73: CMakeLists.txt declares a test target
test_explicit_pd_controller that references
test/testExplicitJointPDController.cpp which doesn't exist; either add a new
test source file named testExplicitJointPDController.cpp under the
motorium_control/test/ directory implementing the explicit PD controller unit
test (matching the style of testImplicitJointPDController.cpp), or remove the
ament_add_gtest and associated target_link_libraries block for
test_explicit_pd_controller from CMakeLists.txt to eliminate the broken target;
search for the symbols test_explicit_pd_controller and
testExplicitJointPDController.cpp in CMakeLists.txt to locate the lines to
update.
- Around line 39-42: The CMake add_library lists
src/ExplicitJointPDController.cpp which (and its header
ExplicitJointPDController.h and potential test
testExplicitJointPDController.cpp) are missing and will break the build; add a
matching implementation and header for the ExplicitJointPDController class
(matching the interface/pattern used by ImplicitJointPDController: class name
ExplicitJointPDController, constructors/destructors, public control methods and
any virtual overrides) and create the test source
testExplicitJointPDController.cpp if CMake references a test target, or
alternatively remove the missing file entries from the add_library()/test target
if you intend not to provide them; ensure the new files compile and are
referenced consistently with the existing ImplicitJointPDController symbols and
the add_library call.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@motorium/motorium_control/include/motorium_control/JointPDController.h`:
- Around line 46-51: The comment block in JointPDController.h contains a typo:
"therms" should be "terms"; update the documentation in the block that describes
the implicit and explicit PD controllers (the comment above or within the
JointPDController class/definition) to replace both occurrences of "therms" with
"terms" so the description reads "...computes the feedback terms itself..." and
"...forwards the feedback torques to the driver."
- Line 59: The header declares an unused member function validateConfig() in
class JointPDController but there is no implementation and the code uses
config_.validate() instead; remove the validateConfig() declaration from
JointPDController.h (the unused symbol validateConfig) to clean up the interface
and avoid confusion, ensuring no remaining references to
JointPDController::validateConfig exist (update any calls or tests if found).

In `@motorium/motorium_control/test/testExplicitJointPDController.cpp`:
- Around line 56-78: Add test parity with the implicit controller by adding two
tests under JointPDControllerTest that mirror the implicit suite: (1)
InitializationMissingJoint — construct a JointPDControllerConfig with a joint
name that does not exist and assert construction fails (use the same
EXPECT_DEATH pattern used by the implicit tests) when creating
ExplicitJointPDController(*robot_description_, config); (2) PartialControl —
create a config where kp/kd vectors are larger than the provided joint_names,
instantiate ExplicitJointPDController, call the same control step / torque
computation helper used in the implicit PartialControl test, and assert the
controller only applies control for the specified joint_names and leaves other
joints unaffected (compare torques/outputs to expected values). Reference
ExplicitJointPDController, JointPDControllerConfig, and JointPDControllerTest to
locate where to add these tests.
- Around line 40-54: Rename the test fixture class JointPDControllerTest to
ExplicitJointPDControllerTest and update all TEST_F usages that reference
JointPDControllerTest to use ExplicitJointPDControllerTest instead; specifically
change the class declaration "class JointPDControllerTest" and every
TEST_F(JointPDControllerTest, ...) to TEST_F(ExplicitJointPDControllerTest, ...)
so the explicit-PD tests no longer collide with the implicit-PD fixture name.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
motorium/motorium_model/include/motorium_model/FixedIDArray.h (1)

32-36: ⚠️ Potential issue | 🟡 Minor

Missing <optional> header include.

The is_optional trait specialization on line 51 uses std::optional<T>, but <optional> is not included. This relies on transitive inclusion which is fragile.

Suggested fix
 `#include` <Eigen/Dense>
 `#include` <concepts>
 `#include` <memory>
+#include <optional>
 `#include` <span>
🤖 Fix all issues with AI agents
In `@motorium/motorium_model/include/motorium_model/FixedIDArray.h`:
- Line 161: The debug-only assertion MT_DCHECK(std::ranges::size(range) ==
vector.size()) must be replaced with a runtime check to prevent out-of-bounds
access in release builds: change MT_DCHECK to MT_CHECK (i.e.,
MT_CHECK(std::ranges::size(range) == vector.size())) at the same location in
FixedIDArray.h, and include a clear error message describing the mismatched
sizes if your MT_CHECK API accepts a message (e.g., "range size must equal
vector.size()"); keep the surrounding code and logic unchanged.
- Around line 167-168: The insertion branch in FixedIDArray::(inserter usage)
calls val.value() for optional<T> which throws std::bad_optional_access and is
inconsistent with toEigenVector; add an explicit precondition check before
accessing the optional (e.g., assert/MT_CHECK(val.has_value()) with a clear
message referencing the ID/index and the FixedIDArray operation) or document the
requirement in the FixedIDArray API comment so callers know empty optionals are
not allowed; update the code path that uses inserter(val.value(), vector(index))
to first verify val.has_value() and emit a clear error if not.

In `@motorium/motorium_model/test/testFixedIDArray.cpp`:
- Around line 316-331: The test uses a non-deterministic matrix via
motorium::matrix3_t::Random() (variable transform) which makes failures
unreproducible; replace this with a fixed, deterministic 3x3 matrix (e.g.
explicit values) or seed the RNG before calling motorium::matrix3_t::Random() so
transform is repeatable, then leave the rest of the round-trip calls to
array.toEigenVector and array.fromEigenVector unchanged to verify values
deterministically.

@manumerous manumerous self-assigned this Feb 3, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@motorium/motorium_control/test/testExplicitJointPDController.cpp`:
- Around line 117-123: Move the duplicated lambda into the test fixture by
adding a static helper method JointState makeJointState(scalar_t q, scalar_t v,
scalar_t effort) to the ExplicitJointPDControllerTest class (the fixture used by
the PartialControl and ComputeAction tests), implement it to construct and
return a JointState with q, v, effort, and then delete the local lambda
definitions inside the PartialControl and ComputeAction test cases so they call
ExplicitJointPDControllerTest::makeJointState instead.
- Around line 56-67: The test TEST_F(ExplicitJointPDControllerTest,
InitializationValidConfig) currently constructs ExplicitJointPDController
directly to assert no exception; make the intent explicit by wrapping the
construction call inside EXPECT_NO_THROW(...) so the test clearly checks that
ExplicitJointPDController(controller_args) does not throw; update the test body
to call EXPECT_NO_THROW(ExplicitJointPDController
controller(*robot_description_, config)); keeping the same config and
identifiers (ExplicitJointPDController, TEST_F, InitializationValidConfig).

Comment on lines +56 to +67
TEST_F(ExplicitJointPDControllerTest, InitializationValidConfig) {
JointPDControllerConfig config;
config.joint_names = {"joint1"};
vector_t kp(1);
kp << 10.0;
vector_t kd(1);
kd << 1.0;
config.kp = kp;
config.kd = kd;

ExplicitJointPDController controller(*robot_description_, config);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider using EXPECT_NO_THROW to clarify test intent.

The test implicitly verifies that construction doesn't throw, but wrapping it in EXPECT_NO_THROW would make the intent explicit and improve test readability.

♻️ Suggested improvement
 TEST_F(ExplicitJointPDControllerTest, InitializationValidConfig) {
   JointPDControllerConfig config;
   config.joint_names = {"joint1"};
   vector_t kp(1);
   kp << 10.0;
   vector_t kd(1);
   kd << 1.0;
   config.kp = kp;
   config.kd = kd;

-  ExplicitJointPDController controller(*robot_description_, config);
+  EXPECT_NO_THROW(ExplicitJointPDController controller(*robot_description_, config));
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
TEST_F(ExplicitJointPDControllerTest, InitializationValidConfig) {
JointPDControllerConfig config;
config.joint_names = {"joint1"};
vector_t kp(1);
kp << 10.0;
vector_t kd(1);
kd << 1.0;
config.kp = kp;
config.kd = kd;
ExplicitJointPDController controller(*robot_description_, config);
}
TEST_F(ExplicitJointPDControllerTest, InitializationValidConfig) {
JointPDControllerConfig config;
config.joint_names = {"joint1"};
vector_t kp(1);
kp << 10.0;
vector_t kd(1);
kd << 1.0;
config.kp = kp;
config.kd = kd;
EXPECT_NO_THROW({
ExplicitJointPDController controller(*robot_description_, config);
});
}
🤖 Prompt for AI Agents
In `@motorium/motorium_control/test/testExplicitJointPDController.cpp` around
lines 56 - 67, The test TEST_F(ExplicitJointPDControllerTest,
InitializationValidConfig) currently constructs ExplicitJointPDController
directly to assert no exception; make the intent explicit by wrapping the
construction call inside EXPECT_NO_THROW(...) so the test clearly checks that
ExplicitJointPDController(controller_args) does not throw; update the test body
to call EXPECT_NO_THROW(ExplicitJointPDController
controller(*robot_description_, config)); keeping the same config and
identifiers (ExplicitJointPDController, TEST_F, InitializationValidConfig).

Comment on lines +117 to +123
auto makeJointState = [](scalar_t q, scalar_t v, scalar_t effort) {
JointState js;
js.q = q;
js.v = v;
js.effort = effort;
return js;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Extract makeJointState helper to the test fixture to reduce duplication.

The makeJointState lambda is defined identically in both PartialControl and ComputeAction tests. Moving it to the fixture class would reduce duplication and improve maintainability.

♻️ Suggested refactor

Add to the fixture class:

class ExplicitJointPDControllerTest : public ::testing::Test {
 protected:
  void SetUp() override {
    // ... existing setup ...
  }

  static JointState makeJointState(scalar_t q, scalar_t v, scalar_t effort) {
    JointState js;
    js.q = q;
    js.v = v;
    js.effort = effort;
    return js;
  }

  std::unique_ptr<RobotDescription> robot_description_;
};

Then remove the local lambdas from both test cases.

🤖 Prompt for AI Agents
In `@motorium/motorium_control/test/testExplicitJointPDController.cpp` around
lines 117 - 123, Move the duplicated lambda into the test fixture by adding a
static helper method JointState makeJointState(scalar_t q, scalar_t v, scalar_t
effort) to the ExplicitJointPDControllerTest class (the fixture used by the
PartialControl and ComputeAction tests), implement it to construct and return a
JointState with q, v, effort, and then delete the local lambda definitions
inside the PartialControl and ComputeAction test cases so they call
ExplicitJointPDControllerTest::makeJointState instead.

@manumerous manumerous merged commit 19dea10 into main Feb 3, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant