Lynxmotion SES V2 Hexapod Robot

I might be able to clear up a few things on the EM modes. I havent used the T modifier before so I can’t say how that works. I use the EM0 mode exclusively. I send a lot of position updates per second, around 30 times for each servo. I was using the Orokos KDL library to do the path planning for me and the EM1 (default) mode was working against me with choppy motion, not really bad, but noticeable. Around that time Seb suggested trying the EM0 mode given how I was (1) doing my own path generation and (2) sending many updates. EM0 disables the internal motion planner, and FPC just adds a simple IIR filter to the motion and thus leaving the external master to do the planning. With EM0 and an FPC of around 3 I get very smooth motion! If I lower my update rate though things degrade…motion will get choppier and it doesnt try as hard to get to the destination. The FPC is also a filter, so with a value of 3 you must send the target position at least 3 times in order to saturate the filter and get the internal target register to be the intended value. That doesnt mean send every value 3 times, that would be silly, just keep sending updates continuously from your planner and use the FPC to smooth as required. I actually modify stiffness and FPC depending on different motion states too but not necessary.

It sounds like your motion planner would be more efficient on the bus communication since it spits out a position and time. I never really thought about doing it this way but it makes sense. Only downside is you have no fine control over the shape of the path, Rectangular, Trapezoidal, etc. I can’t really help on this side but I thought my experience with EM0 might fill in what that mode is used for.

1 Like

Thanks @cmackenzie,

You are sort of confirming what I was starting to feel like we may have to head toward.

Initially I was hoping that the smarts in the servos could be used to reduce the load on the main processors, in the same way the original Phoenix code that controlled the 18 servos using an SSC-32. That allowed you to code programs like the Phoenix and run it on lower powered processors. Like the first version by @xan was written in basic and run on a Basic Atom Pro. Later I converted to Arduino and it ran on the Botboarduino which is repackaged UNO.

I believe we can still make it work in the same way that you are are. Which more or less means that you duplicate all of the SSC-32 logic into your program, and do your own interpolation, and careful timing on when to output the next data to each of the servos.

Two of the servo drivers for the Phoenix code already do this as I mentioned earlier today. For example my ServoEx library I did long ago for Arduino. Also the old bioloid library (or my updated BIoloidSerial) library which we used for the first generation dynamixels like the AX-12 servos.

So probably need to replicate that solution again. Which is a shame as was hoping that we could use the extended features of the LSS servos firmware.

But before we end up resorting to this, will try a few more things.

Again wish list for LSS servo firmware:
a) Have option (maybe default) that if you output commands to servos like you would to an SSC-32, that the servos should respond as close as physically possible to a servo connected to the SSC=32 Obviously having the group move supported would be a benefit to this.

b) if you have more advanced stuff like: the timed moves have code to accelerate up to some speed, travel at that speed, and then de-accelerate, then again you need some way to tell the servo what will be it’s next position/time/speed, such that it has enough information to know what it should do as it hits your current target position.

It would be interesting to hear what other things you might have tried with EM=1. Like if you told the servos to move to new positions in lets say 50ms, is there a reasonable point that you could tell them a new position and timing? Like if you tried to tell them at 45ms their new stuff, would it switch over smoother before the ramp down?

Again thanks!

Kurt

1 Like

Thanks for the addition clarification and especially how you are getting the servos to work with the humanoid project.

Yes in a simple test EM0 and a stiffness of -4 we got a good response with just using the move command. Unfortunately it seems to complete in 0.003 seconds but in a lot of cases this is going to be way to fast for a good leg movement. From what I have seen of the code so far, still sorting it out, moves are timed so you get a smooth gait with all 6 legs with required timings of 100 - 250 ms, don’t hold me to it - @xan or @zenta or @kurte would definitely be better at explaining it. Not sure of the frame rate - just trying to get the basics setup like I posted early on CFG settings.

As @kurte mentioned there are a few more things to try to getting timed moves working properly otherwise will have to revert to the more complicated way as @kurte mentioned.

