Lynxmotion SES V2 Hexapod Robot

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%.

Hello all,

Quick update:

I tried the EM=0 and tried to use the SD modifier to see if it would work or not…
Like the T it does nothing…

Pushed up changes to the LSS test sketch we are running ‘c’ followed by ‘i’
Will see if it works with EM=1 any better than T…
Note: had to roll my own as no library function for this, nor even a define for “SD” for modifier.

But there is for SD as a motion setup command? so I am guessing that:

#1SD144\r#1D100\r

Will be interpreted differently than:

#1D100SD144\r

Will be interesting to see…

That’s correct. Running this function: (Keep forgetting how to post code in a proper way…)

void MoveAllServos(void) {
// first move all to center and on
AllServosCenter();

static int MIN_SERVO_POS = -200;
static int MAX_SERVO_POS = 200;
int servo_angle = 0;
int servo_increment = 3;

int positions[NUM_SERVOS];
int voltages[NUM_SERVOS];
int temps[NUM_SERVOS];
int index_print = 0;
Serial.println(“Move All servos: Enter any key to exit”);
while (Serial.read() != -1);

while (!Serial.available()) {
elapsedMicros em = 0;
servo_angle += servo_increment;
if (servo_angle >= MAX_SERVO_POS) servo_increment = -3;
if (servo_angle <= MIN_SERVO_POS) servo_increment = 3;
for (int j = 0; j < NUM_SERVOS; j++) {
myLSS.setServoID(pgm_axdIDs[j]); // So first is which servo
myLSS.moveT(servo_angle, 250);
}

Serial.printf("TQS:%u\n", (uint32_t)em);

while (em < 10000) ;//wait 10mS

}
}
I found using a rather high time value in the moveT command gave a softer movement.

I’ve not looked at the cfg files you mention yet.

1 Like

First - I wish I knew as well how to post code in the forum as well, so we are in the same both.

Thanks for posting the code - not sure its going to work for me with just one leg but will give it a try. PS nice video you posted was nice to see all the legs moving.

Ok not a problem with the cfg file was just curious.

Things are slightly overwhelming at the moment, hard to keep up with all your posts here.
I do have a PS4 remote and got a CSR V4.0 BT USB dongle. If you have a code I’m ready to try and look into. Would you mind pointing my in a direction what files to work on? @kurte I assume some of these are the ones?

You think you all can share the plugin?

But back to the question at hand. I did a couple things. In the sketch I had it print out what angles I was requesting as it was going and what get position is showing and bouncing it against LA:
Data from sketch:

Current pos: (qd: 446), dPos(-896), tStep(-89)
i: 1, move: 357
i: 2, move: 268
i: 3, move: 179
i: 4, move: 90
i: 5, move: 1
i: 6, move: -88
i: 7, move: -177
i: 8, move: -266
i: 9, move: -355
i: 10, move: -444
Final Move: -450
Time(ms)/ Pos(deg)
258 / 446, 436, 407, 370, 322, 266, 204, 136, 59, -18, -108

You can clearly see there is a difference in what gets returned from get position. On the first and last moves from the LA confirms that:

In actuality it does move the servo the 90degs to the next position from my recognizing.

Now as a spoof I add in a 500ms delay:

    delay(em0_rate);
    delay(500);
    temp[i] = LSS_1.getPosition();

GetPosition works:

goal: -450, time: 250, pos_num: 10 Current pos: (qd: 446), dPos(-896), tStep(-89) i: 1, move: 357 i: 2, move: 268 i: 3, move: 179 i: 4, move: 90 i: 5, move: 1 i: 6, move: -88 i: 7, move: -177 i: 8, move: -266 i: 9, move: -355 i: 10, move: -444 Final Move: -450 Time(ms)/ Pos(deg) 5258 / 447, 359, 270, 182, 92, 4, -86, -174, -264, -353, -447
There could be a couple of contributing factors to this: (1) Running at 250K baud, (2) comm issue with the servo - servo completes moves but when getting position servo not ready to transmit right away.

Now you might ask why am I doing this. Trying to get an accurate time to see if it works.

Tell me about it.
Yes. The LSS_PhoenixUSBJoystick is one it kind of sort of works. At least the legs will up and down.

Am also working on the zenta one: mjs513/LSS_Phoenix_BT (github.com). To be hones probably can grab both of them from there. I am using that as our experimental before posting to Kurt’s repository.

