[C++] reset and get encoders? rotate degrees abs./rel.?

hi,

1st,
to reset the motor encoders I found e.g.,
BP.offset_motor_encoder(PORT_A, BP.get_motor_encoder(PORT_A));

why is this such a long command with offset and get encoder and all that?

wouldn’t it be possible to have a simple command just like
BP.reset_motor_encoder(PORT_A);

or what am I perhaps missing about the offset and/or a reset command?

.
.

2nd,
for polling the encoders there are 2 different functions,
1 to pass the port and an 1 int32_t value, returning int (not int32_t which has been passed)
and 1 to pass just the port and returning int32_t:


    int     get_motor_encoder(uint8_t port, int32_t &value);
    int32_t get_motor_encoder(uint8_t port);

why that?
I see that on the 32-bit ARM7 Pi2 int and int32_t have identical sizes
(not sure about the 64bit ARM53 Pi3 + new Pi2 though),

so why not always use either int or the stdint declaration int32_t ?

:?:

On the first offset encoder.

It obviously works by setting an offset for the encoder count not by resetting it to zero. This can be handy if your not wanting to reset it to zero but maybe another value for example if you where sync 2 motors together and one was out by a slight bit and needed a adjustment to be calibrated to line up with the other. If you want it to be reset to exactly zero the you will need the offset to be the amount that the current count is at.

If you want a command that just resets to exactly zero and can’t be set to anything else then it would be super simple to write a routine called BP.reset_motor_encoder(PORT_A); that you pass one argument too and it runs the one line of code BP.offset_motor_encoder(PORT_A, BP.get_motor_encoder(PORT_A)); then returns and save it in your library to use for all your future programs :slight_smile:

thanks, about resetting to values either than 0 I see your point - IIUC, reset to 0 would be the same as
BP.offset_motor_encoder(PORT_A, 0); or by
#define reset_enc(p) offset_motor_encoder(p, 0)

but I don’t get what sense it would make to reset to
BP.offset_motor_encoder(PORT_A, BP.get_motor_encoder(PORT_A));

??

if you set the offset to = 0 then you haven’t changed anything the offset is zero so the output will be the same.
If you set the offset of the count to be equal to the current count then the output = 0

I still don’t understand.
Resetting an encoder means to me:
drop the current value and set it to an arbitrary value, e.g. = 0
Why would I need something like an offset then?
It’s 0, so what?

(tbh, I even still don’t see at all what an “offset” is needed for, anyway… :-/ )

it doesn’t rest the encoder it just uses the current count and minus off whatever offset there is.
So the encoder counts ticks to know how much it has turned. BrickPi just keeps counting ticks and doesn’t have a reset but it does have an offset. So the offset = 0 when you start up brickpi and if you want to read the encoder the reading you get is the current count - offset so if offset = 0 then it will just you the current count. If you have rotated 360 and you want to reset the count if doesn’t reset then count but rather you set the offset to 360 then the reading you will get is current count - offset i.e 360-360 = 0

sorry, I don’t understand that behaviour.
At the start there is a reset to 0, IIUC, ok.
So for the future there will be all rotation counts relative to 0, that’s what was to be expected.

Now imagine, I have a joint with an endpoint-touch sensor.
I move the motor of the joint until it’s pressed, then slowly a little backwards until it’s released again.
Then I want to reset the encoder to 0 again, so that all future movements will be relative now to this “new 0”.
That would be reasonable if one did it this way, I think, but now:
what do I miss about BrickPi and what has to be processed for that task resetting to a “new 0” instead ?

It probably would be better if the brickpi had a set_encoder_count() function rather than offset_motor_encoder then you could just make it = 0 if you want to rest to zero or you could make it another number if you where just re-calibrating to sync motors.

yes, set_encoder_count() would be reasonable and logical, but that offset thing I don’t understand at all :frowning:

You could write that in a routine and save it in a library. In fact I think that I will do that as that will be more user friendly.

Might be a good update for Dexter to include in future BrickPi library

as written above:
what has to be processed for that task resetting to a “new 0” instead ?

I still do’nt understand that whole offset thing, tbh it looks kind of incomprehensible and weird to me. :frowning:

Ohh be careful with that because I was reading another thread on here where a guy had trouble with that. If you have set the motor to goto a set rotation then stop the brickpi will hold the motor at that count. If you then change the count output (offset) then the brickpi will spin the motor to make it goto the correct count output you have set it too.

huh…?
I don’t understand a single word about that - that sounds very weird.
If I set the encoders to 0 and order the motor to rotate 95, then I expect it to rotate to 95 degrees clock-wise, resulting to the new encoder postion 95;
and when I command to rotate -20 then I expect it to rotate 20 degrees back , stopping then at encoder position 75 -
where is the problem?

