-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New calibration so100 #709
base: main
Are you sure you want to change the base?
Conversation
Hello @pkooij, thanks for the PR! Is this still relevant? |
Looks very nice but I'm not yet sure if it works. I've tried it on this branch (which is my refactor PR + your changes) and I'm having calibration issues (like some motors go all the way around in the other direction past a certain point). There's also the (strong) probability that I did something wrong along the way, let's discuss this IRL with the robot ;) |
What this does
Use new simpler calibration method for so100
The raw motor position value always outputs 0...4096
In the old calibration in
run_arm_manual_calibration()
:Now we go further
zero_target_pos
is a list of 0's. Thus the homing offset that is being set is: 0 - zero_pos. zero_pos is theraw motor value from the motor in this position
.zero_pos
to calculate the direction of the motors by comparing it with the current readrotated_pos
and look if we positively turned all joint 90 degrees of 1024 ticks or negatively to know the drive_mode.rotated_target_pos
which is a list of 1024 (used below). Which represents this 90 degrees shift. ROTATED_POSITION_DEGREE is set to 90 at the top of the code.homing_offset
is being overwritten thus the previous sethoming_offset = zero_target_pos - zero_pos
wasn't needed for anything. (we only needed the zero_pos to calculate the drive mode (direction))homing_offset = rotated_target_pos - rotated_drived_pos
Here the homing offset is calculated taking the list of 1024 (rotated_target_pos) and subtracting the current position (rotated_drived_pos).rotated_drived_pos
is just the current positionrotated_pos
(read in the rotated position) with the right direction (0,1) applied.homing_offset
is finally saved to the yaml for later use. And is basically thus the position of the arm in thezero_pos
as told here: this position will correspond to every motor angle being 0. If you set all 0 as Goal Position, the arm will move in this position.We then load in the calibration from the yaml file and use the
homing_offset
for each joint in theread
andwrite
withapply_calibration()
andrevert_calibration()
respectively.In
apply_calibration()
called inread()
:Thus here we first add the
homing_offset
, which places the virtual zero (homed position/position for the user) of any raw_value from 0...4096 from the motor, at thezero_pos
set earlier.Example:
If the read position (in the rotated calibration position) was 1000, then this will happen:
rotated_pos = 1000
rotated_target_pos = 1024
This is from a list that is always 1024 (as discussed before)rotated_drived_pos = apply_drive_mode(rotated_pos, drive_mode)
# This will only *-1 if drive mode is 1.Thus
rotated_drived_pos = 1000
(is still 1000)homing_offset = rotated_target_pos - rotated_drived_pos = 1024 - 1000 = 24
Then in a
read()
when the motor is in the zero position specified earlier, robot "laying down".We will read the raw motor position of -24 (Because it is 90 degrees from the position we read when homing (1000) in the rotated position)
Thus in
apply_calibration()
we dovalues[i] += homing_offset
->-24 + 24 = 0
And now we have the homed position.If the read position (in the rotated calibration position) was 1000, then this will happen:
rotated_pos = 3500
rotated_target_pos = 1024
rotated_drived_pos = apply_drive_mode(rotated_pos, drive_mode)
Thus
rotated_drived_pos = 3500
homing_offset = rotated_target_pos - rotated_drived_pos = 1024 - 3500 = -2476
Then in a
read()
when the motor is in the zero position specified earlier, robot "laying down".We will read the raw motor position of 2476 (Because it is 90 degrees from the position we read when homing (3500) in the rotated position)
Thus in
apply_calibration()
we dovalues[i] += homing_offset
->-2476 + 2476 = 0
And now we have the homed position.This proves that the way you assemble the motor doesn't matter (in the old calibration and thus also not in the new calibration).
What however happens is that because we do a "shift" here:
values[i] = values[i] / (resolution // 2) * HALF_TURN_DEGREE
in theapply_calibration()
Where we re-center into a symmetric range (e.g., [-2048, 2047] if resolutions==4096) and the middle homing position will be virtual 0!This is not a problem for most joints because they were "homed" in the middle of their actual range. But for joints (2, 3): shoulder_lift and elbow_flex which where "homed" not in the middle but at one end of their (190) degree range, this creates a problem.
The problem is that the rest position is on the other side of their (190) degree range. And when we do
values[i] = values[i] / (resolution // 2) * HALF_TURN_DEGREE
We "reserve" each of our unique 0...4096 positions (homed) to either -2048...2047. This range directly maps to -180..180 later. But because we "homed" for these two joints at one end of the range when we then let them in their "rest" (normal rest position for the robot) they are at the other side of the range, which is either < -180 or <180. (At the turnoff point). And because we only communicate with the robot (often from this rest position). We don't know how it got there (FeeTechs don't track multi turn). This means internally in our code we can for those joints either start at -180 (or -160..-180) or at (160..180). This causes the problem.To fix this we can simply also take the actual center of these 2 joints as our homing position. Because then it physically won't reach or cross our "homed" threshold or jump between 180..-180.
Extra:
This does the invert of
apply_calibration()
when writing to calculate back to the raw motor position.In
revert_calibration()
called inwrite()
Conclusion:
It doesn't matter how the motors are assembled. It does matter where we home.
This PR: homes in the middle of all joints. Thus we can get rid of all
autocorrect_calibration()
and other "complex" code. The range now is always 180...-180. However, this breaks current calibration method, because the calibration positions are different (motor of shoulder_lift and elbow_flex are shifted 90 degrees from original homing (which wasn't in the center), the virtual zero of the robot is now when every motor is in the middle. This influences policies trained with the "old" calibration method and datasets that are already on the hub (could be converted).Further to discuss: when to merge this? (possibly with another breaking change)
TODO:
Note: the Feetech can't reliably do multi turn. Because when the motor goes beyond 180, even though we tell it to move again to 10. It will try to go there the other way around.
How it was tested