Lynxmotion SES V2 Hexapod Robot

I have played around with a few different boards:

The one that @dialfonzo assembled, started off as simple to assemble board, which uses the LSS adapter board to control the servos and talk to the servos and the like:

The Kitchen Sink, is different in that it does not require the LSS adapter and it has an XBee connector on it, but again in either case you don’t need to use XBees.

Here is the 3d… @cyberpalin beat me to assemble one.
It has it’s own DC/DC converter , lots of IO pins to play with. If you do use XBees it has three LEDS to show RX, TX, and connections. But again I will mostly use USB Host connection. I did still have the parts for 4 3.3v to 5v conversions. The first two are used like the other board for the Servos. Unlike the other board, I don’t need them for XBees as both the T4.1 and XBees run on 3.3v, but I setup optionally to populate the other two to bring out 5v versions of IO ins 24 and 25, which for example could be used for Neopixels or as these pins can be I2C could be used for DotStar, and as these pins are also UART pins I might experiment with RC receiver that does iBus… both have simple sound output and possible to hook up Adafruit/Sparkfun QWIIC devices

1 Like

Would love to be working on this with you guys, but too many other project underway which need my attention.

1 Like

@cyberpalin Keep in mind that the leg design being used is not actually the one shown in the wiki. Use the design (photos) at the top of this post. Since there’s no walking algorithm yet, the zero positions have not yet been determined.

1 Like

Those are cable clips which can be used to attach things with the magnets.
Created for the LSS 4 DoF Arm which do have shells on it. HERE

You can see one use on the mechDOG wiring HERE.

Having a big BEC on the LSS-Adapter would increase it’s size and price.
Usually a 3s LiPo or similar will provide the right voltage.

Found that out last night when I was assembly the leg :). Did exactly as you said, used the photos to assemble in post 2 to assemble the leg. :slight_smile:

Too bad. Think at some point RobotShop may need to update the firmware based on what we find. Believe @kurte mentioned some. Is that a possibility?

If there are issues found with the servo’s communication, our firmware team will certainly investigate and work on it.

Baud Rate: As fast as possible that is reliable :wink: Their LSS test sketch and elsewhere I believe said it could go up to 921.6K and they also show 750K. But I started at 500K and was getting a reasonable number of packets not looking right.

Quite a few tests were done before the servos were released, and the suggested baud rate ended up at 115200 with a very low rate of packet loss. You may be encountering the same issues we encountered during testing at higher baud rates.

1 Like

I’ve had some professional & personal delays, but I’m mostly at the end of “catching-up” to things. I should be able to get on with testing this stuff on my end in a few days.

Things noted so far:
a) some query functions error out often screwing up the Serial bus. In particular Serial Number a high percentage of the time.

b) Earlier it was suggested that if you wish to query multiple values from a servo, by writing out your complete set of query functions and then wait for the responses to come back. My simple tests showed that there did not appear to be any speed up at all. It is like for each logical servo cycle, it would output one result at a time.

c) Speed: I assume you are using hardware UART of the STM32 on the servo. So again not sure why you would need to go down to 115200? As mentioned before with old AX12 servos I typically ran at 1MBS. WIth their newer ones ran often at 2MBS, sometimes faster. They have setups that go up to 6…

d) Reliable communications: It might just be me, but I personally believe you need some form of reliable communications. Especially when you have motors and the like running in an electrically noisy setup. Personally I wish you implemented some form of packet setup, with some form of checksum or CRC and optionally some form of ACK/NAK.

Again I understand you like the idea of simple ASCII so one can easily read the stuff. Also I understand your desire for SSC-32 compatibility. That is I can totally understand the goal that you should be able to take an SES V1 design with RC servos and an SSC-32 , swap in the LSS2 servos and a goal that the software should just work. But at a minimum that would have required you to implement the group moves.

And for example with some devices you have that option, like the RoboClaw or XBee or … But with many of these, you then have the option to turn on some form of packets.

Would love to be working on this with you guys, but too many other project underway which need my attention.

Personally I think you do need an SES/LSS Advocate, where one of their primary Job responsibilities is to drive things like this… Probably said enough :wink:

2 Likes

Did something interesting this morning. I used the PEP v2.02 spreadsheet to generate a gait - all I changed were the lengths for the coxa, femur and tibia - I will post something on that config later.