if you set the motor to rotate 90 degree the brickpi will rotate 90 degree then hold it at count 90. If an external force rotates the axle the brickpi will apply voltage to correct it back to count 90.

No if you startup your brickpi and tell motor to rotate 90 then it will rotate and hold at position 90, if you now reset the count to zero then the brickpi detects the motor that is suppose to be at position 90 is now at position 0 and it will correct it.

So if you want to reset you counter to zero you will need to reset the position of the motor to zero if you don’t want if to move

no, when in a “hold mode” then of course an enc reset may cause some troubles, if not used arbitrarily.
Of course usually the motor has to be set to coast, then one can reset the encoders.

perhaps it’s because a C tutorial about all that is missing.

I need the following commands:
1.) set enc to 0
2.) set enc to either value
3.) read the current enc value (relative to the 0 reset point)
4.) rotate relative degrees (e.g., +95 or -20 from the current position state)
5.) rotate to an absolute position regardless of the current value (e.g., 0 or -180°)

how can this be done?

Dexter could probably do with writing a good reset motor function that both resets the count to zero and resets the desired motor hold position to zero at the same time

I know it has caught up others too

ok, so the questions forwarded to @matt:

to reset the motor encoders I found e.g.,
BP.offset_motor_encoder(PORT_A, BP.get_motor_encoder(PORT_A));

why is this such a long command with offset and get encoder and all that?

wouldn’t it be possible to have a simple command just like
BP.reset_motor_encoder(PORT_A);

or what am I perhaps missing about the offset and/or a reset command?

then:

for polling the encoders there are 2 different functions,
1 to pass the port and an 1 int32_t value, returning int (not int32_t which has been passed)
and 1 to pass just the port and returning int32_t:

int     get_motor_encoder(uint8_t port, int32_t &value);
int32_t get_motor_encoder(uint8_t port);

why that?
I see that on the 32-bit ARM7 Pi2 int and int32_t have identical sizes
(not sure about the 64bit ARM53 Pi3 + new Pi2 though),

so why not always use either int or the stdint declaration int32_t ?

(added to TO post:)

I need the following commands:
1.) set enc to 0
2.) set enc to either value
3.) read the current enc value (relative to the most recent 0 reset point)
4.) rotate relative degrees (e.g., +95 or -20 from the current position state)
5.) rotate to an absolute position regardless of the current value (i.e., a fixed setpoint, e.g., to the absolute encoder value 0 or -180°) even when the motor is currently rotating (quickly changing relative enc values)

how can this be done?

edit:
just found out that for C++ it’s not quite as easy as for C to just wrap some #defines around the class methods, especially when an instance of a class method has to be passed additionally. So probably the public class methods will have to be enhanced by a few more methods, i.e.

reset (to 0)
set (to either value)
and perhaps even some more new ones

Ok you understand the coast being fine with rest encoder offset but the hold being a problem.

  1. To set enc to 0 then you have to set the offset to current position
  2. to set enc to a value then you need to set offset to current count + the value you want
  3. read current enc including the offset (relative to the rest 0) BP.get_motor_encoder(PORT_A)
  4. will have to look that one up I have used it plaenty of time but don’t have it on tip of my brain right now
  5. not sure about this last 1 and you would have to wait for Matt to answer

Just to clarify:

BP.offset_motor_encoder(PORT_A, BP.get_motor_encoder(PORT_A));

essentially sets the encoder value to 0 (subtract the current position from the current position). The advantage of this over just a simple “set to 0” or “reset” is that it allows user code to safely deal with rotating motors without losing encoder counts. If you were to read the current position and then tell the FW to set the encoder to 0, the motor could have rotated 15 degrees in the mean-time, and there’s no way for your program to know that. As it is, you can read the encoder and then use that value as an offset, so if the motor is rotating, no counts will be lost. For example, read encoder (360), motor rotates another 15 degrees (375 total), offset encoder by 360, encoder now reads 15 (no counts were lost between the read and the “reset”).

If you want a “reset_motor_encoder” function (where is doesn’t matter if you lose a few counts), you can wrap the above line of code as a simple function and use that to reset the encoders.

These two functions both get the encoder value:

int     get_motor_encoder(uint8_t port, int32_t &value);
int32_t get_motor_encoder(uint8_t port);

The first one returns the error value (should be 0) so that the program knows that it actually got a valid reading, and then it returns by reference the encoder value. This is ideal for situations where getting a valid encoder value is critical, and an error can be dealt with.
The second one returns the encoder value, but doesn’t have a way to return an error. This one is ideal for simple inline encoder reads.

Shane answered 1, 2, and 3.
Regarding 4, use get_motor_encoder to get the current position, add the offset you want (+95 or -20), and then tell the motor to run to that position using set_motor_position.
Regarding 5, use set_motor_position to set the absolute position motor target.