Fundamentally, what is the best (or your preferred) way to control the motion of each joint of a “smart” servo used to create an articulated robot?
Approach 1: Rely on the smart servo’s onboard motion controller for timed moves
The motion controller under EM1 is made for a move without any additional / intermediate position commands (which therefore allows T and S to be calculated knowing start and end positions, and can therefore make use of modifiers. It takes into consideration any resistance experienced during the rotation and compensates in terms of output torque and speed. Update: “group move” is being implemented and should be released soon.
Approach 2: Use an external controller and send many intermediate position commands to the servo
The EM0 motion controller mode is made for receiving many small position commands where the servo holds at each position (and hence max torque can be provided), but does not include any modifiers: since it receives a new command each time where the positions are so close, not knowing the next position, timing cannot be anticipated. Update: it should be possible to communicate reliably with the servo at higher baud rates in the next firmware update.
Approach 3. Different from above (describe)
Is there another way which might present some advantages? If so, please describe.
I’m not sure if I fully understand the question but I can give some insights on how I did this in the past.
With a hexapod it is very important that the movements of all servos are synchronized. They all need to travel from their existing location to the next location and arrive at the same time. So the time is the same for all servos and speed will differ depending on the distance.
With the phoenix and SSC-32 a group command was sent including a duration (time). While the SSC was managing the movement of all (PWM)servos the controller was calculating the next angles. The next set of commands should be sent before the duration (time) elapsed to make sure the robot did not stop/shake between moves.
In the SSC-32 it was possible to already send the new commands, while the current movement was still being executed. The next commands became active on confirmation by sending an (13). It was always possible to overwrite the current movement at any time.
Is this functionality possible with the new servos where the controller is distributed and not centralized?
ps. I’m not sure what you meant with EM0 and EM1.
I hope this helps, but please ignore this message if it doesn’t make any sense
@xan Indeed, that’s the type of answer we’re looking for.
With a hexapod it is very important that the movements of all servos are synchronized. {…}
The latest firmware update should allow for this. Excited to release it! Our experts have been working hard and their efforts are appreciated.
While the SSC was managing the movement of all (PWM)servos the controller was calculating the next angles.
Question is, if the move uses a time modifier, the approach would be to have the main controller wait until those motions are executed before sending new commands? For example if the first command send to all servos (via group move command) specifies 1000ms, would the controller wait until 1000ms has elapsed (or the servo has confirmed it has reached the desired final angle) before sending a new command, with the exception of course where the motion changes (ex. moving forward and changing to moving sideways). Just looking to confirm. For example the hexapod sequencer built into the SSC-32 used three positions to lift a leg and put it down at a new location rather than many intermediate positions.
It is sort of hard to give a good answer to this as I don’t typically think about it as having multiple approaches, although with some other servos I do think about it as how much of the smarts of the servos to enable…
At the basic level: when I tell a servo to go to point X, I expect it to go to point X. If nothing else is specified or defined, I expect it to get there as fast as it can and/or if a max velocity is set, then try to go at that velocity to that point. But I should never have to tell it to go there N times before it gets there.
Now if I tell a servo that I want to go from current position to position X2 in time T, then I expect it to arrive there in time T… And likewise if I say Speed S to try to get there in time S.
That is I expect it by default to work like the SSC-32.
I totally agree with @xan that for good results something like the Group Move is essential, that is you want all 6 legs to arrive at their new positions at the same time…
As he/you mentioned the SSC-32 did this with the group move. With Dynamixels, there are a variety of ways, including the SYNC WRITE packets, likewise BULK WRITE packets. Or they have the concept of REG WRITE instructions, which say hold these new values in memory, but don’t use them until you receive an ACTION packet which could be broadcast…
Now the difficulty in answering how to use, is How do these timed things work. The problem with some of these smart setups is they are too smart and too ignorant at the same time. That is a major problem with many of these setups is that each timed move is thought of as a complete action in itself and not simply a portion of some larger motion… Sort of like in boating navigation they should be more like way points instead of end points.
That is with SSC-32 Suppose the servo is at 400 and if I were to do something like:
at T=0 send: #1P500T200
at T=200 send: #1P600T200
The servo Would logically move for .4 second at the same logical speed from 400 to 600. Assuming a 20ms servo cycle, it would internally at T=20=410 T=40:40…
With the current servo in EM=1 with each of these moves it is going to ramp up speed, coast and ramp down. So at the T=200 time frame it is going to ramp down and then ramp back up… So moves become jerky.
Multiple solutions possible for this:
a) ability to turn off the smarts for ramp up/ramp down… That is make it work like SSC-32
b) Ability to provide the servos with additional information. Like maybe either allow them to receive the next move command that they can peak at to know what is coming and adjust how to handle the way point. Again could be logically a double buffer, or could potentially be a queue of N deep.
c) Settings in the PID or equivalent which maybe logically neuters the ramp up and down … more or less a)
In these cases the servos should only arrive at their new position in the 1000ms… Obviously if all of the servos are already at that position to start… Then we still typically wait that one second before we move again
Note: with Software implementation of the interpolation code, if we are doing it using fixed point math, we sometimes take the Current and Target angles and shift them left N bits to make a larger delta between the angles, such that we can compute that for example if the servo only move 2 units in 10 time slices, it will do it on the 5th and 10th cycle…
I was thinking about this when reading @xan reply and then @kurte beat me to it… This is what I had observed as well because of the motion profile the movement is jerky and hence we need to use EM0. If we can get the feature to disable the motion profile but change the speed etc. based on the modifiers then that would be a very good feature for making smooth motion using intermediate position engine. It certainly would take of some load from the main controller.
I haven’t used SCS-32 so cant comment on the group move. I would like to use one of these… are they still available ? It certainly is a lot desirable to be able to move groups of servos as it reduced the numbers of commands that need to be sent.
Indeed. You are correct that the current firmware in EM0 and EM1 mode interprets the command as being the “last” and as such, goes through a deceleration phase as it nears the desired position. If a command follows that, it will therefore have an acceleration phase.
A “queue” of position and time commands (sort of as you described) would allow the servo to remove any deceleration and acceleration between moves, though adding commands would likely simply add to this queue rather than interrupt the current motion.
If we can get the feature to disable the motion profile but change the speed etc. based on the modifiers then that would be a very good feature for making smooth motion using intermediate position engine.
Without some kind of knowledge that there is a command coming (or a queue), in order to arrive at the desired angle without overshooting, it would need to decelerate somehow (PID).
No motion controller would be EM0 (which does not currently have time or speed modifiers) which has the servo rotate at full speed to the desired angle, so the idea would be to adapt EM0 to include time and speed modifiers?
One experiment might be, working with EM1 as it’s currently implemented, and increasing the AA and AD to max, and even sending the next command slightly before the previous one has ended. For example if a timed move in EM1 of 100ms has a deceleration phase of 5ms, increase the modifier time to 105, but send the next command at 100ms:
Ex: #3D500T105
//This assumes a (random) deceleration stage of 5ms
//… after 100ms a new command is sent (so the time is correct) #3D550T105
Granted it’s a hack.
I totally agree with @xan that for good results something like the Group Move is essential, that is you want all 6 legs to arrive at their new positions at the same time…
Eagerly awaiting the firmware update for you all to test.
So implementation wise does it make sense to see if the number of position update entries in the ques is <=1 then interpret as the last position update and use acceleration/ deacceleration in the motion profile. If number of entries for position update in the queue >1 then accelerate then just keep going on with out any deceleration and picking up the position updates from the queue and doing what it does until last queue entry. At this stage h stop the motion by deceleration. Obviously, easier said than done but I was just trying to see if there is a way to achieve this in a simple manner. Ignore if it is gibberish…
I guess it feels like the EM0/EM1 would possibly converge to just EM with the use of motion profile enable/ disable as a modifier along with T and S than a separate command… feels like… .
I guess it feels like the EM0/EM1 would possibly converge to just EM with the use of motion profile enable/ disable as a modifier along with T and S than a separate command… feels like
So something like:
#254EM0#3D500#5D250#3D1450T1000<cr>
This effectively sets the motion controller to 0 for all servos, though the Time modifier is not implemented like that at least yet…
Not sure how many people would use EM0 and EM1 in the same program, so maybe keep as a configuration?
Actually when it sees that there are still items in queue, it may still want to adjust some in the logical deceleration time frame, that is if the speed before the change is faster than the new speed then maybe it might choose to adjust the speed the last few previous cycles and likewise if it will be going faster …
Group move
Let’s picture a single leg of the hexapod. When walking, we want the tip of the leg to move in a straight horizontal line. To do this, all 3 servos need to travel to their next location (angle) the travel distance (in degrees) will differ for each of the servos. By making the duration of the move fixed (by using the time-variable) the only thing which should vary is speed. Servos with a small distance to travel, move slowly. Servos with a larger distance to travel move faster. All servos should end at their destination at the same time.
The group command should calculate the distance to travel by taking its current position and the new position. This will result in the distance. The distance together with the time should lead to a servo-specific speed. needed to arrive at the new position at the correct time.
Accelerating/Decelerating
The following image displays the movement of the tip of the leg. It uses 2 “swing” movements (6 → 1 and 1 → 2) and 4 movements on the floor.
When we accelerate/decelerate for each of the moves the hexapod will become very shaky. So this should be disabled for the hexapod.
Note: The multiple positions are needed for the gait engine and also allow us to change speed and/or direction in every step.
Updating
Sending the movement command (18 addresses + 18 positions + time command) will take some time. Therefore the phoenix code started sending the next command before the previous one was completed. To do this took the duration of sending the next command into consideration. If the previous command has T100 and the new string takes 3ms to send, the phoenix code will start sending the next command 97ms after the previous command.
The group command should be able to receive the next command before the old one is completed. On receiving a it should start moving to the next position directly. No need to first execute the previous command.
Terrain adaption
When working on the terrain adaption part we had a concept where we used the following diagram,
We moved the leg down (2 → 3). The tip of the leg was equipped with a switch. As soon as it was pressed we send a “STOP” command to stop all movement. Then we would like to query the positions of all servos to see where we ended up stopping. Based on that information we can calculate the next move.
If we are going with this approach we also need to be able to update (STOP) the movement during execution.
ps. I don’t know which approach @zenta used to get terrain adaption to work.
Shortly explained: very small steps. It simply stop moving the leg downward when it get ground contact. If a leg that are supposed to have ground contact loose contact it will try to move it more downwards. Only the legs in swing phase are controlled by the gait algorithm. The legs on ground are only moved by the balance calculations.
For the PhantomX that uses the AX-18 I made an experimental version using load/torque readings on the femur servos. It worked ok but not perfect. Servos with a relative low gear ratio are more suitable for this. A physical switch on the foot is a bit more reliable.
All servos reaching the goal at the same time for each step is mandatory for a hexapod.
Looking forward for the next upgrade. Been a bit busy with other things lately.
Xan looks like part of your earlier document on the walking gaits and the like: Lynxmotion Project Page
For those of you who have not read it before. Lots of great information. Likewise Zenta also has some interesting project pages up there as well which are also great reads
I have probably already said enough about the need for something like the group move.
And the desire for control of the timing of when the next move happens. Xan as you mentioned, with the SSC-32 we did this by timing when we sent out the final character for the move. Later we used a version of the SSC-32 firmware that had binary communications which we again we timed when we sent out the last portion of the packet which was the move time.
Likewise with other servos like AX-12 we could do this by always doing a complete SYNCWRITE of the whole message at the correct time. That worked as the message was a fixed length so would take the same time for the UART to transfer. As mentioned late last week it would be great if you could have the servo help out and be able to tell them their new goal positions before the previous move completes and again remove some of the timing issues from main code.
Terrain adaptaion
It will be fun to play with lots of different options. Lots of different things to maybe tryout like:
a) foot switches like we tried on the T-Hex years ago.
b) Like a) but with maybe something like FSR. I see many examples of this including biped feet with multiple FSRs
c) The idea of using something like TOF sensors like: Adafruit VL53L0X Time of Flight Distance Sensor - ~30 to 1000mm : ID 3317 : $14.95 : Adafruit Industries, Unique & fun DIY electronics and kits where you augment above with looking first. Keeps my Vacuum robot from falling down stairs.
d) Like c) But could use some form of camera or lidar to map the area to again maybe detect where things are… I know I walk better myself when I can see where I am going versus walking in the dark and hitting a pot hole.
e) Sensors to detect our balance. If our leg starts to go go down or not all the way down and body changes balance you then try to recover from that.
f) Probably a combination of all of the above.
Thanks for adding this, @kurte did this great update which somehow slipped my mind. Switching to binary communication reduced the number of bits that need to be communicated which highly increased speed.
I would like to add:
g) use the torque/power readings from the servos. In an ideal world, the weight of the robot should be divided equally between all legs. I wonder if something like this is feasible.
Thanks, I meant to add that as well! The LSS servos have some stuff toward this (I think) with the CH and CL modifiers. My guess they only work with EM=1. Not sure if there are other commands to set it outside of the move.
Very true. Also important if for example your setup is to control servos from a PC or SBC through USB to some controller, like LSS adapter boards (shields). With these the USB packets will hold up to 64 bytes of data per packet.
So for example with the old SSC-32 in binary mode for the 18 servos we would send: 3*18+2 bytes or 56 bytes which would fit into one USB packet.
With the current LSS stuff we would probably need to send like: #xxDnnnnTtttCR or about 10-12 characters per servo *18= about 216 Which comes out to 4 USB packets per move
Now if group moves are in place and we don’t have to re-specify the time for each one so maybe more like 9*18+5=167 so 3 packets. In addition you then have the added differences in then how long does it take for the Serial controller to output your data at the baud rate.
Side note: with Teensy 4.x unlike most other Arduinos including T3.x and most USB to serial adapters like the FTDI adapters mostly used, which transfer at USB High speed (12Mbps) with 64 bytes of data, the T4 runs a USB Full speed (480Mbps) and can have 512 byte packets.
Trying to compile the ideas / suggestions into defined tasks:
POSITION COMMAND
If a simple position command is received, it should have minimal acceleration and deceleration
Method to send additional position commands such that the servo does not stop / decelerator at the previous end position but instead maintains the speed
MODIFIERS
In relation to the position command with minimal accel / decel, ensure T and S modifiers work
Ensure T and S modifiers work in group commands
Ensure CH and CL work in this approach as well
GROUP MOVE
Able to receive and execute the next group move command before the previous one has ended
You may want to say that the servo would use the additional position information to decide if it will need to slow down or speed up or keep at the same speed.
Yes - the modifiers I would hope would work in all case usages.
Group moves, yes please The ability to chain group moves even better!
There are lots of other things mentioned, but are probably not in the scope you mentioned. Things like:
a) Group move - hopefully have smaller packets (don’t need to repeat the time stuff for all 18 servos). But still will be a lot larger messages than the binary version on SSC-32 (older update firmware). Not only faster because smaller number of bytes to transfer but in addition fixed size so you can use that to help synchronize… Not as important if one can queue up moves.
b) Still wish at times servos had option to send back some form of ACK when they receive commands. Note: the acks could carry back additional information. Example Dynamixels ACK returns hardware fault information. Like over or under voltage, overheat …
b1) Wish you have the ability to make sure the packet the servo sees is the packet you sent and vice versa. Like maybe some way to send a checksum or CRC with your packet. Sorry not fully thought through on how you would do it with your plain text message formats: Could maybe add modifier at end of message before CR: like:
#1D400T50$99\r
Where the 99 was some form of simple Ascii checksum. But hopefully catch if I tried to send go to 400 but the servos saw 800
c) Faster query response. The new beta one is faster on chained ones and appears to fix many/all of the data corruption. It did speed up the case where I chain up multiple queries to same servo, but it still looks like each query waits for some internal cycle to answer each one…
c1) Wish there was faster way to ask all of the servos for data. That is I may want to do something like output to the Serial port: “#1QD\r #2QD\r#3QD\r#4QD\r#5QD\r…#18QD\r” and hopefully get the current position of all 18 servos. But my impression is that there may not be any way for the servos to coordinate when it is safe for them to answer.
Quick summary wish: As I have probably said more than once probably a simple goal to ask for, but maybe not easy to totally implement, would be take an example sketch that does some reasonably complex moves, like the Phoenix, or an arm or… That was built using SSC-32 and RC servos.
Than show a version of the same code that runs with the LSS servos and describe the changes needed and why. And then show enhancements that the new smart servos give you beyond that, like sensing gripper closed or detect servo heating up…
As an intermediate step not sure how much it would help to run SSC-32 with LSS servos.
Again nice summary of some great new additions if implemented.
a) Group move: To be tested in the next firmware update.
b) ACK when they receive commands: To be seen perhaps?
b1) Checksum or CRC: This was discussed quite a bit before the servos were released given one of the goals was to try to make communicating with the servo as accessible and as easy as possible (no need to have a programming background to send simple, easy to understand serial commands). The OPTION of a CRC is interesting for more advanced users, but won’t be in this firmware release.
c) Faster query response: Looking forward to your feedback as soon as the new firmware release is available.
c1) Data: Changes will be made in the upcoming firmware release.
We certainly greatly appreciate the firmware dev working on the project and promise to unchain him from his desk and feed him pizza after this release
@cbenson - Thanks for the update. Any idea of when the next beta of the firmware update will be?
Great to hear that, will be interesting to see what all he has come up with.
There are always interesting conflicting goals in projects like this. In this case Readable versus Reliable versus communication speed and ease of programming. For me, one of the highest priorities would be reliability of the communications. Especially when you are dealing high speed communications in a electrically noisy environment, where the signals may be degraded as you daisy chain the servos.
As for Ease of programming, that is what a good library or sets of libraries can give you.
Again will be interesting to see what all is implemented here.
Apologies all for the delay - we know you’re eagerly waiting for the firmware update, but we thought it best to ensure that most bugs are resolved before sharing.