nasa-jpl / osr-rover-code

Code that runs on the Open Source Rover
Apache License 2.0
435 stars 148 forks source link

Calculation of ticks/enc revolution #73

Closed ericjunkins closed 4 years ago

ericjunkins commented 4 years ago

The roboclaw_params.yaml uses has params for encoder ticks per revolution, currently set to 2000. This 2000 is not quite the number. Will provide details in a write up shortly

ericjunkins commented 4 years ago

20200330_181452

ericjunkins commented 4 years ago

I did a quick sketch up of the math seen above, but i'll also explain a bit more here: The 2000 ticks is only an ideal number, and doesn't actually reflect what is happening on the real system. There would be two ways to go about getting the real ticks:

The proposal is to pull the numbers for each corner min/max, get their total span, and use that to calculate the ticks per revolutions per corner. It should be almost identical, however because of differences in resistors and the voltage dividers they will not quite be the same.

Achllle commented 4 years ago

I think you can get pretty close by using the overflow numbers (which I remember to be round 1800). It's a step that needs to happen anyways in the build docs, so we could add that people should take note of those numbers and replace the 2000 with those specific values.

Would this problem exist if we switch to digital absolute encoders? I was wondering why we didn't just get the digital ones.

ericjunkins commented 4 years ago

What overflow number are you referencing? Sorry I don't quite follow.

I think it would not be an issue with digital encoders if they place nice with the roboclaw. But because it only took in analog voltage for absolute encoders I didn't think there is an option that fit

Achllle commented 4 years ago

When you spin the absolute encoders, their value goes from 1 -> ~1800 before they jump back around. That would effectively indicate the range of ticks.

You're right regarding analog encoders, from the spec sheet: "RoboClaw is capable of reading absolute encoders that output an analog voltage"

ericjunkins commented 4 years ago

Ah i see what you mean. I think the calculated values would have put that at 1563 ticks based on the resistor values:

Vout = (R2/R1+R2) Vin Vout = 10k/(10k + 22k) 5 Vout = 3.125 * 5 = 1.563

ericjunkins commented 4 years ago

If you use the clipping range of the encoder then that would be a parameter that each individual motor would want as an input from the config file. During calibration you could measure each of these max values, which it could then use to calculate ticks per rev.

As a note, we did notice one of our 4 motors to have a slightly bigger range than the others, 3 of them were at 980 ticks/rev +/- a few, with one motor at about 1050 ticks/rev. These differences could be from resistor values.

@Achllle To go back to the 1800 tick value of clipping, you're using resistor values of R1 = 22k, R2=10k from the build docs? Even though they are 5% resistors, quick calculation I think puts the error bar of the voltage divider to be 1.563 +/- 0.110 V, so I would have expected that the max you would have is ~1673 for a clipping value.

ericjunkins commented 4 years ago

I think the biggest thing to consider here is: What is the best method of calculating the encoder ticks per revolution?

Method Description Pros Cons
Calibration range Using the assumed 90 deg rotation of the motor, and min/max values pulled from the calibration phase, and gear ratio, calculate encoder ticks/rev of motor Dynamically calculated, no extra steps required Relys on calibration of the 90 degrees window, which could be off potentially by a few degrees each direction
Calculated from encoder clipping window During calibration phase, record the clipping value of each encoder, this is the encoder ticks per revolution, needs gear ratio to give ticks/rev of motor Experimentally derived value will be correct for sure. Doesn't rely on calibration for corner commands relative to center (assuming you trust where 'center' is) Extra step, and not dynamically loaded in every time. All users have to calculate and update their individual numbers
Calculated from voltage divider Using the 0-5V window of the absolute encoder, and knowledge of the voltage divider, calculate the clipping window, then repeat steps in previous method Theoretically the same number for each, no extra steps Potentially not accurate enough. Voltage divider might vary enough to cause this to be innacurate

I think this details a few of the proposed ideas, if there are any others let me know. @Achllle @gfosmire @mikcox care to weigh in on method selection here.

gfosmire commented 4 years ago

I like the calibration range method best, though maybe with the slight modification of not adjusting the actual encoder min/max values to avoid hard stops at the edges, but rather handle that programmatically in the code. This way doesn't require the storing of an additional value in the config the way the encoder clipping value method does. Also, I think they effectively end up being the same, as the encoder clipping window method still relies on trusting where the "center" is, which is equivalent to trusting that the value spanned from encoder min to encoder max is 90 degrees, because you have to assume that "center" is half way between them. In the end I think the difference in method is minor, and so my vote is for what we have already.

