Add MKS-SERVO42D/57D servo motor CAN protocoll#192
Add MKS-SERVO42D/57D servo motor CAN protocoll#192Johannes-Thiel wants to merge 20 commits intomainfrom
Conversation
…m/zauberzeug/lizard into add-MKS-SERVO42D/57D-motor-module
|
It looks good for me, but I also tried to do an AI review on this as well. It found some things. Review: PR #192 – Add MKS-SERVO42D/57D servo motor CAN protocolSummaryThis PR adds a new Main concerns are around the MAJOR1.
|
|
The |
falkoschindler
left a comment
There was a problem hiding this comment.
Just a quick review:
Markdown:
- The line length should be limited at roughly 120 characters. There's one with >250.
- There should be one sentence per line.
- Please document units (e.g. speed commands/properties).
- Why does
speedexpect an int and not float? Maybe it becomes clear when seeing the unit (steps?). Or is it a motor limitation?
MksServoMotor::handle_can_msg:
- The early exit is a bit weird because in principle it would still make sense to continue handling a message without parameters. But
data[0]would fail. So I think we should merge it into one condition, checking the count first:if (count == 6 && data[0] == 0x39) { ... }
Note that I didn't read the C code line by line. I'll trust your judgment, AI reviews and hardware testing. Let me know if this is ok or if I should read it more carefully.
…m/zauberzeug/lizard into add-MKS-SERVO42D/57D-motor-module
|
@falkoschindler The can protocol of the MKS motor will store the command byte in |
falkoschindler
left a comment
There was a problem hiding this comment.
@Johannes-Thiel There are still some issues, mostly with documentation, but apparently also one or two bugs in precision_zero:
Missing units for speed and acceleration parameters
The run(), rotate(), and stop() methods document value ranges but not units:
run(speed, direction, acc): speed is "0-4095", acc is "0-255" — no units specified.rotate(degrees, speed, acc): speed is "0-65535", acc is "0-255" — no units specified. Note: different speed scale thanrun().stop(acc): acceleration range and unit are not mentioned at all. The explanatory text below the method table only coversrun()androtate().
If these are raw protocol values with no direct physical mapping, that should be stated explicitly. If they do map to physical units (e.g. RPM, deg/s, deg/s^2), those should be documented.
grip(), release() and precision_zero() are domain-specific
grip() and release() are hardcoded shortcuts for the Feldfreund gripper (rotate(5, 3000, 255) and rotate(-40, 3000, 255) respectively). They don't belong in a general-purpose motor driver module and should be removed from the C++ implementation. Users can achieve the same behavior with Lizard routines:
let grip do
motor.rotate(5, 3000, 255)
end
let release do
motor.rotate(-40, 3000, 255)
end
precision_zero() has a similar problem. The core algorithm — rotate to a target angle, read the angle error via CAN, apply a correction, then set coordinate zero — is a generally useful homing pattern for MKS servos. However, the implementation hardcodes Feldfreund-specific values: target angle (240°), working current (1000 mA), start position (-110°), and various timing constants (2s, 1s, 1s). Either make it generic by accepting parameters (target angle, start position, speed, current, timeouts), or remove it entirely. Note that unlike grip()/release(), this cannot be moved to Lizard user code because it relies on internal CAN angle error reads (0x39) that aren't exposed to user-space.
set_holding_current valid range unclear
The docs say the argument is a "percentage" but don't specify valid values. The implementation does (pct / 10) - 1 clamped to 0-9, so effective valid inputs are 10, 20, ..., 100 (in steps of 10). Values in between are truncated. This should be documented.
precision_zero() failure path is incomplete
When precision_zero() fails (state PZ_FAILED), homing_state is set to PZ_FAILED but homing_active is never set back to false. On success (PZ_DONE), homing_active is correctly cleared. This means after a failure, homing_active stays true forever, which is a bug in mks_servo_motor.cpp:156-158.
Additionally, pz_state is set to PZ_FAILED but never reset to PZ_IDLE. Since step() calls step_precision_zero() whenever pz_state != PZ_IDLE, the state machine keeps running every cycle after failure, hitting the default no-op branch indefinitely.
|
I took care of most of these issue. Now we can test if the following Lizard routine works for homing the Feldfreund gripper. If it does, we can remove all the code related to int sleep_start_time
let sleep_1s do
sleep_start_time = core.millis
await core.millis > sleep_start_time + 1000
end
let precision_zero do
motor.working_current = 1000
motor.position(240)
await sleep_1s # wait for the motor to move
await sleep_1s
motor.read_position_error()
await sleep_1s # wait for the motor to respond
motor.position(240 - motor.error)
await sleep_1s # move to the stalled position
motor.zero()
await sleep_1s # wait for zero to be applied
motor.position(-110)
endNote that I renamed "rotate" to "position", "run" to "speed" (in analogy to other motors) and "angle error" to "position error". |
Motivation
For the gripper in the feldfreund we want to use the MKS-SERVO42D/57D servo motor. To communicate with this motor we want to use the can bus. This is a first implementation of the communication.
Implementation
Progress