2 Likes

I’m Back :smiley:

Was out removing a couple of trees that were sort of blocking some of my trails.

Posting code like: The code that was trying to do moves using the speed modifier:

void cycleStance()
{

  while (Serial.read() != -1) ; // clear any remaining serial input.
  // BUGBUG:: quick and dirty setup first move
  for (uint8_t position = 0; position < RF_STANCE_COUNT; position++) {
    for (uint8_t leg = 0; leg < COUNT_LEGS; leg++) {
      if (legs[leg].leg_found) {
        myLSS.setServoID(legs[leg].coxa.id);
        legs[leg].coxa.time_position = myLSS.getPosition(); 
        myLSS.setServoID(legs[leg].femur.id);
        legs[leg].femur.time_position = myLSS.getPosition();
        myLSS.setServoID(legs[leg].tibia.id);
        legs[leg].tibia.time_position = myLSS.getPosition();
      }
    }
  }


  for (uint8_t count = 0; count < 1; count++) {
    for (uint8_t position = 0; position < RF_STANCE_COUNT; position++) {
      for (uint8_t leg = 0; leg < COUNT_LEGS; leg++) {
        if (legs[leg].leg_found) {

          myLSS.setServoID(legs[leg].coxa.id);
          // compute speed... 
          int delta_pos = abs(legs[leg].coxa.time_position - rf_stance[position][0]); 
          int move_speed = 3600000l  / (delta_pos * servo_move_time);
          LSS::genericWrite(myLSS.getServoID(), LSS_ActionMove, rf_stance[position][0], "SD", move_speed);
          //myLSS.moveT(rf_stance[position][0], servo_move_time);
          //myLSS.move(rf_stance[position][0]);
          myLSS.setServoID(legs[leg].femur.id);
          delta_pos = abs(legs[leg].femur.time_position - rf_stance[position][1]); 
          int move_speedf = 3600000l  / (delta_pos * servo_move_time);
          LSS::genericWrite(myLSS.getServoID(), LSS_ActionMove, rf_stance[position][1], "SD", move_speedf);
          //myLSS.moveT(rf_stance[position][1], servo_move_time);
          //myLSS.move(rf_stance[position][1]);
          myLSS.setServoID(legs[leg].tibia.id);
          delta_pos = abs(legs[leg].tibia.time_position - rf_stance[position][2]); 
          int move_speedt = 3600000l  / (delta_pos * servo_move_time);
          LSS::genericWrite(myLSS.getServoID(), LSS_ActionMove, rf_stance[position][2], "SD", move_speedt);
          //myLSS.moveT(rf_stance[position][2], servo_move_time);
          //myLSS.move(rf_stance[position][2]);
          legs[leg].coxa.move_status = LSS_StatusUnknown;
          legs[leg].femur.move_status = LSS_StatusUnknown;
          legs[leg].tibia.move_status = LSS_StatusUnknown;
          Serial.printf("<%d, %d %d> ", move_speed, move_speedf, move_speedt);
        }
      }
      //delay(delay1);
      checkStatus2(position);
      // lets try printing out positions of the legs (goal, timed position, end_position)
      Serial.println("\nPrint Servo Positions Joint(Goal, timed, end)");

      for (uint8_t leg = 0; leg < COUNT_LEGS; leg++) {
        if (legs[leg].leg_found) {
          myLSS.setServoID(legs[leg].coxa.id);
          Serial.printf("C:%u(%d, %d, %d)", myLSS.getServoID(), rf_stance[position][0], legs[leg].coxa.time_position, myLSS.getPosition());
          myLSS.setServoID(legs[leg].femur.id);
          Serial.printf("\tF:%u(%d, %d, %d)", myLSS.getServoID(), rf_stance[position][1], legs[leg].femur.time_position, myLSS.getPosition());
          myLSS.setServoID(legs[leg].tibia.id);
          Serial.printf("\tT:%u(%d, %d, %d)\n", myLSS.getServoID(), rf_stance[position][2], legs[leg].tibia.time_position, myLSS.getPosition());

          // remember the last position to use in next one... 
          legs[leg].coxa.time_position = rf_stance[position][0]; 
          legs[leg].femur.time_position = rf_stance[position][1]; 
          legs[leg].tibia.time_position = rf_stance[position][2]; 

        }
      }

      //GetServoPositions();
      if (Serial.available()) {
        Serial.println("*** Paused hit any key to continue ***");
        while (Serial.read() != -1);
        while (Serial.read() == -1);
        while (Serial.read() != -1);
      } else delay(3 * delay1);
    }
  }
}