Ideally, it would be advantageous to get moveT working properly - not 100% sure if this is an issue with the firmware issues that we already mentioned or a more basic issue with the servo since it seems most stuff is being done with EM0. NOTE: Still have to play with that sketch that dialfonzo mentioned but been busy on and off today and looks like tomorrow will be busy most of the day as well.

Not going to say I am signing off because I never know … :slight_smile:

1 Like

I like this video I did that shows the EM0. It’s simple code that reads position from one arm (servos are limp) and then sends the position commands to the other arm so it mirrors the motion. I have a few other videos that show this same code in EM1 mode, and with FPC=0 but this video is with EM0 and CPR3 (actually its FPC, but for some reason I keep typing CPR lol).

I’m still hopeful that your EM1 pursuits might prove fruitful though. I’d be interested if you are able to get the timed motion working. Maybe there is a way to overwrite the timed moves as you go so the servo doesnt stop or decell too much. I just dont know enough of EM1 to say.

I’ve also gotten the communication bug you’ve shown earlier and it hurts my update rate. I also just got one of those Saleae Logic analyzers myself…this thing is BLOWING MY MIND!! haha. I’ve heard they’ve locked the firmware devs in a room with Pizza so I’m hoping we have a new firmware to test soon.

3 Likes

Thanks for posting that @mackenzie. As you might have guessed this is in an interesting project even with my limited set up - definitely spending a lot more time than I expected playing with this. Yes that LA is definitely a good tool and very handy - sits on my self - haven’t put it pack in the case yet. Thanks to @kurte who convinced me to get the Salae one - did have a cheap one but the Salae is alot better!

Anyway @dialfonzo posted a sketch earlier on timed moves using EM0 So with my simple setup used my tibia servo to run a test on the timing only going in the range from -45 to +45 in 250ms. Well its close but didn’t spend too much time on the sketch yet - more of that tomorrow but here are the results:
Sequence Start

Frame 1 Timing: 251
Frame 2 Timing: 251

Note - this is the time to start the sequence and return from the sequence. There is nothing in the code thats giving me actual move times - have to add that tomorrow. Don’t think at fast speeds (delays of 250ms is going to turn out that it actually works). Just a feeling but been wrong before.

And if anyone is interested here is a very rough cut of the sketch that think works properly now:

