Lynxmotion SES V2 Hexapod Robot

Just noticed and back to playing for a little bit. So I guess the next bit is for everyone. What I have and checked so far is this:
#define DEFAULT_GAIT_SPEED 30 // Default gait speed - Will depend on what Servos you are using…
#define DEFAULT_SLOW_GAIT 50 // Had a couple different speeds…

//--------------------------------------------------------------------
//[MIN/MAX ANGLES] - Start off assume same as Phoenix...
//Zenta Changes Tibia min/max
#define cXXTibiaMin1    -60
#define cXXTibiaMax1     75
#define cXXFemurMin		-90
#define cXXFemurMax		 90
#define cXXCoxaMin		-75
#define cXXCoxaMax		 75


//[LEG DIMENSIONS] - from Lynxmotion drawing
//Universal dimensions for each leg in mm
#define cXXCoxaLength     50    // 50.8 to be exact
#define cXXFemurLength    80    // 80.32mm to be exact
#define cXXTibiaLength    116  //116.24 from drawing

//--------------------------------------------------------------------
//[BODY DIMENSIONS]
#define cRRCoxaAngle   -34   //Default Coxa setup angle, 34.280877 degs from center line? atan-1(60.6/88.9)
#define cRMCoxaAngle    0      //Default Coxa setup angle
#define cRFCoxaAngle    34      //Default Coxa setup angle
#define cLRCoxaAngle    -34   //Default Coxa setup angle
#define cLMCoxaAngle    0      //Default Coxa setup angle
#define cLFCoxaAngle    34      //Default Coxa setup angle

#define cRROffsetX      -61    //Distance X from center of the body to the Right Rear coxa
#define cRROffsetZ       89     //Distance Z from center of the body to the Right Rear coxa

#define cRMOffsetX      -81     //Distance X from center of the body to the Right Middle coxa
#define cRMOffsetZ      0       //Distance Z from center of the body to the Right Middle coxa

#define cRFOffsetX      -61     //Distance X from center of the body to the Right Front coxa
#define cRFOffsetZ      -89    //Distance Z from center of the body to the Right Front coxa

#define cLROffsetX       61      //Distance X from center of the body to the Left Rear coxa
#define cLROffsetZ       89     //Distance Z from center of the body to the Left Rear coxa

#define cLMOffsetX       81    //Distance X from center of the body to the Left Middle coxa
#define cLMOffsetZ       0       //Distance Z from center of the body to the Left Middle coxa

#define cLFOffsetX       61      //Distance X from center of the body to the Left Front coxa
#define cLFOffsetZ      -89    //Distance Z from center of the body to the Left Front coxa

min/max angles are based off of zero for all servos. Now the fun begins:

  1. Can not effective measure these values:

//MIN MAX control definitions:
#define MaxLegLiftHeight 120
#define MedHighLegLiftHeight 90
#define MedLegLiftHeight 60
#define MinLegLiftHeight 40
#define cFemurHornOffset1 -140 //- 14 deg
#define cTibiaHornOffset1 580 //+ 58 deg due to how the MKIII is mounted ref. Trossen assembly instruction
//#define UseFootSensors //bug bug not installed, must disable