Using the gait angles for the RF I added a gait generator to @kurte’s example sketch and noticed something (note for the session I changed the speed to 30 from 60). For each gait position I did a getPositions for each servo. When I ran it I did not see any noticeable movement of the leg which is kind of confirmed by the dump:
Position 1:
2:-2 1773
4:6 776
6:2 778
Position 2:
2:-2 1739
4:6 750
6:2 755
Position 3:
2:-2 1568
4:6 751
6:2 845
Position 4:
2:-2 1713
4:6 747
6:2 784
Position 5:
2:-2 1743
4:6 782
6:2 779
If I add a 1 second delay between positions:
Position 1:
2:70 1846
4:-303 880
6:-340 886
Position 2:
2:-52 1884
4:9 763
6:107 843
Position 3:
2:-24 1633
4:6 763
6:48 814
Position 4:
2:-2 1716
4:-1 885
6:-1 821
Position 5:
2:35 1733
4:-1 815
6:-42 872

So it looks like between positions will need a query to ensure that the servo is finished moving before the next position.

Guess it would have to be something Query Status and see if its moving and when finished move on?

Good morning @cyberpalin and others

Looks like someone is having some fun!
Is your output in PWM (RC) like servo positions centered at 1500 or in angles (10ths of a degree) Actually looks like maybe both…

There were a couple ways of doing some of this.

That is suppose Servo 2 wants to move from 70 to -52 in 100ms (Or what the step time is).
And so you output something like: #2D-52T100\r
Which hopefully will start moving that servo to that position and should arrive at that position in specific time.

However if you output a new command, it will override that…

Two ways we handled this. We detected that the servo made it to it’s position.

Do some form of Query. On SSC-32 this was the Q command… Which returned something like a . when done and something like a + if the last. With the LSS we do still have the Q command, which returns a byte showing different status.

Note: with the SSC-32 we only needed to talk to the SSC-32 as it controlled the servos, here we would maybe have to ask all of the servos are you done yet…