> // LSS Setup & Variables
> #include <Wire.h>
> #include "SparkFun_Qwiic_Keypad_Arduino_Library.h" //Click here to get the library: http://librarymanager/All#SparkFun_keypad
> KEYPAD keypad1; //Create instance of this object
> 
> 
> #include <LSS.h>
> #define LSS_BAUD  (250000)
> 
> LSS LSS_1 = LSS(0); 
> 
> int Timing = 250;                        // Time in ms for the motion (T Parameter) 
> int delais_frame = 1000;                  // Time between each Frame
> int em0_rate = 25;                        // Rate at wich the positions are sent (20ms)
> 
> // Interractions
> int pushButton = 9;
> int buttonState;                          // the current reading from the input pin
> int lastButtonState = HIGH;               // the previous reading from the input pin
> unsigned long lastDebounceTime = 0;       // the last time the output pin was toggled
> unsigned long debounceDelay = 50;         // the debounce time; increase if the output flickers
> 
> void setup() {
> 
>   Serial.begin(115200);
>   
>   if (keypad1.begin() == false)   // Note, using begin() like this will use default I2C address, 0x4B. 
>                   // You can pass begin() a different address like so: keypad1.begin(Wire, 0x4A).
>   {
>     Serial.println("Keypad does not appear to be connected. Please check wiring. Freezing...");
>     while (1);
>   }
>   Serial.print("Initialized. Firmware Version: ");
>   Serial.println(keypad1.getVersion());
>   
> // Initialize the LSS bus
>   LSS::initBus(Serial1, LSS_BAUD);
>   Serial.println("Initial Reset: ");
>   LSS_1.reset();
>   delay(2000);
>   LSS_1.setServoID(6);
>   // LSS Settings
>   Serial.println("Set AngularStiffness: ");
>   LSS_1.setAngularStiffness(-4);
>   Serial.println("");
>   delay(250);
>   Serial.print("Set Holding Stiffness: ");
>   LSS_1.setAngularHoldingStiffness(4);
>   Serial.println("");
>   delay(250);
>   Serial.println("Set Motion Control: ");
>   LSS_1.setMotionControlEnabled(0);
>   delay(250);
>   LSS_1.setMaxSpeed(1800, LSS_SetSession);
> 
>   
>   Serial.println("Set FPC: ");
>   Serial1.println("#6FPC5\r");
>   delay(250);
>   
> }
> 
> void sequence(){
>   // Frame 1:
>   uint32_t time = millis();
>   Spoofing(-450,Timing);
>   Serial.printf("Frame 1 Timing: %d\n", millis()-time);
>   delay(delais_frame);
> 
>   // Frame 2:
>   time = millis();
>   Spoofing(450,Timing);
>   Serial.printf("Frame 2 Timing: %d\n", millis()-time);
>   delay(delais_frame);
>   }
> 
> void Spoofing(int32_t LSS_S_1,int32_t p2_timing){
>   int pos_num = p2_timing/em0_rate;
>   
>   int32_t   LSS_1_qd = query_LSS_1();
>   int32_t   LSS_1_delta = LSS_S_1 - LSS_1_qd;
>   float     LSS_1_min_pos = LSS_1_delta/pos_num;
>   
>   for (int32_t i = 0; i < pos_num; i++){
>     LSS_1.move((LSS_1_min_pos * i) + LSS_1_qd);
>     delay(em0_rate);
>   } 
>     LSS_1.move(LSS_S_1);
> }
> 
> int32_t query_LSS_1()
> {
>   int32_t posLSS = 0;
>   int32_t lastPosLSS = -1;
>   char readBuffer[100];
>   lastPosLSS = posLSS;
>   posLSS = LSS_1.getPosition();
>   return posLSS;
> }
> 
> void loop() {
>   keypad1.updateFIFO();  // necessary for keypad to pull button from stack to readable register
>   char button = keypad1.getButton();
>   
>       // only toggle the LED if the new button state is HIGH
>        if (button == '#') {
>         //Start the sequence
>         Serial.println("Sequence Start");
>         sequence(); 
>       }                  
> }

Please note - it uses a Sparkfun Qwic keypad that I already had hooked - you all can probably change it back to using a button as in the original sketch. Was to lazy to try it that way. Still want to do some more instrumentation on it to get more details but angles look kinda of correct just by eyeballing.

1 Like

I’m testing yours this morning, i kept the “button” part for my setup and replaced the rest.
Still unsure why but if i’m requesting a movement of 10s the last positions don’t seems to be calculated and/or output right.

Here you can see the last few position where it jump from “202” to “1800” and i have the feeling the behavior is always present, just less noticable if you demand a small movement. (attached the full motion)

int Timing = 10000;                        
int delais_frame = 1000;                  
int em0_rate = 5;
#0D196
#0D197
#0D198
#0D199
#0D200
#0D201
#0D202
#0D1800

position_capture.txt (18.0 KB)

something definitely strange going on. I was playing this morning as well before I have to do other things, I pretty much instrumented it a little bit more. If I tell it basically go through a 90deg range (-45 to +45) with the following:

  // Frame 1:
  Serial.printf("\nFRAME 1\n--------------\n");
  Spoofing(-450,Timing);
  delay(delais_frame*3);
  Serial.printf("\nFRAME 2\n--------------\n");
  // Frame 2:
  Spoofing(450,Timing);
  delay(delais_frame);

Where timing is set to 250. I am seeing this as an output with my updated sketch:

FRAME 1

goal: -450, time: 250, pos_num: 10
Current pos: (qd: 447), dPos(-897), tStep(-89)
Time(ms)/ Pos(deg)
233 / 447, 439, 408, 364, 315, 257, 193, 130, 56, -24, -28

FRAME 2