with the way my setup is. I would assume the heights would be based on low/med/high stance positions?

  1. Ok since I set the gyre’s (cw/ccw) they would have to transpose some how with this:
    #define cRRFemurInv 0
    #define cRMFemurInv 0
    #define cRFFemurInv 0
    #define cLRFemurInv 1
    #define cLMFemurInv 1
    #define cLFFemurInv 1
    #define cRRTibiaInv 0
    #define cRMTibiaInv 0
    #define cRFTibiaInv 0
    #define cLRTibiaInv 1
    #define cLMTibiaInv 1
    #define cLFTibiaInv 1
    Which brings up the point what the program does with these - do you still need to set offsets/configs programmatically for the servos like we do in the sketch and then make the above values match so the right angles get sent to the servos?

  2. I will leave the following values to you all to configure and let me know.
    //--------------------------------------------------------------------
    //[START POSITIONS FEET]
    #ifdef MKI_AX18
    #define cHexInitXZ 147
    #define CHexInitXZCos60 104 // COS(45) = .707
    #define CHexInitXZSin60 104 // sin(45) = .707
    #define CHexInitY 15 //30
    #define cHexGroundPos 23 //bug bug no sensors used here yet
    #endif
    //I’ll probably make the init position more dynamic one time…

    // Lets try some multi leg positions depending on height settings.
    #define CNT_HEX_INITS 2 //Number of init setting
    #ifdef MXPhoenix
    #define MAX_BODY_Y 250
    #define MAX_BODY_Z 120
    #define MIN_BODY_Z -120
    #else
    #define MAX_BODY_Y 150
    #define MAX_BODY_Z 80
    #define MIN_BODY_Z -80
    #endif
    extern const byte g_abHexIntXZ[] PROGMEM;
    extern const byte g_abHexMaxBodyY[] PROGMEM;

    //[PARKED POSITIONS FEET] //Zenta BETA, not sure if I’ll do it this way afterall
    #ifdef MXPhoenix
    #define cHexParkXZ 180
    #define CHexParkXZCos60 103 // COS(55) = .574 *180 = 103
    #define CHexParkXZSin60 147 // sin(55) = .819 *180 =147
    #define CHexParkY 25 //30
    #else
    //Not defined yet
    #define cHexParkXZ 130
    #define CHexParkXZCos60 74 // COS(55) = .574 *180 = 103
    #define CHexParkXZSin60 106 // sin(55) = .819 *180 =147
    #define CHexParkY 25 //30
    #endif

@kurte - @zenta
Was going through the code and was wondering about the cRRTibiaInv or rather c…Inv in general. I can’t seem to find any place in the code where you all are actually setting the servo configurations programmatically.

So this raises the question should you all put something into the phoenix_float code that sets the configuration? Or should that just be part of the assembly process process to use LSS Config. Or you could write a configure sketch to do it once after assembly. @cbenson this one may be yours all decision on how to do this.

Basically the way we have it setup the c…Inv are the default ones.

Will definitely need something to get the servos configured properly.

EDIT: Since I don’t like leaving things undefined we could add this

#ifdef Lynxmotion
#define cRRCoxaInv 1 //CCW
#define cRMCoxaInv 1
#define cRFCoxaInv 1
#define cRRFemurInv 1
#define cRMFemurInv 1
#define cRFFemurInv 1
#define cRRTibiaInv 1
#define cRMTibiaInv 1
#define cRFTibiaInv 1
#endif
Or could just use a empty ifdef - don’t remember if c++ will complain about that or not?

Thanks for your hint Kurt!
Actually, loading the blink program solved it since I then was able to get contact with the T41 when powered from the board again.
The problem started as soon as I’ve uploaded the LSSTestServos program. There must be some sort of conflict in the program that affect the USB port when T41 is powered externally (through your board). Loading the blink program back, I get contact with the T41 again.
Any ideas?

actually setting the servo configurations programmatically

