A quick follow-up - having spent more time in the odrive codebase recently, I think that parsing serial commands & parameters is probably best done the way itās done in ascii_protocol.cpp - using scanf. In this case, that would be something like:
I recently rewrote the UART code to try and improve the performance at any BAUD rate by using a quirk with the DMA interrupts to reduce the latency and jitter on serial commands. If youāre not having issues I wouldnāt worry about changing branches but the pull request can be found here:
I also tidied up and did a basic refactor of the parser so you can better see what letters have already been assigned routines. My next step was to reduce the overhead as the command letter is currently checked twice.
Thank you for this work @mike
Have you figured out how to call a function in ascii, like how you modified the .cpp file to allow you to call a function?
I am trying to reset the encoder count.In native USB i use thisā¦
axis*.encoder.set_linear_count(0)
Now i am trying to incorporate this into my modified ascii file so i can do it.
If you want to call a native function via the ascii protocol, you have to implement it as I implemented the āstatusā command above. There is no way to call a function RPC-style by simply specifying a text function label. All the information about human-readable function names is lost at compile time anyway.
hhhmmmm, let me give it a try quick.
Why is there āe %u %iā?
I get the e has to match the variable you are using, but about the %u and %i?
Also why if (numscan < 3) rather than if (numscan < 1)?
Sorry I am not a coder.
e %u %i
tells sscanf to look for the letter e, followed by a space, an unsigned integer, another space, and then a signed integer. the ascii command to set the linear encoder value of motor 1 would look like:
e 1 25
numscan < 3 is there because a successfully parsed ascii command (as specified above) will yield 3 āscannedā values; the prepended āeā, the axis/motor ID (the ā1ā) and the desired linear encoder value (ā25ā)
With respect, I believe my solution does work. Please be more specific about your process and the error(s) or erroneous behavior you are seeing.
There is nothing wrong with the code you posted from a āchecksumā standpoint; itās essentially what I posted but with all the parameterization removed, so your āeā command can only be used to set to encoder value of motor 0 to 0. The code I posted allows the āeā command to set the encoder value of either motor to whatever value is specified by the ascii command received by the odrive.
Mike,
First thank you for the explanations, this helps a lot.
When I used your code, and compiled it using TUP, the build files that it created did not have the ODriveFirmware.Hex
This tells me that there is an issue in the code?
When i removed the code you gave me, and re compiled, I got the .Hex file back.
Not sure my ignorance in coding is making any sense.
@mike
I found the problem lol. The last line has the wrong variable name
It says new_linear_count, but the actual defined variable is new_encoder_count.
So now it compiled and all, but if i want to set encoder 0 value to 0 i need to send:
āe 0 0\nā
This however keeps giving me invalid format, so i still got to find another bug.
Change numscan < 3 to numscan < 2
I have edited the original code so when others see the post in the future, they have the correct code in front of them.
@mike
I got more questions sorry
when I want to calibrate an axis in native USB, I type: axis0.requested_state = 3
Now I need to implement this in ascii with one character command. So:
else if (cmd[0] == 'q') { // encoder count, format: e axis# count
unsigned motor_number;
int numscan = sscanf(cmd, "e %u", &motor_number);
if (numscan < 1) {
respond(response_channel, use_checksum, "invalid command format");
} else if (motor_number >= AXIS_COUNT) {
respond(response_channel, use_checksum, "invalid motor %u", motor_number);
} else {
axes[motor_number]->requested_state = 3;
}
}
Well, it does not work. I am suspecting the last instruction is wrong. Also I am not sure that numscan < 1 is correct either. Any suggestions?
OR
If I want to change position for a trap trajectory by using: axis0.controller.input_pos = 10000
This also does not work. It does not give errors, it just does not move the motor. It is receiving the correct motor# and value. (yes i did check to see if the motor work using USB)
@mike
Is it possible for you to share the teensy code and and the python script (assuming your using pythong) your using to read and write data at that frequency with me please?
Thank you so much for this great resource. Iām currently working on a quadruped with a similar setup as yours (Teensy 4.1 + 6 ODrives). Would you be able to share your repo/code for the Teensy? That is, the Arduino code.