Skip to content
This repository was archived by the owner on May 29, 2026. It is now read-only.

Add dcmotor and remotized actuators#5

Merged
jvonmuralt merged 8 commits into
newton-physics:mainfrom
jvonmuralt:add-missing-lab-actuators
Mar 13, 2026
Merged

Add dcmotor and remotized actuators#5
jvonmuralt merged 8 commits into
newton-physics:mainfrom
jvonmuralt:add-missing-lab-actuators

Conversation

@jvonmuralt

@jvonmuralt jvonmuralt commented Mar 13, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Added DC Motor actuator with velocity-dependent torque saturation.
    • Added Remotized PD actuator with input delay and angle-dependent torque limits.
  • Documentation

    • Simplified PD/PID control-law expressions in docs.
    • Updated examples and parsing guidance to include new actuator types.
  • Tests

    • Added comprehensive tests for DC Motor and Remotized PD behaviors and parsing.

@coderabbitai

coderabbitai Bot commented Mar 13, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@jvonmuralt has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 15 minutes and 32 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dda7795b-c4d7-43cf-b5fc-ee8b905e430b

📥 Commits

Reviewing files that changed from the base of the PR and between 57f1264 and df99410.

📒 Files selected for processing (2)
  • newton_actuators/_src/usd_parser.py
  • newton_actuators/tests/test_actuators.py
📝 Walkthrough

Walkthrough

Adds two new public actuators (ActuatorDCMotor, ActuatorRemotizedPD), extends the PD controller kernel with optional velocity-dependent and angle-dependent torque limiting, updates PD control-law docs to remove multiplicative G factors, adjusts actuator/kernel call sites, enhances USD parsing for DC motor, and adds comprehensive tests and examples.

Changes

Cohort / File(s) Summary
Documentation
README.md
Documented ActuatorDCMotor and ActuatorRemotizedPD, removed multiplicative G factors from PD/PID control-law formulas, added DC motor examples and updated USD parsing examples.
Public exports
newton_actuators/__init__.py, newton_actuators/_src/actuators/__init__.py
Expose ActuatorDCMotor and ActuatorRemotizedPD in public API and __all__.
DC Motor actuator
newton_actuators/_src/actuators/dc_motor.py
New stateless ActuatorDCMotor class with argument resolution, constructor, and _run_controller that uses PD kernel and velocity-dependent τ_max/τ_min saturation (requires velocity_limit).
Remotized PD actuator
newton_actuators/_src/actuators/remotized_pd.py
New ActuatorRemotizedPD extending ActuatorDelayedPD with lookup-based, angle-dependent torque limits; validates lookup arrays, reuses delay buffers, and passes lookup tables to kernel.
PD / delayed PD callsites
newton_actuators/_src/actuators/pd.py, newton_actuators/_src/actuators/delayed_pd.py
Extended kernel invocation args to include saturation_effort, velocity_limit, lookup_angles, lookup_torques, and lookup_size (placeholders where not used).
Kernel logic
newton_actuators/_src/kernels.py
Added _interp_1d(); expanded pd_controller_kernel signature and implemented ordered clamping: velocity-based saturation → lookup-table interpolation → fallback max_force.
USD parsing
newton_actuators/_src/usd_parser.py
Added DCMotor API schema mapping, schema inference for saturationEffort/velocityLimit, DC motor precedence in actuator selection, and validation enforcing velocity_limit > 0.
Tests
newton_actuators/tests/test_actuators.py
Comprehensive unit tests for ActuatorDCMotor and ActuatorRemotizedPD (creation, arg resolution, velocity saturation behavior, delay buffering, lookup interpolation, USD parsing).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • Remove gear #4: Shares PD kernel signature and control-law modifications; likely touches the same kernel inputs and clamping behavior.
  • Add gear #2: Related changes to actuator constructors and PD pipeline that may conflict with new velocity/lookup saturation features.
  • Remove gear attribute #1: Prior removal of gear (G) multiplicative term from PD/PID control laws; directly related to the control-law documentation and kernel refactor here.

Poem

🐰 New motors hum beneath the moon,
Velocity curves tune every tune,
Angles whisper limits in lookup lines,
Delays keep rhythm, PD aligns,
Hopping giddily — code springs to bloom! 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding two new actuator types (DC motor and remotized PD) to the API.
Docstring Coverage ✅ Passed Docstring coverage is 93.33% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (2)
newton_actuators/_src/actuators/dc_motor.py (1)

57-66: Consider validating that velocity_limit is positive.

