Lynxmotion SES V2 Hexapod Robot

Thanks @kurte, I’ve both, LA and scope.
I run 1.8.15 Arduino IDE and the beta9 Teensyduino.

LSS library… good point. Need to check what I run here, I’ve probably to much old stuff on my PC, even since beta testing.
Sigh… Looking in the library manager it seems like I’m using 1.3.1 version of the library. Trying to update it to 1.4.0 didn’t do any difference in result though.
Delete the arduino_xxxxxx folder containing the lss library. And moved your latest drivers from the github to the library folder.
PROBLEM FIXED!
The test code seem to run fine and the program doesn’t halt anymore, Yes!

Really sorry Kurt for not checking this myself… Feel like a real noob. LOL.
Good to be more on track finally! I hope to be able to join the fun stuff now.

Looking at the zero all positions I noticed I have set them to the legs spread out flat, like on the build tutorial.
If I recall @xan mentioned this and suggested using the old method (femur horizontal and tibia vertical), I’ve used that method on all my hexapods. It’s a bit cumbersome but kinda more logic to do.
What method did you all end with?

Thanks again Kurt!

1 Like

:smiley:

Sorry I should have also picked up on that earlier. I sort of did mine like we used to with other robots and level with the two servo horns and right angle to ground… But none are fully correct.

With some of the stuff that @cyberpalin and I are doing, we are playing with the setup code doing the offsets.
Current hard coded in code.

I also have a partially updated servo offset debug command, which I need to do some debugging of.

What maybe I should do, is if you run that command, it should save the new offsets to EEPROM. And if EEPROM looks correct at the next startup, it should then use that data instead of values built into code.

Or could get “fancy” and maybe store the offsets into a file, that could be stored on SDCard, or if you have an external flash stored to flash… But probably won’t do that … Yet

1 Like

I’m running that fine now thanks!

Ok, I I’ll do the same. Had to search for a while in my workshop for my old dusty stand I made for A-Pod…

1 Like

Sorry was out putting up a pool for the wife. But yes I’m using the latest sketch or pretty close to the latest :slight_smile: Keeps getting added to.:slight_smile:

Glad its working for you and thats all it was.

And by the way its Mike

1 Like

@cyberpalin and @dialfonzo - Confirmed setting MC=0, implies run servo Full speed ahead. And had same results as you did.

Good news is no failures, bad news does not do what we need it to do. And the main reason for NO failures as well we only asked once…

Again my run:

Checks Status wait loops 1 in us: 15468
Print Servo Positions Joint(Goal, timed, end)
C:1(0, 0, 0)	F:3(-900, 0, -901)	T:5(-600, 0, -599)
C:13(0, 0, 1)	F:15(-900, 0, -900)	T:17(-600, 0, -600)
C:1(0, 0, 0)	F:9(-900, 0, -901)	T:11(-600, 0, -600)
C:2(0, 0, 0)	F:4(-900, 0, -899)	T:6(-600, 0, -599)
C:14(0, 0, 2)	F:16(-900, 0, -901)	T:18(-600, 0, -600)
C:2(0, 0, 0)	F:10(-900, 0, -902)	T:12(-600, 0, -600)
Checks Status wait loops 1 in us: 15397
Print Servo Positions Joint(Goal, timed, end)
C:1(100, 0, 0)	F:3(-450, 0, -897)	T:5(-300, 0, -592)
C:13(100, 0, 2)	F:15(-450, 0, -895)	T:17(-300, 0, -594)
C:1(100, 0, 0)	F:9(-450, 0, -894)	T:11(-300, 0, -594)
C:2(100, 0, 0)	F:4(-450, 0, -893)	T:6(-300, 0, -592)
C:14(100, 0, 6)	F:16(-450, 0, -893)	T:18(-300, 0, -589)
C:2(100, 0, 1)	F:10(-450, 0, -890)	T:12(-300, 0, -588)
Checks Status wait loops 1 in us: 15434
Print Servo Positions Joint(Goal, timed, end)
C:1(200, 0, 83)	F:3(0, 0, -448)	T:5(0, 0, -297)
C:13(200, 0, 92)	F:15(0, 0, -444)	T:17(0, 0, -300)
C:1(200, 0, 84)	F:9(0, 0, -447)	T:11(0, 0, -304)
C:2(200, 0, 85)	F:4(0, 0, -444)	T:6(0, 0, -291)
C:14(200, 0, 93)	F:16(0, 0, -441)	T:18(0, 0, -290)
C:2(200, 0, 86)	F:10(0, 0, -438)	T:12(0, 0, -286)
Checks Status wait loops 1 in us: 15864
Print Servo Positions Joint(Goal, timed, end)
C:1(0, 0, 178)	F:3(450, 0, 2)	T:5(450, 0, 11)
C:13(0, 0, 189)	F:15(450, 0, 8)	T:17(450, 0, 0)
C:1(0, 0, 69)	F:9(450, 0, 224)	T:11(450, 0, 210)
C:2(0, 0, 64)	F:4(450, 0, 233)	T:6(450, 0, 211)
C:14(0, 0, 75)	F:16(450, 0, 211)	T:18(450, 0, 217)
C:2(0, 0, 57)	F:10(450, 0, 243)	T:12(450, 0, 225)
Checks Status wait loops 1 in us: 15675
Print Servo Positions Joint(Goal, timed, end)
C:1(-100, 0, 5)	F:3(0, 0, 443)	T:5(0, 0, 445)
C:13(-100, 0, -2)	F:15(0, 0, 442)	T:17(0, 0, 443)
C:1(-100, 0, 3)	F:9(0, 0, 443)	T:11(0, 0, 439)
C:2(-100, 0, 2)	F:4(0, 0, 443)	T:6(0, 0, 441)
C:14(-100, 0, 3)	F:16(0, 0, 435)	T:18(0, 0, 439)
C:2(-100, 0, 0)	F:10(0, 0, 442)	T:12(0, 0, 439)
Checks Status wait loops 1 in us: 15387
Print Servo Positions Joint(Goal, timed, end)
C:1(-200, 0, -94)	F:3(-450, 0, 20)	T:5(-300, 0, 15)
C:13(-200, 0, -100)	F:15(-450, 0, 20)	T:17(-300, 0, 13)
C:1(-200, 0, -96)	F:9(-450, 0, 14)	T:11(-300, 0, 4)
C:2(-200, 0, -97)	F:4(-450, 0, 14)	T:6(-300, 0, 13)
C:14(-200, 0, -99)	F:16(-450, 0, 6)	T:18(-300, 0, 12)
C:2(-200, 0, -99)	F:10(-450, 0, 14)	T:12(-300, 0, 12)
Checks Status wait loops 1 in us: 15485
Print Servo Positions Joint(Goal, timed, end)
C:1(0, 0, -191)	F:3(-900, 0, -435)	T:5(-600, 0, -282)
C:13(0, 0, -198)	F:15(-900, 0, -430)	T:17(-600, 0, -289)
C:1(0, 0, -189)	F:9(-900, 0, -436)	T:11(-600, 0, -291)
C:2(0, 0, -192)	F:4(-900, 0, -436)	T:6(-600, 0, -278)
C:14(0, 0, -192)	F:16(-900, 0, -431)	T:18(-600, 0, -287)
C:2(0, 0, -190)	F:10(-900, 0, -443)	T:12(-600, 0, -282)

So I ask the move to take 250ms and it takes 15… i.e. the time to output the MoveT commands and one loop to do the query.

So again wondering how to properly do a multi-step motion… Do we need to do our own computing of the desired speed for each servos and output that command as well for each move? That will probably be my next attempt :frowning:

@dialfonzo - since you made me go read the wiki I saw for the “T” modifier:

Note: If the calculated speed at which a servo must rotate for a timed move is greater than its maximum speed (which depends on voltage and load), then it will move at its maximum speed, and the time of the move may be longer than requested.

So how does the firmware calculate its required speed to move with say 150ms? Especially since it will also be dependent on accel/decel/stiffness wouldn’t it - don’t know if there is a query to that affect?

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