When we went with this approach (again only one Serial command: Probably just Q\r and one byte back, we found that the servo movements were not fluid but sort of jerky as each servo would start and stop, and then you had to wait for a full Query to complete, before you would start them to their next position.

So we went to our own timed output code. That is if I say that the move is supposed to last 100ms, I will output the next command 100ms from the time I started this move. We also worked to make this time as accurate as possible, as the SSC-32 would not execute the data, until it received the CR. So earlier we output everything but the CR and when that time came we output the final CR to start the next move.

However on Dynamixels, I think the code outputs the whole Group move command at the specified time. But the timing was reasonably the same, as we always output the exact same number of bytes per step.
Which usually worked reasonably well when run from Microcontroller. At times though I have seen issues when run through something like RPI, especially through USB, where the timing may be different when the RPI may be doing something else.

Side comment: So at one point, I had made a version of the firmware for the USB2AX device, which allowed me to say here is the next group move command to execute when you finish the previous one. Which removed the USB latency issues. Edit: I believe I also had code like this in my RPI port that used a Teensy to control the servos

My strong guess is that is what we will probably want to do the walking stuff using our own timing code as well. Unless again the LSS has the ability to say here is your next move…

Hope some of this makes sense

1 Like

Yes having some fun, I think :slight_smile:

Anyways. I am using your test sketch and added a ‘g’ command for generate gait. Then in that function I am using the move command to move it to the set angle:
myLSS.move(-48);
Think thats right for the angles if I read your setServoPosition correctly. Who knows with me.

To your other comment about

Do some form of Query. On SSC-32 this was the Q command… Which returned something like a . when done and something like a + if the last. With the LSS we do still have the Q command, which returns a byte showing different status.
I added an additional function called checkStatus to see if all 3 servos got to their hold position:
void checkStatus()
{
int8_t status1 = -1, status2 = -1, status3 = -1;
uint32_t statusTime = 0;
while(status1 != 6 || status2 != 6 || status3 != 6) {
status1 = myLSS.getStatus();
myLSS.setServoID(RF_COXA);
status2 = myLSS.getStatus();
myLSS.setServoID(RF_COXA);
status3 = myLSS.getStatus();
delay(1);
statusTime += 1;
}
Serial.printf(“Status: %d: %d, %d, %d\n”, statusTime, status1, status2, status3);
}

Did add the print loop time - think max time was 103ms in one case. Here is a little table I put together:

The first column is me typing in the angles manually.

Oh just for completeness here is my gait function (started out as a hack - guess should clean it up )
void generateGait()
{
for(int i=0; i < 5; i++) {
//Start position 1 - start position
// -4.8, 1.1, 11 degrees
myLSS.setServoID(RF_COXA);
myLSS.move(-48);
myLSS.setServoID(RF_FEMUR);
myLSS.move(11);
myLSS.setServoID(RF_TIBIA);
myLSS.move(110);
myLSS.setServoID(RF_COXA);

  Serial.println("Position 1: ");
  checkStatus();
  GetServoPositions();

	//position2
	//-2.6, 0.3, 5.1
	myLSS.setServoID(RF_COXA);
	myLSS.move(-26);
	myLSS.setServoID(RF_FEMUR);
	myLSS.move(3);
	myLSS.setServoID(RF_TIBIA);
	myLSS.move(51);

  Serial.println("Position 2: ");
  checkStatus();
  GetServoPositions();

	//position3
	// 0, 0, 0
	myLSS.setServoID(RF_COXA);
	myLSS.move(0);
	myLSS.setServoID(RF_FEMUR);
	myLSS.move(0);
	myLSS.setServoID(RF_TIBIA);
	myLSS.move(0);

  Serial.println("Position 3: ");
  checkStatus();
  GetServoPositions();

	//position4
	// 3.1, 0.3, -4.4
	myLSS.setServoID(RF_COXA);
	myLSS.move(31);
	myLSS.setServoID(RF_FEMUR);
	myLSS.move(3);
	myLSS.setServoID(RF_TIBIA);
	myLSS.move(-44);

Serial.println("Position 4: ");
checkStatus();
GetServoPositions();

	//position5 - end position
	// 6.7, 1, -8.2
	myLSS.setServoID(RF_COXA);
	myLSS.move(67);
	myLSS.setServoID(RF_FEMUR);
	myLSS.move(10);
	myLSS.setServoID(RF_TIBIA);
	myLSS.move(-82);

  Serial.println("Position 5: ");
  checkStatus();
  GetServoPositions();
}
	//leg up start position
	//6.7, -31.2, -34.3
	myLSS.setServoID(RF_COXA);
	myLSS.move(67);
	myLSS.setServoID(RF_FEMUR);
	myLSS.move(-312);
	myLSS.setServoID(RF_TIBIA);
	myLSS.move(343);

  Serial.println("Position Start Leg Up: ");
  checkStatus();
  GetServoPositions();

}
1 Like

@cyberpalin - Another quick update:
I hacked up my test program, to do a “Q” command
that timed how long it would take to do a Q command to all of the servos (Pushed up the change)

void QueryAllServos() {
  LSS_Status servo_status[MAX_SERVO_NUM];
  uint32_t query_time[MAX_SERVO_NUM];

  if (!g_count_servos_found) {
    Serial.println("Previous Find Servos failed to locate any servos: so retry");
    FindServos();
    return;
  }

  Serial.print("\nDo Query(Q) command on all servos ");
  elapsedMicros emTotal = 0;
  for (int i = 0; i < g_count_servos_found; i++) {
    elapsedMicros em = 0;
    myLSS.setServoID(g_ids[i]);
    servo_status[i] = myLSS.getStatus();
    query_time[i] = em;
  }
  Serial.printf("total time: %u\n", (uint32_t)emTotal);
  for (int i = 0; i < g_count_servos_found; i++) {
    Serial.printf("  %u: %u T:%u\n", g_ids[i], servo_status[i], query_time[i]);
  }
}

With all of the servos at default limp state:

Do Query(Q) command on all servos total time: 113096
  1: 1 T:959
  2: 1 T:682
  3: 1 T:674
  4: 1 T:647
  5: 1 T:650
  6: 1 T:676
  7: 1 T:684
  8: 0 T:100650
  9: 1 T:687
  10: 1 T:792
  11: 1 T:759
  12: 1 T:727
  13: 1 T:742
  14: 1 T:741
  15: 1 T:768
  16: 1 T:740
  17: 1 T:768
  18: 1 T:750

Looks like one servo failed and took over second.

I then used command to center all of the servos. and checked their status and their positions:

Cmd: q

Do Query(Q) command on all servos total time: 12717
  1: 6 T:676
  2: 6 T:667
  3: 6 T:646
  4: 6 T:679
  5: 6 T:663
  6: 6 T:649
  7: 6 T:659
  8: 6 T:673
  9: 6 T:687
  10: 6 T:761
  11: 6 T:731
  12: 6 T:746
  13: 6 T:757
  14: 6 T:751
  15: 6 T:732
  16: 6 T:749
  17: 6 T:734
  18: 6 T:755
...
Cmd: 4
1:2 754
2:3 746
3:-3 786
4:1 751
5:4 750
6:4 775
7:0 876
8:5 841
9:-3 830
10:-9 913
11:6 842
12:5 842
13:0 833
14:0 1178
15:6 843
16:1 854
17:4 843
18:-3 929

So in this case it took like 12ms to just find the status. Note: I am running at baud 250000

Looks like you posed message… So hopefully not too much of a cross post

@mjs513 - I did as you probably know I sent out an add to you my LSS_ test project…
Feel free to either merge your stuff in and/or PR to me or…

Again at some point could move some of this learning and tool stuff to the Beta project…

Ok just issued the PR with my pseudo RF leg gait: Added ‘g’ for simulate RF gait by mjs513 · Pull Request #1 · KurtE/LSS_Test_sketches (github.com)

I agree some point should move some of this stuff.

Oh just for the record and before I forget I configured the servos in LSS Config like this:

Servo 2:
Gyre - CCW
Servo 4:
Origin Offset: 700
Gyre - CCW
Servo 6:
Gyre - CCW
Origin Offset: 190

Used the spreadsheet to generate ripple 6 step profile for the RF leg .
Coxa Length: 5.08cm
Femur Length: 8.128 cm
Tibia Length: 11.43 cm
Used the spreadsheet to generate ripple 6 step profile for the RF leg.

This is using cbensons sample leg in his post #2 I think. I will post a graphic later today with the orientations

Thanks it is merged in :smiley:

And runs on one of the legs :smiley:

At least it runs on one of them - should be 2, 4 and 6 Servo Ids - which ever one that is for you :slight_smile:

Just did the swap of my problematic HDD after cloning last night - seems to be working. :slight_smile:

Wanted to ask but forgot - did you notice anything funky about the leg movement like it was real jerky and not smooth?

Yes it appeared to be really jerky.

Been busy in background answering some questions, but want to play some with it.
Unless you beat me to it :wink:

That is to try it with changing the code from like:

	myLSS.setServoID(RF_COXA);
	myLSS.move(-48);
	myLSS.setServoID(RF_FEMUR);
	myLSS.move(11);
	myLSS.setServoID(RF_TIBIA);
	myLSS.move(110);
	Serial.println("Position 1: ");
  	checkStatus();
 	 GetServoPositions();

To maybe something like

	myLSS.setServoID(RF_COXA);
	myLSS.moveT(-48, 250);
	myLSS.setServoID(RF_FEMUR);
	myLSS.moveT(11, 250);
	myLSS.setServoID(RF_TIBIA);
	myLSS.moveT(110, 250);
	Serial.println("Position 1: ");
//  	checkStatus();
// 	 GetServoPositions();
	delay(250);

And see how well it moves. The current ways set something like 5 positions where each of the
servos try to jump to their new position as fast as the servo will allow. But the MoveT, should tell
the servos to setup their move speed such that they all arrive at that new position at a quarter of a second.

Plus I am guessing that the checkstatus of the 3 servos will add something like at least a 2ms gap to each move, maybe longer. That is you just finished the query of first servo who was the last to complete, so you continue to query the other two, and then have to go back and query all three again…

Plus the time to read in all of the positions and print them.

We can help maybe minimize some of this that may help in certain cases by only asking those servos who have not already responded they are done for their status…

Maybe something like:

void checkStatus()
{
  int8_t status1 = -1, status2 = -1, status3 = -1;
  uint32_t statusTime = 0;
  while(status1 != 6 || status2 != 6 || status3 != 6) {
    if(status1 !-= 6) status1 = myLSS.getStatus();
    myLSS.setServoID(RF_COXA);
    if(status2 !-= 6) status2 = myLSS.getStatus();
    myLSS.setServoID(RF_COXA);
    if(status3 !-= 6) status3 = myLSS.getStatus();
    delay(1);
    statusTime += 1;
  }
  Serial.printf("Status: %d: %d, %d, %d\n", statusTime, status1, status2, status3);
}

Funny you posted the timing just now. Was rereading your post and was about to make some mods to sketch along the same lines. Must be reading each other’s mind. :slight_smile: Will let you know how it works out.

@kurte
I gave it a try and definitely works a lot smoother. Not its getting to final position fast enough though have to make another table and play some more