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.