Very good question, and the rest of the team would be consulted here. From a user’s standpoint, simply assembling the servos at whatever arbitrary angle and having the robot figure out the travel, and subsequent zero position, then auto-calibrating would be best. Alternatively, having the customer assemble the robot in a specific way (ie as little angular offset as possible, then doing a small calibration - as was done with all SES V1 hexapods - saves development time. This needs to be thought through for other robots as well like the V2 humanoid, quadruped etc. No specific answer at this time, so for current testing, whatever method works best for you., and open to ideas.

As Xan indicated, this seemed like a good “zero” position, and servos on both sides all have their driving horn facing the same direction (“forward”).
just in case - did I understand the question correctly?

image

Yep that is a good “zero” position that is adjust by using the specified offset. But for assembly as discussed with @kurte:

  1. all servos should be zero’d
  2. assemble the femur bracket at 90degs to the zero position of the femur servo.
  3. assemble the tibia servo parallel with angled part of the bracket so the foot is inline with the bracket
  4. For the right side tibia the LED should be right when you assemble the servo to the bracket.
  5. For the left side tibia servo the LED should be pointing to the right.

More details can come later after the rest of the hexapod development. A bit early but good make a sticky note somewher.

@kurte
Just tried to compile the zenta_lss_phoenix_phantom_float sketch and failed to compile as you might have guessed. Looks like its still configured for the dynamixel ax12 servos, I think. Where do want to go from here? Or should I hold off.

Yep the Zenta program so far is still configured for his Robots… Other than I started on PS3/PS4 version.

My thinking is/was that I first did some code changing that moved some stuff around in classes. and then maybe @zenta might be able to try it on his own Robot. I did some running on a Phantom Phoenix using a T3.6 and the servos all did move…

Note the PS3/4 stuff needs to be cleaned up and simplified to at least show it walking and turning…

Then was/is going to make an LSS servo class along with a hex configuration set up for this hexapod…

In my own github project is my original first cut at Phoenix code and the hex file there was updated to hopefully be pretty close. Probably still needs lots of tweaks.

But off doing some work on the other building.

Enjoy will take a look since I’ve been working on the hex file - probably can make some headway on the LSS class but probably won’t start that until tomorrow.

Enjoy the rest of the day.

EDIT: Forgot - which repository?

Hope you are having some fun :smiley:

I believe where I was doing most of the stuff was back in my own github project where the LSS Test Servos program is.

If you look at the directory: LSS_Phoenix

It was setup with some initial guesses for hex file and an intial version of LSS Servo driver.
However this still setup with everything as header files, such that when in library those files could be compiled with app specific settings…

But in here is a file _Phoenix_Driver_lss.h which was the first cut… of some code that

I was playing in the SES_V2-Hexapod-Beta project and the directory Zenta_LSS_Phoenix_PhantomX_Float
and the is the one that I was playing with the new classes and the like. Figured when I get the PS3/PS4 working reasonably, I was going to then port it over to LSS Servos.

And that is the directory Zenta_LSS_Phoenix_float. I had started with the code in header files way, but then decided to play with Zentas code on servos that should be know to work with it… And then was going to this directory and ditch most of the initial stuff…

Probably clear as mud!

For most people probably but I think I have been working with you too long because I understand what you said - I think. Going to work first with the LSS_Phoenix code, seems less convoluted to start then maybe go play with the other code base unless you beat me to it. Besides the LSS_Phoenix code looks more like that instructable code I was talking about.

@cyberpalin and others.

I pushed up some changes to the LSS Test servo program, with changes to the ‘i’ command
In particular, again I still tell all of the legs to move to same place, but now I ask each servo of each leg if they are done yet checkStatus2… I also removed the delay call before this to get an idea of how long it would take till all the servo returned state of Idle or failed to read…

Would probably be better to remove some of the leg information from my quick and dirty structures to make the code better, but than again it is just a test program:

void checkStatus2()
{
  elapsedMicros emCheck = 0;
  uint32_t loop_count = 0;
  bool servo_moving;
  do {
    servo_moving = false;
    loop_count++;
    // Should use different table for this
    for (uint8_t leg = 0; leg < COUNT_LEGS; leg++) {
      if (legs[leg].coxa.move_status != LSS_StatusHolding) {
        myLSS.setServoID(legs[leg].coxa.id);
        legs[leg].coxa.move_status = myLSS.getStatus();
        if (legs[leg].coxa.move_status == LSS_StatusUnknown) {
          legs[leg].coxa.move_status = LSS_StatusHolding;
          Serial.printf("get status for Coxa servo:%u for leg:%u failed on loop: %u\n", legs[leg].coxa.id, leg, loop_count);
        }
        if (legs[leg].coxa.move_status != LSS_StatusHolding) servo_moving = true;
      }
      if (legs[leg].femur.move_status != LSS_StatusHolding) {
        myLSS.setServoID(legs[leg].femur.id);
        legs[leg].femur.move_status = myLSS.getStatus();
        if (legs[leg].femur.move_status == LSS_StatusUnknown) {
          legs[leg].femur.move_status = LSS_StatusHolding; 
          Serial.printf("get status for Femur servo:%u for leg:%u failed on loop: %u\n", legs[leg].femur.id, leg, loop_count);
        }
        if (legs[leg].femur.move_status != LSS_StatusHolding) servo_moving = true;
      }
      if (legs[leg].tibia.move_status != LSS_StatusHolding) {
        myLSS.setServoID(legs[leg].tibia.id);
        legs[leg].tibia.move_status = myLSS.getStatus();
        if (legs[leg].tibia.move_status == LSS_StatusUnknown) {
          legs[leg].tibia.move_status = LSS_StatusHolding;
          Serial.printf("get status for Tibia servo:%u for leg:%u failed on loop: %u\n", legs[leg].tibia.id, leg, loop_count);
        }
        if (legs[leg].tibia.move_status != LSS_StatusHolding) servo_moving = true;
      }
    }
  } while (servo_moving);
  Serial.printf("Checks Status wait loops %u in us: %u\n", loop_count, (uint32_t)emCheck);
}

Note Our servo_move_time is 250, so would think we would be near 250…
Removing the print of positions we see:

Cmd: i

get status for Coxa servo:13 for leg:1 failed on loop: 1
Checks Status wait loops 1 in us: 114621

get status for Femur servo:3 for leg:0 failed on loop: 9
get status for Femur servo:4 for leg:3 failed on loop: 10
Checks Status wait loops 92 in us: 660159

get status for Tibia servo:17 for leg:1 failed on loop: 49
Checks Status wait loops 50 in us: 531570


get status for Femur servo:15 for leg:1 failed on loop: 14
Checks Status wait loops 49 in us: 499799

get status for Tibia servo:11 for leg:2 failed on loop: 17
get status for Tibia servo:6 for leg:3 failed on loop: 27
get status for Tibia servo:12 for leg:5 failed on loop: 42
Checks Status wait loops 55 in us: 662790

Note: in many runs like this I will get a few failure for the query command as shown in this run.
Also we see that while I believe I asked the moves to be done in 250, and except for the first move which probably did not move, most of the measured times were significantly different.

And note: for example if on loop 14 servo 15 failed to report data, I don’t ask that servo again for this run which took 55 cycles of asking the servos. I probably should in real case.

So what does this mean? Should we use it all for timing? And of course other questions asked earlier about ramp up/down timings and how they should relate to next move…

Note: I also added the ‘j’ command which only goes to sort of the middle ground and then told it to go the same place many times to see if any screw ups that way. SO far not when I am calling it update like 25 times per second. Will try other variations.

Evening @kurte
Sorry was a bit busy with your bluetooth Phoenix code - more about that later.

Anyway it doesn’t surprise you are running into issues with checkStatus2 and servo failures and the large servo move times until hold position is reached.

Ran into the same problem (not the failures though since I was only testing 1 leg) but the long loops times for the servos. That’s why I put the delay(delay1) - 450ms - after all the servos move seemed to resolve any issues. I did try changing the move time for the servo but no luck without that 450ms delay. Suggest that you uncomment that line in checkStatus3 and rerun the test and see it that helps. Maybe someone else with the full up hex can run the test and see if they seeing the same thing. Sorry I can’t help with that one.

I did some mods to hex_cfg file using the LSS_PhoenixUSBJoystick program and did pair with the DS4 and my leg moved. Not the way I thought it should move but it did move. So tomorrow will doing some debugging and see if I can get it to work :slight_smile:

@kurte
Well I played some more and finally hit the right combination of keys and got the leg moving - something is still off in the hex I think but probably more because I don’t understand it fully.

Anyway I just posted what I have set up so far in the Hex_cfg. Think still need to play more. The link to my edits is: mjs513/LSS_Phoenix_BT (github.com)

cheers.

I’ve done some more debugging. Changed the baud on all servos to 250000 since 500000 often reported collisions (LSS Config app).
Still same fault though (did change the baud in the test code too.
The program halts in the setup section when running this function.

FindServos();

I would assume the T41 doesn’t respond on PC/USB connection when the program halts.
Here are also some pictures of the board you asked for @kurte

Good morning @cyberpalin and @zenta and all:

Sounds great - Will have to play soon. Also need to work more on how the buttons and axis are interpreted on the PS3 or PS4… Question will be to start from a simpler version like the PS2 or Arbotix Commander, which for example just had 4 axis and 8 buttons and just start with some real basics stuff, or to try from code setup from @zenta granddaddy of remotes and try to map most everything…

Simple things like: body height. With PS2 like we may have had Triangle button, as stand up or sit down. And have the hat up and down go up or down some N units… With our XBee remotes we might probably just used one of the sliders on the remote. So for example on some with commander on some versions I did an intermediate way, of if you are holding down one of the buttons and then move one of the joysticks up or down, it will move the hexapod up or down by some percentage of the joysticks value…

Ditto for walking speed and maybe leg lift height…

What I had was sort of combination. I started from Zenta’s version and was stripping down but then was thinking maybe need to start from simplest one first. Note: more “fancy” version also sends textual messages back to the remote, like the name of the current walking gate or the operational mode…
In my first pass on my first board, I have an optional socket for Adafruit displays and had this information display on an ST7789 display. With this board did not have room. So my thoughts are with the QWIIC connectors (which were wrong pattern for ones installed), that I would optionally plug in a display on one of them and if detected could display some of this information. Would help to know when you hit different buttons and it shows you are now in walking mode or single leg mode …

In my next pass of this, I will try to detect which legs are installed and only operate on those legs :smiley:

I remember your mentioning this , but commented out the delay as hopefully see what is going on. I am probably now going to instrument this code with some digitalWriteFast (or toggle) calls to get an idea of things like timing. Like probably a toggle at every query that fails, such that I can quickly see in a Logic Analyzer output where each failure is and if it was the servo did not respond or if it garbled the message or response…

Plus if you ask for a move to be done in 250ms and most of these timings are showing a lot longer timing, what does that mean? Could be maybe we screwed up and set a max servo speed, and our timing request was superseded by the max servo speed. Will check that out.

But if not that, then comes up the next questions, like I asked the servos to arrive at some location at time X, maybe that is not working. So may extend code that function, to know when the servos should arrive. and maybe at about that time, query all of the servos for their current position and state and see if that shows anything interesting.

Or maybe either the values of the query command are not working well or not appropriate to be interpreted in this way. That maybe it only returns LSS_StatusHolding after it arrives at the specific location, and maybe took a second to catch it’s breath and had it’s first few sips of coffee :smiley: or the electronic equivalent.

@zenta - I will take a closer look at your posting and try to help figure out what is going on. But I think I need a few more sips of coffee myself :smiley:

Just as a note decided to start with this code base since it was easier for me to go through and understand better the bits and pieces and just to test bluetooth. Basically it does work but still needs lost of testing to get it right.

Well I think to start I would stick with the DS4 or the PS3 especially since I don’t have a PS2. I did hook up a display to it this morning and was neat so I could see what buttons I was pushing easily.

Was having bit of a problem with the DS4 connecting but maybe that was my fault. Have to play with that a bit mroe.

To be honest to make sure everything was working what I like to see is something like we did with test sketch where addition options were available say using the triangle or another button to tell Spidey to go through the stance position we set up - low/med/high. From testing this morning found this would have come in handy to sort through whether I had the leg INV’s set up correctly and the servo’s were reacting as expected to start. Leg does move in a gait but its strange. Think if you configured the gyre and offsets in the LSS_Config all INV for the right side should be 0? See what I mean.

Along the same lines am a bit confused on setting some of the values like cXXTibiaMin1 and cRRCoxaAngle1: Are these in degrees or are should they be set in 1/10ths of a degree.

Also is this version using the same body axes as the full up code? Also what are the settings this should be at?

//[START POSITIONS FEET]
#define cHexInitXZ 147
#define CHexInitXZCos60 104 // COS(45) = .707
#define CHexInitXZSin60 104 // sin(45) = .707
#define CHexInitY 25 //30

// Lets try some multi leg positions depending on height settings.
#define CNT_HEX_INITS 2
#define MAX_BODY_Y 150
#ifdef DEFINE_HEX_GLOBALS
const byte g_abHexIntXZ[] PROGMEM = {cHexInitXZ, 144};
const byte g_abHexMaxBodyY[] PROGMEM = { 20, MAX_BODY_Y};
#else
extern const byte g_abHexIntXZ[] PROGMEM;
extern const byte g_abHexMaxBodyY[] PROGMEM;
#endif

Yes to everything you said. Just as a note I did try and change the speed up and down (1000, 500, 300) and didn’t seem to make much difference. Same thing with servo move timing. You probably figured that out since I made the speed and timings a define :). Still a lot to figure out with these servos and the best settings.

I agree need more coffee as well. Have a couple of other things to do as well.

Morning afternoon @cyberpalin and all:

Got to run, but I thought I would mention that I pushed up some more changes to the moving legs up and down… Including hopefully detecting which leg(s) you have.

I also put in digitalToggleFast on pin 2 if there is an error receiving data from servo.
And digitalWriteFast on pin 3 around each loop asking all of the servos…

As you can see in the run I just did every cycle through this except one had at least one failure to respond properly:

Also interesting the first pass through asking all of the servos if they are done is the longest, which somewhere around 15ms and then drops quickly to like 8 or 9ms finally down to a few servos…

And in the error condition detected…
The logic analyzer is showing that the data coming back from the servo is showing a bad format again always at the same location in the servo responses.

But now got to run

Just pulled it down but doing some maintenance now but did have a question of the DS4 commands, you have this as a note:

// R1 - options (Change walk gait, Change Leg in Single Leg, Change GP sequence) (Select on PS2)
// R2 - Toggle walk method… Run Sequence in GP mode
// R3 - Walk method (Not done yet) - (PS2 R3)
// L4 - Ballance mode on and off
// L5 - Stand/Sit (Triangle on PS2)
// L6+Right Joy UP/DOWN - Body up/down - (PS2 Dpad Up/Down)
// L6+Right Joy Left/Right - Speed higher/lower - (PS2 DPad left/right)
// Right Top(S7) - Cycle through options of Normal walk/Double Height/Double Travel) - (PS2 R1, R2)
// Left Top(S8) - Cycle through modes (Walk, Translate, Rotate, Single Leg) (PS2: Circle, X, L1, L2)

But doesn’t make sense. For instance to walk gait you show to use option buttons but on the DS4 I get that when I use the Triangle ?

Ok got to run myself…

Sorry, things sort of described in a complete mess currently :blush:

These comments reflect the Arbotix commander, which I don’t think they make anymore…
image

It is simple Arduino shield that worked only with 3.3v Arduino (uno clone mostly). Two thumb joysticks, and 6 buttons above the thumbsticks numbered as you can imagine: R1 is the farthest to the Right.
So right to left (R1 R2 R3 L4 L5 L6) and the two on top area LT and RT. The could have/should have had two extra buttons without any additional expense as the thumb joysticks can be clicked, but they did not route the signals…

Then some of this came from the old PS2 code for the Basic Atom Pro setup…
So I was in the process of trying to figure out what mapping made sense…

Also may still need to double check that we a) properly detect PS4 in this case and my tables for which bit is which button is correct.