goal: 450, time: 250, pos_num: 10
Current pos: (qd: -447), dPos(897), tStep(89)
Time(ms)/ Pos(deg)
233 / -447, -441, -417, -376, -323, -263, -203, -133, -59, 17, 21

Its saying telling me that it issued the commands in 233ms but getposition isn’t returning what I am expecting it too. But it does swing through 90degs (at least eyeballing it) but it seems like it really taking 1second. Have to do more to figure it out but maybe @kurte can play with it while I am out. I want to add in his checkstatus2 function to see if we get errors.

Here is what I have so far:
LSS_M0_TSTEP.zip (1.6 KB)

Going to post it @kurte 's LSS_TEST_SKETCH reposoitory as well.

Just hooked up the logic analizer with the previous test sketch.
The period between possition commands seems about right at 24.64ms

image

Also from the begining of the first position sent to the begining of the last, there is about 10.113ms

1 Like

the 25ms seems about right - I was timing it out as 26ms. But that could be attributed to setup. The interesting thing in that second screen shot is that did you notice the “INVALID PACKET!! invalid position”. I think I would look at the response you get back from get position to see if its returning fast enough. At least thats what I was planning on doing when I get back.

Have to run, sorry, should be back in a few hours. Sure @kurte will jump - still early where he is.

Really appreciate you jumping in and trying to sort this out.

@madmax any progress with a ROS 2 setup?

Good morning @dialfonzo and @cyberpalin, it is getting sort of late here (5:30Am) :smiley:

As I have mentioned a few thousand times, Logic Analyzers come in handy! :smiley: Are you using the version 1 software

Will take a look later. Wondering about those messages mentioned in top line, but then not sure what it is? Is that a HLA for the servos? Which tries to parse the # messages?

Again will look more, but also more interested in trying some of the things I mentioned yesterday in our test sketch, about trying to get the sort of leg moves to be properly timed and then smooth transistions.

Do you still have a setup with you that you can try out some of this stuff as we go along? So far I am only one with a full setup that I know of that has tried some of this stuff.

Also wondering if you have done any fun projects with the new SES2? Any new fun Drones?

Now more coffee!

This line is a plugin that @cmackenzie created for the LSS bus but it’s not perfect.
Here is a closeup of the data regarding the initial query.

Here is a position sent:

If i’m zooming out it show “!!invalid packet” but that’s for the first part where i had “Sequence Start”

image

Screenshot of a 250ms movement of 45deg as you tested

1 Like

Useful tool, I’m learning but found it very intuitive and give a lot of infos.

I’m using Saleae Logic 2 software and the extension that @cmackenzie created, it’s available to install in the software and called “LSS Bus Protocol Analyzer” if you want to check it.

Are you talking directly to me about that ?
I will start now the assembly of an Hexapod i “should” have everything here and if not i will have a partial until i can get more parts from the office.

I’ve designed the mechDOG chassis and @dickel helped in getting some feedback and he did nice code for it…!!
No drone project lately, the market is quite saturated and people are looking for off the shelf drones.

1 Like

My HLA is confused with the \n being added to the packets. The LSS communication guidelines say the packet terminator is just \r. I actually wish it was \n because usb-serial hardware and I think some USART implementations will flush buffers/FIFOs when they see a \n. I’ll need to adjust my HLA to ignore \n

1 Like

Good morning (at least in my timezone) all:

The other difficulty with HLAs are they can only process one channel. So you can not easily for example have an HLA with TX and RX data and combine them so you can see when the responses arrive. There have been a few requests up on the Saleae beta forum for this feature… I have not yet tried one. I do have a low level one for Dynamixel Servos…

Yes, I think it would be great if someone at RobotShop could play along, so when come up with questions, often times it is easier to understand if you can see the stuff in action. Also hopefully fun to see things when new things are working.

Will have to look at the mechDOG. was @dickel able to make use of CM=1 or is that also bypassing it?

Sort of wondered about the drones as there sure are a lot of options out there.

