I’ve had some good brainstorming with @cmackenzie about those two points (group moves and group queries) and we’ve had some interesting ideas to solve both. Those will take a bit longer to come out as we work on all the different parts of the project that also need our attention! But, no worries, we have possible solutions to make all of this even easier than it already is!
I just got the body panels on my doorstep! Thanks
@dialfonzo The rubber knobs/pads that came with the parts. I assume they are intended to be placed at the bottom of the body, or?
That leads to the next question. When performing calibration with all legs spread out flat its critical if we agree to do this with or without the rubber pads…
@kurte - Sorry for the confusion, i think we shipped the original Short-C brackets since we had no stock of the new ones.
That’s a good point for the rubber feet, if we install them it will mess with the calibration.
They are not needed, it was something i used on the Humanoid and dropped a few in the kit. Maybe we should not use them ?
@cbenson are we going to send the new ones ?
We’re happy to send a separate shipment with the new short-C brackets (and whatever items the group decides to use collectively. In order to save a bit on shipping (as two are located in EU), we’ll wait a bit for feedback.
I don’t need any. As long as the dimensions are the same it doesn’t matter. Then again, I solved it using the beta V2 parts.
@cbenson - Probably no hurry or the like on C - brackets - I don’t think the servos will mind if I use a zip tie
@dialfonzo @cmackenzie - The current commands look like they should work great.
Also will be interesting to see what you come up with for Group moves and query.
I need to get busy and finish soldering up board… And then get my feet wet with the code and if my guessing/assumptions are correct and the like.
Example if I do something like:
myLSS.moveT(1800, 500);
delay(50);
myLSS.moveT(1500, 500);
Will the second move start right at that point in time or will it wait until the first move completes in anther 450ms? My guess is immediate.
But I do like the idea of the ability to have a FIFO queue of moves (or even just double buffering). A couple reasons, including some of same reasons the processors do this for UARTS or SPI or…
But the first reason I sort of did this earlier with a few servo controllers, was I was running into inconsistent timings of commands going out over USB from RPI or the like which was causing not overly smooth motions, sometimes with jitters.
And again I need to read through more carefully things like trapezoidal motions and the like, where if you say do a move to 1800 with time T500, does the servo ramp up acceleration from the current location and de accelerate when it gets close to position 1800? But if it knows that it should then continue to 1500 would it change that behavior? Again I need to read more and experiment as you maybe already have this covered.
Again sorry for my ignorance here.
Be careful what you say here… They are smart servos, after all… they may eventually be connected to the Internet!!!
Immediate.
Yes, I see what you mean about queuing commands. Like the group move, this has been discussed but is not a feature (yet). Funny enough then that in most situations (with a PCs and the RPi) the delays using USB for real-time control (such as with smart servos) are due to the FIFOs in the USB meant to increase total throughput at high data rates without bogging down the CPU!
By the way, @cmackenzie searched more into this and you can (on the RPi4, at least) change the settings of the FIFO for some of the onboard UARTs and change them to a FIFO of 1 byte, therefore having (near) real-time control of the port (and thus no latency other than context switching/processing time, which are pretty low).
In EM=1, that is exactly what happens (idle -> move command received -> acceleration -> stable velocity -> decelerate -> hold).
If another move command is sent while one is already in progress the behaviour will change to accelerate in the proper direction. There are a few typical cases there, such as:
- Idle: typical case, see above.
- Already moving in the proper direction: acceleration phase will increase velocity if needed, otherwise it will drop to target velocity and decelerate as normal once close to the target position.
- Moving in opposite direction: will decelerate and switch direction, at which point it performs as if from moving from the idle case above.
- Holding: will use current motion (holding) to determine starting point of acceleration (prevents dropping if under load). If the new move is in the opposite direction of current “motion” (i.e: holding under load) it will perform as moving in the the opposite direction case above.
I hope that clears up some of those details for you @kurte!
I’m very glad for all the questions, as I’m sure the rest of the team is!
The only kind of reprehensible ignorance is the voluntary sort!
@dialfonzo @cmackenzie - The current commands look like they should work great.
Actually @scharette deserves most of the credit here…He is working on these commands in the servo code. I am just a sounding board.
But I do like the idea of the ability to have a FIFO queue of moves (or even just double buffering).
My Alternative LSS library already does this if you are interested. I would suggest the compliant-joint branch as its the most recent. I am using it on Linux now but it originally was made on Arduino and it should still work. Uses mostly static allocation for servo loops so works well on low memory devices. I did some performance tests between RPi and Arduino not that long ago. (FYI Performance was the same on RPI (w/ serial on IO header) and my 32bit Arduino.)
[edit]…oops…I guess I misunderstood. Yes, would be nice to send all servo positions in one broadcast command. Seb and I talked about this. The big bus time is reading back mA and position though just because it’s a query that requires a write and a wait/read…we cant think of a way to speed this up yet.
But the first reason I sort of did this earlier with a few servo controllers, was I was running into inconsistent timings of commands going out over USB from RPI or the like which was causing not overly smooth motions, sometimes with jitters.
Yup! Serial over USB devices suck for servo control. Expect >16ms delays, up to 64ms with FTDI in default mode. FTDI has a low-latency mode you can enable for about 8-10ms latency worst-case. I have all the jitter worked out and it’s not the servos so AMA.
@cmackenzie and @scharette - Would be interesting to see your alternate library.
Note: on my earlier RPI stuff for other servos, I had code in place, when I am doing outputs to an FTDI (ttyUSBx) device, I would use the tcdrain to tell the USB to output it now and wait until it completes before returning. However if it was not FTDI (ttyACMx) I did not call the tcDrain as it really slowed things down.
As for speeding up Query functions with Robotis servos, with a concept of a group Query. I have seen two different approaches.
a) Robotis - Protocol 2 version devices. You do special Instruction to do the query and you send it to the broadcast ID. The query includes start register and count and list of IDS. Each servo in turn listens for the previous servo in the list to respond and then it responds (or a timeout time if the ones before it don’t respond)… Works OK, I think so far I only used it to help cleanup some of the APIs in their libraries. Again only works with Protocol 2 devices and controllers
B) Xevel’s USB2AX device
With his setup, what he did was to do more or less the same query as the Robotis one does, to his controller. His controller than sent out individual packets to each of the servos in the list, and waited for their responses, which it packaged up and sent as one packet back to the host over USB. This saved a lot with the USB overhead. There may be other details I am skipping over here, like he may start the USB output if you filled up a complete USB buffer…
Now back to playing - So far I left all of the servos at their default baud rate. But I am assuming that we will up the baud rate up to the highest speed, like .5MB?
Yup, that would be the most optimal way to do it.
Since you will be updating (at least) 18 servos I recommend using 500 kpbs.
We do support some higher baud rate but I don’t recommend them. We’ve tested 36 servos on one bus (with long LSS Y-cables near each other, multiple boards, etc.) over many hours with complete saturation of the bus and had 0 packet loss. Cannot assure 0 packet loss at higher baud rates (at this time).
Hi all.
Did we agree on servo ids? The old SSC-32 Lynxmotion Phoenix numberings or the ones I posted earlier (same as used for PhantomX).
Since you will be updating (at least) 18 servos I recommend using 500 kpbs.
I’m going to state the obvious for experienced Arduino users, but “around” 500 but with respect to Arduino’s serial clock error rates. I usually look up in the respective Arduino device docs what serial bitrates have the least errors based on Arduino clock. Servos are more flexible, so it really depends on the Arduino.
would use the tcdrain to tell the USB to output it now
That’s interesting. I didnt know about tcdrain(), I tried flush() and some other ioctl calls, but not much difference over USB. I am not surprised about ACMx serial devices though, those are pretty low latency as-is.
FYI My notes on the serial are in my Evernote Serial Port Latency, Also Alternative LSS Library is on github (use compliant-joint branch).
Will update to the 500 kbps as mentioned. Note your Alternate LSS library either does not exist or is in a protected location.
tcdrain - took me awhile back then to find stuff out when I was learning RPI stuff.
I would look at places like:
http://man7.org/linux/man-pages/man3/termios.3.html
tcdrain() waits until all output written to the object referred to by
fd has been transmitted.tcflush() discards data written to the object referred to by fd but not transmitted, or data received but not read, depending on the value of queue_selector: TCIFLUSH flushes data received but not read. TCOFLUSH flushes data written but not transmitted. TCIOFLUSH flushes both data received but not read, and data written but not transmitted.
Today I did some more soldering of the board that I will start seeing if it will talk or not. I screwed up my Servo connectors (RX and TX pins reversed), but I am setup to have Arduino Header and I have TTL level shifters on the 4 pins associated with Servos and XBee, so will be interesting to see if it works… Tomorrow, tonight want to wash the board and let it dry.
Still need to mount it and then at first do everything with wall wart and USB power…
Note, I am showing it with a T4 in it with an adapter (FRDM4236) that has a lot of castellated pads soldered to bottom of T4 to make look like T3.6… Will be using it with a T4.1. But can not show pictures of T4.1 until it is released…
Pardon my messes…
Official public location: https://github.com/Lynxmotion/AlternativeLSS
I think the public version is not up-to-date with the compliant-joint branch, though. I’ll have a look at updating the mirror later (oh no! my mirroring scripts are at work! P )
For quick access for now, here’s a ZIP of it…
Lynxmotion_AlternativeLSS-feature-compliant-joint_(2020-05-06).zip (123.1 KB)
Thanks, looks like the one on github is about 3 months old. Will overwrite the one I have with yours.
Thanks again
@scharette - Thanks again - Looking at zip, 2 second look and it looks more like setup for RPI/ROS setup? With Cmake files and the like. Is there a proper subset of the zip/branch that should be used?
Currently trying the Scan program with just one leg connected to LSS board which is plugged into my T4 board and it is scanning and finding servos 8,10,12. It is interesting that it appears to always get the data for fhe first two servos, but the third one (12) will sometimes go through a few cycles of unresponsive.
Note: I have not updated the servos bad rates yet so using 115200.
Wondering is your PC LSS sketch the only “valid” way to set the baud rates. Or is it OK to have a sketch that gets a list of servos and then sets the baud rate (CID) and then do a reset on them? And then go back and reset the baud rate of the serial port?
Unsure of the details, better wait for @cmackenzie to get back to us!
You could just send something like #254CB500000\r followed by a #254RESET\r. Seems like a simple way to update the whole bus. Also, between the CB and RESET commands, all affected LSS will blink purple, so that should help confirm if the LSS received the command and recognized it.
Sorry, I posted location to the beta lib instead. The location should have been https://github.com/Lynxmotion/AlternativeLSS, and the release is in https://github.com/Lynxmotion/AlternativeLSS/releases. The zip @scharette posted is the newer code and a newer API…so not really the correct one. Also, the Arduino release is in the Arduino Library Manager as AlternativeLSS (info at https://www.arduinolibraries.info/libraries/alternative-lss)
Older code:
- Arduino only
- Command queuing
- Simpler API with LynxChannel (bus) and LynxServo and AsyncToken (ReadAsync and waitFor)
Newer code:
- Works on Arduino but in beta
- Better performance with command queuing, faster code and command scheduling (uses statistics to send next command before previous response received)
- Less simple (but still simple) API
I like the newer code because it is more packet based (closer to the LSS metal). I found I was always sending the same packets so it would be more efficient to statically allocate the list of packets and my loop is just send/wait-async/receive. There is no concept of “channel of servos” or even servo class. Static alloc means no memory fragmentation. If a packet shouldn’t be sent it can just be disabled for that round.
The newer code does use cmake to build an Arduino package (puts files in Arduino compatible layout and zips). For non-Arduino cmake compiles and provides high compatibility with OS or device. I am a big cmake fan and used it long before ROS. The new lib is not ROS related but to my surprise the ROS build tool built it automatically when I put it into a lib folder (I didnt expect it to, but I guess since I put it in a “lib” dir within my ROS project it assumed it should build it.) In my ROS humanoid I then wrap the LSS lib into a ROS node but that is not included here.)