I believe that this sort of matches or uses markdown format stuff… like:

But a couple of basic ways. If you have something short that you want in blocks you can simply have a blank line followed by one or more indented lines (like 4 spaces)… like:

#1P500\r

For large blocks like above, you can use what I think they call fences? but
if you start a row with three characters (on my keyboard to left of 1 key below ~ That will start a block which ends with another line with three characters… Which is what I did for the block above…

About to try changing that block to commands and see what it does…

@dialfonzo @cbenson and all:

I am experimenting with different options to again see if we can find a way to use the servos firmware to do more of the work… So experimenting with a few different options. Back in the posting I did about:

So I tried turning EM=1 and tried the program again to see about the timings… Feels like the servos are going much slower than I expected…

So then looked at Wiki and I see: for the modifier: https://wiki.lynxmotion.com/info/wiki/lynxmotion/view/lynxmotion-smart-servo/lss-communication-protocol/#HSpeed28S2CSD29modifier

Modifier (SD) is only for a position (D) or relative position (MD) action and determines the speed of the move in degrees per second. A speed modifier (SD) of 180 would cause the servo to rotate from its current position to the desired absolute or relative position at a speed of 180 degrees per second.

But if I look at the Motion Setup command for Max speed: https://wiki.lynxmotion.com/info/wiki/lynxmotion/view/lynxmotion-smart-servo/lss-communication-protocol/#HMaximumSpeedinDegrees28SD29
We see:

This command sets the servo’s maximum speed for motion commands in tenths of degrees per second for that session

So both with the same Name SD = Command in tenths of degree and modifier in degrees? Is this correct? If so confusing, or my guess is more likely wiki wrong?

Thanks

Update - Looks like the SD modifier is probably in tenths of a degree.

Hi @kurte!

mechDOG’s code uses EM=0. We are going to share the code… nothing fancy or sophisticated… but it’s a good example of multiple servos moving at the same time (starting and ending the move at the same time).

1 Like

Thanks @dickel for sharing.

Examples always helps - by any chance is it doing timed moves?

BTW_ was having fun watch the youtube videos on mechDog

1 Like

Thanks @dickel,

I sort of figured you would say EM=0. So far have not seen otherwise.

Will be interesting to compare approaches, on the logical implementation of the group moves.

We will probably soon make a version of the Hex LSS Servo driver code uses EM=0, and roll our own (or borrow one).

Probably start off with making the code similar to what has done in the past for some different servos.

Probably something like:

You have an array of the desired new positions for the servos and another with the current positions.
You probably setup to try to output N logical frame per second lets say 50 which implies 20ms cycle.
i.e. if your move is to take 200ms. That implies your move will take 10 servo cycles

You then for each servo you calculate the delta move (new - old). you then compute how much to increment the servo position you output by…

So if servo 1 you wish to move from position 100 to 200. that would imply a delta of 100 and so for each servo update cycle you would add 10 to the position and you do this for all of the servos in the move…

That more or less is it. Sound similar to what you are doing?

There are some other minor things to take care of, like: checking you don’t go beyond the requested position. Also how to handle delta values that are not fully integer…
if you are only moving 5 units in 10 cycles, which of the cycles do you do the additions on. Two simple approaches… Do this with floating point… T4.1 has hardware floating point.

Or do like the old bioloid library (An early library for dynamixels) does. If you know you have a range of 3600, that value fits in 13 bits… So you could setup your deltas and working position to be shifted up 3 bits… And then when you add you can right shift back and only if it actually changes do you output value. The version of this code I have used is up in the github project: https://github.com/kurte/bioloidserial with functions with names like: interpolateSetup and Interpolatestep).

Again it will be great to see what approaches you have taken.

Thanks
Kurt

1 Like

One of our firmware gurus seems to have made a breakthrough regarding the communication. More news and hopefully firmware to test coming soon. :smiley:

1 Like

Do you have a link for the ones you have ?

That is good news!! I am going to stating getting things together from today and will be able to test as well… I would like to know what the problem was though (I am sure others would be as well ), if it is within the IP boundary obviously…

The posts in here are quite overwhelming… I am still reading through from last time and for some posts I have to read twice … but its all good… :slight_smile: