feat(mcp266): CANopen dual-channel MCP266 motor controller component - #758
Conversation
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Pull request overview
Adds a new espp/mcp266 component to control a Basicmicro MCP266 dual-channel brushed DC motor controller over CANopen, including docs, an ESP-IDF example, and host-buildable mapping tests.
Changes:
- Introduces
espp::Mcp266controller + constexpr mapping core (detail/mcp266_core.hpp). - Adds host unit tests for the mapping/PID-field remap and an ESP-IDF TWAI+CANopen example.
- Wires the component into docs (Sphinx/MyST + Doxygen) and CI (build + component upload).
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| doc/en/motor_control/mcp266_example.md | Includes the component example README into the docs. |
| doc/en/motor_control/mcp266.rst | Adds MCP266 component documentation and toctree entry. |
| doc/en/motor_control/index.rst | Adds MCP266 page to the motor control docs index. |
| doc/Doxyfile | Adds MCP266 headers and example to Doxygen inputs. |
| components/mcp266/test/mcp266_host_test.cpp | Adds host-buildable unit test for mapping core. |
| components/mcp266/include/mcp266.hpp | Implements the espp::Mcp266 dual-axis controller API. |
| components/mcp266/include/detail/mcp266_core.hpp | Adds constexpr mapping helpers and PID field-order remap. |
| components/mcp266/idf_component.yml | Declares the component for IDF Component Manager. |
| components/mcp266/example/sdkconfig.defaults | Sets example task stack defaults. |
| components/mcp266/example/main/mcp266_example.cpp | Adds ESP-IDF example using TWAI + CanopenClient + Mcp266. |
| components/mcp266/example/main/CMakeLists.txt | Registers example main component. |
| components/mcp266/example/README.md | Documents how to build/run the example. |
| components/mcp266/example/CMakeLists.txt | Adds example project CMake configuration. |
| components/mcp266/README.md | Adds component README with capabilities/limitations and device quirks. |
| components/mcp266/CMakeLists.txt | Registers the new component and include paths. |
| .github/workflows/upload_components.yml | Adds MCP266 to component upload workflow. |
| .github/workflows/build.yml | Adds MCP266 example to CI build matrix. |
Suppressed comments (1)
doc/en/motor_control/mcp266_example.md:3
- The MyST
{include}fence should start at column 1. If there is any leading indentation in the actual file (the diff view here suggests it may be indented), Sphinx/MyST can treat it as a nested code block and fail to process the directive. Ensure the opening/closing fences are not indented.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
f880699 to
6078a39
Compare
|
Addressed the review comments:
(Verified the example still compiles for esp32 and esp32p4, and the host mapping test passes.) |
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Pull request overview
Copilot reviewed 17 out of 17 changed files in this pull request and generated 6 comments.
0d4d55b to
e71cd43
Compare
|
Self-review — one fix applied, two notes:
Host mapping test passes; example builds for esp32 and esp32p4. |
e71cd43 to
e52dd10
Compare
e52dd10 to
9a10d7e
Compare
New component espp/mcp266: a dual-channel controller for a Basicmicro MCP266 (RoboClaw family) over CANopen, layered on CanopenClient like Ds402Drive (transport-agnostic). Both axes are driven symmetrically; M2's CiA 402 objects mirror M1's at +0x800 via Ds402Drive's object offset. Position control uses standard CiA 402 profile position mode and is the supported capability; configure_position_loop() handles the two device quirks (the [0,0] MinPos/MaxPos clamp that zeroes every target, and the setter's D,P,I vs readback's P,I,D field order). The manufacturer speed/ duty command mirror is implemented but documented as inert on the tested firmware. Telemetry (battery, temperature) reads via the mirrored command objects. The reverse-engineered object mapping (0x2000 + command mirror, per-axis objects, position-PID field remap) lives in a host-buildable detail core with a standalone unit test. Includes an example (Twai + CanopenClient + Mcp266 position sequence), README, rst docs + Doxyfile/toctree entries, and CI example-build + component-upload registrations. Depends on the Ds402Drive object-offset feature (#757). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0153z8MvyCu6YT47myGDn4rK
9a10d7e to
92afad0
Compare
|
✅Static analysis result - no issues found! ✅ |
|
Hardware validation —
This was exercised by building the MIB firmware against the component via |
Summary
A new component,
espp/mcp266: a dual-channel controller for a Basicmicro MCP266 (RoboClaw family) brushed-DC motor driver over CANopen. Layered onespp::CanopenClientlikeespp::Ds402Drive, so it's transport-agnostic — the app owns the CAN transport and feeds frames to the client.Both motor channels (
M1,M2) are driven symmetrically; M2's CiA 402 objects mirror M1's at+0x800viaDs402Drive's object offset.What it provides
configure_position_loop()handling two device quirks: the position PID'sMinPos/MaxPosclamp defaults to[0, 0](forces every target to zero), and the setter (cmds 61/62) uses field orderD, P, Iwhile the readback (63/64) usesP, I, D.drive_speed/drive_duty) — implemented but documented as inert on the MCP266 firmware tested (the drive advertises only cyclic-sync modes; velocity likely needs csv + SYNC/PDO, undocumented for this device).Device mapping
The MCP266 mirrors its packet-serial command set into the manufacturer OD region at index
0x2000 + command number. That reverse-engineered mapping (command objects, per-axis addresses, position-PID field remap) lives in a host-buildabledetail/mcp266_core.hppwith a standalone unit test (test/mcp266_host_test.cpp,ALL PASSED).Included
include/mcp266.hpp+detail/mcp266_core.hpp), README,idf_component.yml.Twai+CanopenClient+Mcp266position sequence) — builds for esp32 and esp32p4.doc/en/motor_control/mcp266.rst+ example md + toctree + Doxyfile entries.Dependency
Stacked on #757 (
Ds402Driveobject-offset) — the component usesDs402Drive::Config::object_offsetto address M2. Base will retarget tomainonce #757 merges.🤖 Generated with Claude Code