mikcox commented 4 years ago

I'm with you all... I think the calibration range is the best option listed above since it doesn't require manual calibration input from the user.

Is there any value to re-calibrating every boot? Not sure if we've really ever seen enough slippage to warrant this... Just wanted to float the idea.

ericjunkins commented 4 years ago

I don't think we would want to ever do re-calibration on boot, that defeats the purpose of having absolute encoders in the first place. But if we wanted to write a calibration script that could be run upon command that would be a better implementation I think.

mikcox commented 4 years ago

I've heard of builders who had their absolute encoders rotate in the mounts while shipping or moving their rovers (since it's not glued or affixed, the encoder is just sort of press-fit into the 3D printed mount). That leads to the motor trying to move to a position outside the hard stop, even if it's trying to go to its "zero position" and just drive straight.

That issue led to hard stops being snapped and gearboxes being broken. It's rare and I agree it shouldn't ever happen, but we have seen it happen and it caused damage to somebody's rover.

I agree with you though: There are a couple ways we can get around this issue, and we definitely don't have to solve it by allowing a re-calibration on each boot.

Achllle commented 4 years ago

Some thoughts on this:

If the decision is to stick to the previous method of assuming a 90deg range, that's fine, although I'm personally not going to use that method.

ericjunkins commented 4 years ago

What are you thinking is the biggest source of error in the 90 degree assumption? The 3D printed hard stops will be relative to each other extremely close to being 90 degress exactly. There will be some small amount of error from a relative shift of the entire 3D printed piece, if you are finding the middle off of the min/max values you are subject to that issue as well.

In my mind unless you can calibrate the 'zero' position of the corner without using the min/max values, in the end everything about the corner relys on those values and everything will be relatively shifted if it is wrong, so if you trust it for the zero position you trust it for everything.

Achllle commented 4 years ago