Or potentially could always try to go back and resurrect my own DIY remote which I have not played with in a long time.

But if I were to do a new DIY, I would probably be more tempted to use different wireless than XBees…

1 Like

Hi @zenta - So far I am not seeing anything obvious in your photos.

This function is pretty simple:

void FindServos(void) {

  g_count_servos_found = 0;
  int32_t pos;
  Serial.println("\nSearch for all servos");

  // Initialize to no servos...
  for (int i = 0; i < MAX_SERVO_NUM; i++) {
    myLSS.setServoID(i);
    pos = myLSS.getPosition();
    if (myLSS.getLastCommStatus() == LSS_CommStatus_ReadSuccess) {
      g_ids[g_count_servos_found++] = i;
      Serial.print("    ");
      Serial.print(i, DEC);
      Serial.print(" - ");
      Serial.println(pos, DEC);
    }
  }
  Serial.println("  Done");
}

Question do you have servos connected at this point? If so have you supplied the servos something like 12v? I normally have been using Wall Wart. That is wondering if the servos are seen and you ask them for information or the like and they are only getting any voltage through the RX or TX pin, than maybe they are sucking the power away from the main processor.

At one point I thought about making these boards have a set of transistors like relay that you set a PIN high to enable power to go out to the servos, which some of the boards I have for Dynamixels do (modeled after The discontinued Arbotix Pro board, which was based off of another board, I think it was the CM510 board, but could be wrong.

You might try adding some additional Serial.print(); Serial.flush() functions at the start.

If me would add some calls like in setup:

...
  delay(1000);
  // Lets start of trying to locate all servos.
  // Initialize the LSS bus
  LSS::initBus(LSS_SERIAL, LSS_BAUD);
  Serial.println("After initBus"); Serial.flush();

  FindServos();
  Serial.println("After FindServos"); Serial.flush();

  PrintServoVoltage();
  Serial.println("After PrintServoVoltage"); Serial.flush();
...

Also similarly instrument FindServos.

void FindServos(void) {

  g_count_servos_found = 0;
  int32_t pos;
  Serial.println("\nSearch for all servos");
  Serial.flush();

  // Initialize to no servos...
  for (int i = 0; i < MAX_SERVO_NUM; i++) {
    myLSS.setServoID(i);
    pos = myLSS.getPosition();
    Serial.printf("After get Position %d\n", i); Serial.flush(); 
    if (myLSS.getLastCommStatus() == LSS_CommStatus_ReadSuccess) {
      g_ids[g_count_servos_found++] = i;
      Serial.print("    ");
      Serial.print(i, DEC);
      Serial.print(" - ");
      Serial.println(pos, DEC);
    }
  }
  Serial.println("  Done");
}

And see what is the last message you see…