Note with the test sketch I was able to run it and will play more as it helps demonstrate some things. What would be interesting extension to it, would be to have the ability to slow it down, so you can more easily monitor how the servo transitions from one setting to the next. Like it would be fun if someone hooked up something like a POT resistor to one of the analog pins, and you read the pot to choose how fast to rotate.

Another interesting experiment would be to somehow hook up a servo horn such that when it rotates it turns a pot or rotary encoder and then have the sketch do some timed captures of the values to see how it tracks.

But right now I am curious about trying a few experiments to see if some of the random thoughts on how maybe I might be able to make something like #1D100T250\r followed by another that should continue the move, without having the servo want to pause between… Not sure if any of these will work:

LIke: can I do a new #1D… at lets say delta time 225 with the new positions and time and bypass the slow down code? If anything like that works, how close can i get to the actual position/time?

Or in EM=0, T modifier does not work and what has been stated neither does S? First I will try S just to confirm. Then assuming it does not, may then try altering the Max speed and if that works at all then see how close we can get.

Now back to playing

The other difficulty with HLAs are they can only process one channel. So you can not easily for example have an HLA with TX and RX data and combine them so you can see when the responses arrive.

Yes, I asked for this on the Saleae forums and posted in their Idea board. Since it’s python there is nothing stopping us from writing our own back-end communication and I see one person used sockets to do this with mixed results. I was considering using ZeroMQ. The HLA seems to process incoming data in like a queue, so one HLA may fall behind in time a bit from it’s friend if it has less data to process. I believe this is the issue with backend comm between two HLAs not being in time sync and one HLA is missing the synced events that it’s friend generates sometime later. So the back-channel can’t just send data it must also be used to pause HLAs that are ahead of it’s friend.

I am not sure if anyone up here has mentioned it or not. But recently there was a sort of a screw up with ROS, where they forgot to renew their security keys, which than lapsed.

So they had to issue new keys. This caused issues like you were no longer able to do things like:

sudo apt-get update

And have the system fetch updates to any of the ROS packages or the like. I first saw this on the ROS Discourse messges I receive and later on the forum:


I found that I had this issue on my Ubuntu machine, but was able to resolve it using the instructions in one of the messages.

I am not sure if everyone has fully recovered from this or not. One of the last messages I saw on RobotSource, it sounded like for example Robotis is now going to have to update all of their prebuilt images (assume RPI) to all have the new updated keys.

Not sure how much this impacts anyone here. But thought I would mention it in case someone hits it.

1 Like

Hi

I have started with the URDF file for the hexapod. That is the trickiest one to get correct. I am now assembling the leg. Once I am done Colin would help me with xacro to get it complete. The individual parts had their origins way out and that was causing issues. I had to get the parts in Blender and get the origin in the centre of mass and rexport those parts.

Here are some screenshots of WIP of the URDF file…

EDIT: I am still catching up with the latest posts …there seems to be some important ones …

Hi,

I’m testing the “move all servos” function in the LSStest program. Commented out the parts that involve reading positions just for testing if it’s possible to get some smooth movement.
I keep getting some glitches on som servos now and then. In the video I run in a 10mS loop with 3 position increments. I’ve also tried a loop of 25mS with the same result. What do you think can cause these random glitches?

1 Like

Playing catch up now since I just got back and reading what I missed. I was looking at those YouTube videos last night with the mech dog - really cool what you all did.

@dialfonzo - is the code for that available - would be interesting to see how he handle servos configs.

Well if I had another setup I would give it a try but not going to invest right now in more servos just to test. I will you guys do that with all the servos :slight_smile:

@zenta - which test code are you using? There are 3 that at least I have been playing with in @kurte responsitory: LSS_TEST_SERVO, LSS_PHEONIX, and Zenta :). Going to make an assumption its the LSS_TEST_SERVO sketch? Can you share what you have. I can give it a try on my 1 leg.

Wondering if the glitch could be caused by a timing issue, or the related to the issue we were discussing with using timed move’s (moveT).

@madmax - @zenta question?
Have you all looked at the CFG files I set up for the LSS_PhoenixUSBJoystick or Zenta_LSS_Phoenix_PhantomX_float code. Not sure its 100%.