As I mentioned in my previous comment, there are other ways of finding the middle, such as driving the rover with the corner motors in admittance mode, or adjusting based on sensor based localization (driving in a straight line and auto-adjusting until localization indicates you're actually going straight). Sometimes you might even want to set it yourself, if you notice that your rover is drifting. I did that on my own rover, since the middle calculated from the max and min values is indeed off.

Why use an approximation if you have the exact values though? Finding the overflow value is something that is done in the build docs already. The reason that this is important is because it excludes any debugging in that area, e.g. "I wonder if this inaccuracy is due to the assumption that the range is exactly 90 degrees. I used a low-cost 3D printer with the wrong material setting so it expanded more than it should have" (in this case the middle should actually be relatively unaffected). In the case of odometry calculation, you want to have the highest accuracy when you're turning the most, and with the 90 degree assumption, any error is spread linearly the farther you go from the middle.

To me, unless that overflow value changes over time, there is nothing to lose by using the more exact calculation. I do see the advantage of using the 90 deg assumption though, so don't let me stand in the way of going back to that :octocat:

ericjunkins commented 4 years ago

I think my biggest hesitation is trying to reduce the number of things that have to change on everyone's individual robot. As much editing of configs and parameters as we can get around would be nice, so something that is dynamically pulled is nice. Maybe there is something smart we can do to make sure you aren't ever running with someone else's config file, I want to make sure to avoid a scenario where someone pulls a branch for somenone else's robot and ends up damaging something on their robot because the configuration file was incorrect.

ericjunkins commented 4 years ago

I think what I'll do is try make some measurements and calculations as to how close the 90 degree assumption is. I'll calculate what my method estimates the encoder tick/rev_encoder and then measure it from the encoder itself to compare, I think having exact number will allow us to appropriately answer this question 👍

ericjunkins commented 4 years ago

Okay so I spent a while today looking into this, here are my findings:

Using the 90 degree assumption and calculating the ticks/rev of the encoder led to a 5.6% error compared to using the method to read encoder clipping values. This is assuming that the reading clipping values method produces Exactly the correct tick/rev value, which it is will likely be closer but not exact either. So i went down a rabbit hole to figure out exactly how accurate and what value that should be.

As described the datasheet: https://www.usdigital.com/products/...., the encoder will have a non-linear region of operation. We will never be operating in the non-linear region, reading the clipping value involves pulling data from the non-linear region, which without modification would assume it is linear everywhere. Below I go through calculating what the ticks/rev are in the linear region, and then applying that to the entire region to make use of the clipping value.

clipping_calc_1 clipping_calc_2 clipping_calc_3

In the end this then would make a slight modification to the clipping values input, it changes it about 8-10 total ticks, however this entire issue is to deal with precision of the corner system. I and am interested in feedback @Achllle , @mikcox when you guys get a moment to read through this.

In the end I think that the error that is <=5% for the 90 deg assumption method is higher than we would want, and should stick with the clipping method. The above information would be to decide if the clipping range needs modification.

Achllle commented 4 years ago

Phew, seems like you digged in pretty deep! I haven't properly looked at the spec sheet for the encoders, but since you mention linear region, is there any evidence that the slope for that region is the same for all encoders and we could use that? As using the clipping value in that case would probably be an unreliable approximation for that as well.

Slightly off-topic here, but should we consider using the or another Arduino (Mega?) and doing controls ourselves? We could get digital absolute encoders and as an added benefit, the drivers would be cheaper. This is something that I've done before.

ericjunkins commented 4 years ago

I believe that within the linear region it behaves exactly as described by the datasheet, which is a linear relationship between rotation degrees and output voltage. The reason I bring it up is that using the clipping voltage isn't quite the 360 degree rotation, because it has a non-linear region, based on the load impedance

image

It is also important to note the encoders output is starts at 0.015V, and has a max of 4.987V, so that tightens the range also. Again, everything I did above only made a diffrerence of about 10 ticks, but I do believe it all to be correct and be implemented. The final equation would be the (C_p -11)* 1.0076 to use.

ericjunkins commented 4 years ago

As far as the idea to switch to using something like an arduino mega and motor drivers, that certainly could work, and I'm sure there is a lot of cost savings to be had there. I think the trade off to explore is the trade off between cost, and complexity. The project's goal is still to be an educational robot, and so we just need to make sure to appropriately target something that is doable for high schoolers. Not saying that that particularly couldn't be, just that it needs to be an important consideration

Achllle commented 4 years ago

I see. So if I understand correctly that's the approach you would go with?

Regarding your earlier point of specific values that everyone needs to update and keep track of: I agree that's a downside, but I don't think it would be bad enough to damage someone's robot if they used the default values. And using the default values would mean that things would still work, it just wouldn't be as accurate. Since the roboclaws still hold the min and max encoder values, they provide a last line of defense against overturning.

Achllle commented 4 years ago

I'll look into a setup using motor drivers and arduino instead of the roboclaw motor controllers. Perhaps something to keep in mind for the next rev of the PCB.

ericjunkins commented 4 years ago

Yes. To summarize all of this, I believe we should keep the your method of using the clipping value for the encoder, with the slight modification detailed above, maybe once I get a verification from someone that the math looks sound. I can drop PR #76 and instead we can do that.

Can look into another rev of the PCB at some point as well. That's something I think we do want to attempt to bundle changes into, so would be good to collect any proposal of changes.

mikcox commented 4 years ago

If we're considering spending time doing a hardware redesign, I'd also like to refresh the idea of using servos for the corner steering instead of DC motors. There are some high torque servo options that I think would work pretty well, plus it helps with our calibration issues since in theory we'd have to do a lot less calibration work with a servo.

Not to mention, we might be able to greatly reduce cost by removing 2 roboclaws and all of the absolute encoders, which aren't cheap.

@ericjunkins @Achllle what do you all think?

Achllle commented 4 years ago

Yes, we actually investigated that option using Dynamixels instead. In the end we didn't pick that option because we weren't sure what the torque requirements would be for the corner motors (definitely hard to calculate accurately). Dynamixels are nice to use because everything is integrated, current protected, high quality and are probably the strongest small package smart servos around,, but they also come with a high price. All servo motors are going to be significantly lower torque than geared DC motors, but we could add in an extra gearbox. The cost for the current setup is 4$29.99 + 455 + 2*69.95 = $480. The strongest dynamixels not from the pro line, the XM series, are about $300 each excluding peripherals (~$70). The Dynamixel AX-12As are $45 each, but only have about 1.5Nm stall torque. Most hobby servos are similarly weak, and the other ones flat out lie about what the motors can do.

I recall seeing that others tried swapping out the corner motors with servos already. We should hear how that went. We could also just give it a try, or even test out what torque is required to move the corner motors in worst case scenarios. If it turns out we're way over what we need, might as well switch. We could easily hook them up to the existing arduino to do the controls.

EDIT: if it turns out that we do need that amount of torque, I would add that calibration upon startup might actually not be all that bad and we could just use quadrature encoders.

ericjunkins commented 4 years ago

Closing due to this being solved in a different issue. PR #86