The resolve_arguments method requires velocity_limit but doesn't validate it's positive. A zero or negative value would cause division by zero in the kernel (line 97 of kernels.py) or produce incorrect torque-speed behavior.

♻️ Proposed validation
         if "velocity_limit" not in args:
             raise ValueError("ActuatorDCMotor requires 'velocity_limit' argument")
+        if args["velocity_limit"] <= 0:
+            raise ValueError("ActuatorDCMotor requires 'velocity_limit' > 0")
         return {
             "kp": args.get("kp", 0.0),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@newton_actuators/_src/actuators/dc_motor.py` around lines 57 - 66, The
resolve_arguments function currently requires "velocity_limit" but doesn't check
it's > 0; update resolve_arguments in the ActuatorDCMotor implementation to
validate that args["velocity_limit"] is a positive number (coerce to float if
needed) and raise a ValueError with a clear message if velocity_limit <= 0
(e.g., "ActuatorDCMotor requires positive 'velocity_limit'"). Keep the rest of
the returned dict the same and ensure you reference the "velocity_limit" key
when performing the check.
newton_actuators/_src/actuators/remotized_pd.py (1)

130-137: Consider validating that lookup_angles is sorted.

The _interp_1d function in kernels.py assumes xs is sorted (per docstring: "sorted sample arrays"). The class docstring mentions the lookup should be "sorted by angle" but there's no runtime validation. A mis-ordered array would produce incorrect interpolation results.

♻️ Optional validation
         if len(lookup_angles) != len(lookup_torques):
             raise ValueError(
                 f"lookup_angles length ({len(lookup_angles)}) must match lookup_torques length ({len(lookup_torques)})"
             )
+        # Validate angles are sorted (required for interpolation)
+        angles_np = lookup_angles.numpy()
+        if not np.all(np.diff(angles_np) >= 0):
+            raise ValueError("lookup_angles must be sorted in ascending order")

         self.lookup_angles = lookup_angles
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@newton_actuators/_src/actuators/remotized_pd.py` around lines 130 - 137, The
constructor currently checks lengths but doesn't verify that lookup_angles is
sorted, which _interp_1d (kernels.py) requires; in the RemotizedPD initializer
(where self.lookup_angles, self.lookup_torques, self.lookup_size are set) add a
runtime validation that lookup_angles is monotonically non-decreasing (e.g.,
each element >= previous); if the check fails raise a ValueError explaining
"lookup_angles must be sorted by angle" (include lengths/first offending indices
for clarity) so mis-ordered inputs fail fast rather than producing incorrect
interpolation results.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@newton_actuators/_src/kernels.py`:
- Around line 94-101: Add validation to ensure every entry in velocity_limit is
> 0 before any division occurs: in ActuatorDCMotor.resolve_arguments (and/or
prior to the block using saturation_effort in newton_actuators/_src/kernels.py)
check the velocity_limit array values and raise/throw a clear error if any value
is <= 0; this prevents division-by-zero in the saturation computation that uses
vel / vel_lim (variables referenced: velocity_limit, saturation_effort,
current_vel, max_force, max_torque) and keeps existing array-length checks
intact.
- Around line 35-38: The loop in the interpolation (for k in range(n - 1)) can
divide by zero when xs[k + 1] == xs[k] because of the denominator (xs[k + 1] -
xs[k]); add a guard inside that loop to detect a zero denominator and handle it
(either raise a clear ValueError stating lookup angles must be strictly
increasing, or return a sensible value such as ys[k] / ys[k + 1] or their
average) so the code never performs (x - xs[k]) / (xs[k + 1] - xs[k]) when the
difference is zero; update the interpolation branch that computes t = (x -
xs[k]) / (xs[k + 1] - xs[k]) accordingly.

In `@README.md`:
- Line 61: The README bullet currently uses the actuator class name
`ActuatorRemotizedPD` where the other items list the state type; update the text
to reference the state type `ActuatorRemotizedPD.State` so it matches the
pattern used for other entries and removes ambiguity—edit the bullet that reads
"`ActuatorRemotizedPD` - Inherits `ActuatorDelayedPD.State` (same delay
buffers)" to instead use "`ActuatorRemotizedPD.State` - Inherits
`ActuatorDelayedPD.State` (same delay buffers)".
- Around line 42-43: Update the ActuatorDCMotor documentation to describe that
torque is clamped to both a velocity-dependent lower and upper bound (τ_min(v)
and τ_max(v)) rather than only τ_max(v); replace the current single-bound
formula with a short description showing that τ_limit = clamp(τ, τ_min(v),
τ_max(v)) where τ_min(v) and τ_max(v) are computed from the motor torque-speed
curve (or explicitly state if the kernel uses symmetric sign handling), and
reference ActuatorDCMotor and the τ_max(v) expression so readers know to treat
both bounds when integrating.

---

Nitpick comments:
In `@newton_actuators/_src/actuators/dc_motor.py`:
- Around line 57-66: The resolve_arguments function currently requires
"velocity_limit" but doesn't check it's > 0; update resolve_arguments in the
ActuatorDCMotor implementation to validate that args["velocity_limit"] is a
positive number (coerce to float if needed) and raise a ValueError with a clear
message if velocity_limit <= 0 (e.g., "ActuatorDCMotor requires positive
'velocity_limit'"). Keep the rest of the returned dict the same and ensure you
reference the "velocity_limit" key when performing the check.

In `@newton_actuators/_src/actuators/remotized_pd.py`:
- Around line 130-137: The constructor currently checks lengths but doesn't
verify that lookup_angles is sorted, which _interp_1d (kernels.py) requires; in
the RemotizedPD initializer (where self.lookup_angles, self.lookup_torques,
self.lookup_size are set) add a runtime validation that lookup_angles is
monotonically non-decreasing (e.g., each element >= previous); if the check
fails raise a ValueError explaining "lookup_angles must be sorted by angle"
(include lengths/first offending indices for clarity) so mis-ordered inputs fail
fast rather than producing incorrect interpolation results.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7b88be0a-a809-477c-8adf-7dba196877dd

📥 Commits

Reviewing files that changed from the base of the PR and between 4eab871 and f2e10dc.

📒 Files selected for processing (9)
  • README.md
  • newton_actuators/__init__.py
  • newton_actuators/_src/actuators/__init__.py
  • newton_actuators/_src/actuators/dc_motor.py
  • newton_actuators/_src/actuators/delayed_pd.py
  • newton_actuators/_src/actuators/pd.py
  • newton_actuators/_src/actuators/remotized_pd.py
  • newton_actuators/_src/kernels.py
  • newton_actuators/tests/test_actuators.py

Comment thread newton_actuators/_src/kernels.py
Comment thread newton_actuators/_src/kernels.py
Comment thread README.md Outdated
Comment thread README.md Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@newton_actuators/_src/usd_parser.py`:
- Around line 98-99: The parser currently infers "DCMotorAPI" when either
"saturationEffort" or "velocityLimit" exists which can cause
ActuatorDCMotor.resolve_arguments to raise a ValueError due to a missing
velocity_limit; update the schema detection in usd_parser.py so you only append
"DCMotorAPI" to schemas when both "saturationEffort" and "velocityLimit" are
present, or alternatively add a defensive check in validate_kwargs (or
ActuatorDCMotor.resolve_arguments) that raises a clear, early error if
"DCMotorAPI" is in schemas but velocity_limit is missing; refer to the schemas
list, the string "DCMotorAPI", and
ActuatorDCMotor.resolve_arguments/validate_kwargs when making the change.

In `@newton_actuators/tests/test_actuators.py`:
- Around line 883-903: The test
test_parse_dc_motor_only_saturation_effort_infers_schema documents that
parse_actuator_prim currently infers ActuatorDCMotor when only saturationEffort
is present but ActuatorDCMotor.resolve_arguments requires velocity_limit and
will raise ValueError; update the test to reflect the intended parser behavior:
either assert that parse_actuator_prim raises/returns an error when
velocity_limit is missing, or change the expectation to validate that
resolve_arguments is not called and an appropriate error is surfaced,
referencing parse_actuator_prim and ActuatorDCMotor.resolve_arguments (or adjust
usd_parser.py decision logic) so the test and parser agree on whether
velocity_limit is mandatory.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 92516162-9112-4986-b35e-40cc84365cf9

📥 Commits

Reviewing files that changed from the base of the PR and between f2e10dc and 57f1264.

📒 Files selected for processing (4)
  • README.md
  • newton_actuators/_src/kernels.py
  • newton_actuators/_src/usd_parser.py
  • newton_actuators/tests/test_actuators.py

Comment thread newton_actuators/_src/usd_parser.py Outdated
Comment thread newton_actuators/tests/test_actuators.py Outdated
@jvonmuralt jvonmuralt merged commit b247a63 into newton-physics:main Mar 13, 2026
5 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Mar 20, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant