Lynxmotion SES V2 Hexapod Robot

Thanks,

But I guess that I am missing is how would one use EM=1 for anything other than simple one move operations? Like on a robot, maybe to close a gripper until it hits something.

That is how does one chain multiple moves of multiple servos into a smooth operation. As again the EM=1 system has no clue what I am going to ask it to go next, so it has no way to know if the servos should slow down, or speed up, or keep at the same speed. So what I see is they slow down and speed up and are not reliably at the position I asked them to be when the time elapses!

Also what I donā€™t understand is with EM=1 and IPE=1 (lots of TLAs)ā€¦
Why again the IPE does not use the SP or T data to figure out how much of a delta it should do for each of itā€™s intermediate points?

But for now, I guess best to work with bird in handā€¦

1 Like

Originally the EM=0 mode was just the absence of Motion Control.
It was useful but without any filtering the movements were not smooth.

We implemented the FPC (Filter Position Count) on top of that"
Once done, we implemented IPE which take care of motion in between 2 positions.

1 Like

For this (specific) case, the CH and CL modifiers were implemented: The current sensor is not super precise, but with a bit of experimentation, you will get a value which can be used for these modifiers to know when you want to stop the motion and either hold in place at the last position, or go limp (safety). This is used in the gripper of the 4DoF arm, and can easily be implemented in other degrees of freedom.

1 Like

That is exactly what EM=1 is meant for, for the most part.

You are literally describing the reason why a controller external to the smart actuators is required to do anything even remotely complex in robotics/animatronics/etc. And why multiple control modes are used in those cases.

The LSS themselves are only the actuators with no concept of their environment. Your code, taking the role of the controller, needs to provide that context in how you control them.

Of course, they are DC motors and thus controlling speed means controlling voltage. As you are already aware, that changes magnetic flux and available torque, too. All of it is tied together. So, if you ask for a timed move in a direction that has a higher or lower loads than your settings are set for you will get a different behaviour.

If you look into any larger platforms youā€™ll notice that (such as what @cmackenzie is doing) the situations at each joint, the motions requested and their relative impact/position in context with the entire platform are all considered to ensure proper response from the smart actuators.

EM=1 means that IPE is irrelevant. A different motion/control is done then.
IPE is only used when EM=0.

To be fair, EM is two lettersā€¦ :smiley: :rofl:

As mentioned above, IPE is used only during EM=0, which does not care for time modifiers to move commands. It always goes as fast as possible to the next position. This is where intermediate positions, the management of FPC, motion settings, etc. will matter more to get the behaviour you want in each motion.

Just make sure you donā€™t feed your bird some french fries or somethingā€¦ :wink:

1 Like

Thanks @scharette @dialfonzo @cbenson:

To try to summarize what all of your have said: EM==1 is in most cases can not be used. About the only rare case is for something like gripper where you only do one move. As such much of the higher level things such as timed moves, or controlling speed, or CH or CLā€¦ are not applicable to the leg servos that are part of the hexapod. As such we need to implement own servo interpolation code. And when you are in EM==0 mode, thhe SSC-32 compatibility is mostly that you output commands in ASCII characters that end with a CR.

Note: the need to do your own interpolation code is not unique to these servos. With the first generation Dynamixels like the AX12 servos, they had some ability to do interpolation, but their very limited AVR processor boards did not do it as well as many of us would like. So we mostly used Software interpolation. If you have looked at the Phoenix code bases like Phoenix_driver_AX12ā€¦ you will notice in the driver we had it configurable to experiment. running the Hexapod either way.

But back when I was first using Dynamixels, the library developers, did not leave you on your own to have to reinvent the wheel for this. Back then many of us used (and still use) some variants of the Bioloid library. The library was developed by Michael Ferguson back sometime around 2008. If you follow ROS development at all his name is probably familiar. The library has a concept in it referred to as a pose. So most of the motion code is done by telling the pose code here is the new positions for each of the servos and how long to get thereā€¦ It does the simple math of (destination - current)/(time converted to number of steps)ā€¦ And updates all of the servos by that amount per cycleā€¦ I have also replicated the same code a long time ago in my version of the Servo library (ServoEX) ā€¦ So again nothing new here.

I was in the process of making a version of the simple cycle through 7 positions with timing, to work with the SSC-32. Some extracts of it:
The Leg servo structure was updates to also have the SSC pin number and if that servo needed to be inverted. Can post or put to my github if anyone wishes to look

// Define each of the moves Coxa, Femur, Tibia in 10ths of a degree one line per move
int16_t rf_stance_smooth [RF_STANCE_COUNT][3] =
{
  {0, -600, -600},       //Low
  // 0, -900, 510 degrees
  {100, -300, -300},      //mid Low
  {200,  0,  0},          //Med
  {0,  300, 300},         //High
  { -100,  0,  0},        //Med
  { -200, -300, -300},    //mid Low
  {0, -600, -600}       //Low
};

elapsedMillis emServos;
...
// convert angles to PWM..
void inline ConvertAndOutputSSCServoPos(uint8_t servo_id, int pos, int invert) {
  if (invert) pos = -pos;
  int32_t  pwm_pos = ((long)(pos + 900)) * 1000 / cPwmDiv + cPFConst;
  userial.printf("#%uP%u", servo_id, pwm_pos);
}
void loop()
{
...

  Serial.printf("Cycle Move Times %d\n", move_time);
  for (uint8_t position = 0; (position < RF_STANCE_COUNT) && !Serial.available(); position++) {
    for (uint8_t leg = 0; leg < COUNT_LEGS; leg++) {
      ConvertAndOutputSSCServoPos(legs[leg].coxa.ssc32_pin, rf_stance_smooth[position][0], legs[leg].coxa.ssc32_inv);
      ConvertAndOutputSSCServoPos(legs[leg].femur.ssc32_pin, rf_stance_smooth[position][1], legs[leg].femur.ssc32_inv);
      ConvertAndOutputSSCServoPos(legs[leg].tibia.ssc32_pin, rf_stance_smooth[position][2], legs[leg].tibia.ssc32_inv);
    }
    while (emServos < (uint32_t)move_time) ; // wait for the right time
    userial.printf("T%u\r", move_time);
    emServos = 0;
  }
  if ((move_time == MOVE_TIME_MAX) || (move_time == MOVE_TIME_MIN)) move_time_change = -move_time_change;
  move_time += move_time_change;
}

Again nothing terribly un-ordinary.

Could easily do without helper function. The SSC-32 driver code does the math inline with one Serial.printā€¦

Many of the things that have been mentioned throughout this beta, I an surprised that they were not addressed long ago, probably in the Servo Alpha time frame.

That is I would have suspected that many simple sketches like this, and probably other simple sketches that ran on simple robots like the BRAT, would have a version of it developed for SES2 and LLS servos. And through this process you could determine if the servos firmware would support something like timed group moves and be able to smoothly transition. If yes great, if not than develop support library code to facilitate. In either case I would hope that the WIKI addressed how to convert from SES1 to SES2 including servo SSC-32 to LSS and included examples. Never too late.

Now back to playingā€¦

Kurt

Well Two starts with T :smiley:

Actually our birds :bird: (chickens) would probably enjoy french fries

1 Like

That sounds about right for an hexapod. To be clear here, the LSS could do more (plenty of space for upgrades) on the interpolation front (and in EM=0; IPE=1, it does some), but you wonā€™t have timed moves like you were saying from the LSS firmware itself with also smooth motion with quickly varying loads (such as in a hexapod; at least for one of the 2/3 joints).

Certainly more examples are a good idea. I suppose that was the goal of the beta test, to be honest.

1 Like

Thanks @scharette - To me having a good set of examples that you were developing your new products for, would be fundamental to driving the development.

Again this is just me, but at the of the Jim Frye era of Lynxmotion, I was searching for what my next Robotics projects would be, and new online homeā€¦

At that time what really intrigued me was some stuff I started reading about some new products coming out, from Robotis. I believe they were probably near the end of beta cycle as if I remember correctly you could pre-order them. They had three kits at the time and I was trying to decide between two kits at the time, which is now no longer available but Trossen still shows up on their Store pages:
Bioloid Comprehensive Robot Kit or Bioloid Premium Robot Kit

What really caught my interest, was for example their premium kit they showed working setups for a hexapod, a puppy, simple humanoidā€¦ This included instructions on how to build, code and controller tor run them, sensorsā€¦ I was about to pull the trigger back then, but decided to instead go with Trossen Robotics and the PhantomX hexapod, as I already had interactions with at the their main developer at the time.

Likewise as I have mentioned before, my first attempt to understand ROS was to work(play) with KevinOā€™s ROS hexapod code and make it work on the PhantomX. But at the time it really felt like trying to fit a square peg in a round hole, that is to make the hexapod act like a limited Roverā€¦

So I decided to purchase a TurtleBotā€¦ There were two versions in contention, The Turtlebot 2i by Trossen and the Turtlebot 3 by Robotis. In the end I went with the Turtlebot 3 by Robotis, for a few reasons, including: price (since I was mainly purchasing as learning tool), Expertise (main developers wrote free book on ROS), and examples of different configurations. They sell two versions: Burger and Waffle, and they also show several other configurationsā€¦

1 Like

{ā€¦} at the of the Jim Frye era of Lynxmotion, I was searching for what my next Robotics projects would be, and new online homeā€¦

In hindsight, there would have been many things RobotShop could / should have done differently during that transition. Live and learn and hope to improve for the next time.

But at the time it really felt like trying to fit a square peg in a round hole

Completely irrelevant, but made me think of this for those who have not seen it:

2 Likes

One size fitā€™s all :rofl:

1 Like

Hi All,

I have been following the discussion here and there is so much good information in these thread. I agree with @cyberpalin and @kurte that there should be some place where this info is written down and also about the example codes. It makes perfect sense.

These kits are/were something. I never had any opportunity to work with Dynamixel servos. As I said before, the very first servos I really got were the RC type MG996R from Tower PRO about $4 per piece. Getting LSS was a bit of decision on my part. Which now after the discussion I think that if I am a cautious buyer before buying them I would need the example codes and detailed instruction / information etc. They are not cheap when considering buying a full hexapod. May be once the hexapod is complete there would be such things available but I thought I would mention because that seems like a lot important now that I have been playing a lot more with them.

Also, with all the discussion on the EM=0/1 etc etcā€¦ I was a bit intrigued and decided to give my own hexapod code base a try with different things. In my code, atleast for the gait it sends multiple positions and I have used EM=0 for the code. I tried with MoveT API but the motion was awfulā€¦ I couldnā€™t get it to work smoothly.
My extract for the servo configuration looks like belowā€¦

One question on it. I know in the LSS_TEST sketches it uses the maximum speed value as 600. What is that value ? degrees/ sec or RPM. When I read the maxSpeed in my code it says 360. So what does it correspond to ?

// test our servos
  for (uint8_t i = 0; i <= 17; i++)
  {
    myLSS.setServoID(l2sid[i]);// mapping for my code

    pos = myLSS.getPosition();
    servo_speed = myLSS.getMaxSpeed(LSS_QueryConfig);
    motionprofile_before = myLSS.getIsMotionControlEnabled();
    if (motionprofile_before)
    {
      myLSS.setMotionControlEnabled(0);
      motionprofile_after = myLSS.getIsMotionControlEnabled();
    }
    myLSS.setAngularStiffness(-4);
    delay(250);
    myLSS.setAngularHoldingStiffness(4);
    delay(250);
  }

So now on the hexapod side I have another video where with help from @cyberpalin and @kurte I was able to attach a wired PS4 controller by integrating its code base with mine. Thanks @kurte and @cyberpalin for all your help and the code with the USB host code.

So the hexapod still needs some fine tuning but I did this for fun. I havenā€™t calibrated it. It is partly because I have no idea how to and what should be the correct procedure. The legs do look like there is some sort of offset in them. Need to read about this partā€¦

I actually also wanted to get to know the USB control code and how the different variables are configured on the Phoenix. I also have another question regarding the SmoothControl function. What does it achieve for translation ? I see it is only used for translation and seems like it gets the current input control and multiplies that by a factor (2/3) and then divides the different between the current position and the controller input by another number. Is that a generic function or is that tailored for DIY controller with more range ?

Now for the video. Here is an uncut / unedited video from my phone. The Hex starts off by showing the translation then rotation(rotation need some workā€¦ ) and then the tripod gaitā€¦ This is all with EM=0 the servo configuration aboveā€¦

I hope you all like itā€¦

Now on to decoding more of the Phoenix codeā€¦

May be now is the correct time to ask this question to @kurte / @cyberpalin. How do I pair the PS4 controller to the CSR dongle on the Teensy?

3 Likes

Thats maxSpeed - its in degrees per second.

Very cool video so it works with EM0. Been testing different things with the following settings:

[CODE]
myLSS.setMotionControlEnabled(0);
myLSS.setAngularHoldingStiffness(4, LSS_SetSession);
myLSS.setAngularStiffness(-4, LSS_SetSession);
myLSS.setFPC(3, LSS_SetSession);
[\CODE]
all based on the discussion plus the testing that I was doing with @dialfonzo that kind of kicked off the whole EM0 lesson - have a word document now with all the notes. While it worked with 1 leg very nicely wasnā€™t able to test with a spider. So thank you for the great video :slight_smile:

For the PS4 that relatively easier.

  1. Edit the LSS_Phoenix_Input_USB_Joystick.cpp to uncomment the line that says pairing and comment out the next line - that line is used when you are already paired.
#if defined(BLUETOOTH)
	//BluetoothController bluet(myusb, true, "0000");   // Version does pairing to device
	BluetoothController bluet(myusb);   // version assumes it already was paired
  1. Turn everything on then hit the PS4 button and you should pair with the dongle.

Oh and remember to go in Hex_cfg.h and uncomment the line at the begining of the file to use Bluetooth - its a define.

Then after that you can go back to the way it was with pairing line commentd out and then all you have to do is hit the PS4 button.

2 Likes

I agree with @cyberpalin and @kurte that there should be some place where this info is written down and also about the example codes. It makes perfect sense.

We can add any useful information to the first, second and third posts here in this thread (easy access). Feel free to reply here with what to include.

1 Like

@madmax, glad it have it working with EM=0

Thanks @cyberpalin

One note on the pairing of the PS4, that once it boots up with the pairing code turned on in the sketch, you Share button and PS button at the same time, until the PS4, starts a sort of double blinkā€¦ Hopefully then it pairs. Then assuming it paired, you change the two lines back and rebuild again.

With the BLUETOOTH option, it was needed before on PS4 as a little of the data is different when connected by plugged in versus by BT. In particular the HAT buttons. Some of the current code with BT enabled, tries to deduce this. It assumes the PS4 is BT if the BT object is active otherwise it assumes wired.

Note: I have also cheated in the past and simply paired a PS4 with a BT dongle on my Linux bootā€¦ Could probably do as well with windows, but my windows machine has a BT built inā€¦

With PS3 it is even easierā€¦ You can use the normal BT buildā€¦ Then you need to plug in the BT dongle and make sure it starts up, and either remove it or if using hub, plug in the PS3 wiredā€¦ Hopefully code will have remembered the BT address. Once the joystick has started up wired, I believe you hold down either the L1 or R1 buttons and the PS3 button and it will tell the PS3 to update itself for that BT objectā€¦ After that simply unplug it, plug back in the BT dongle and press the PS3 button to connect upā€¦

1 Like

Darn it - i keep forgetting to tell people to hold the share/ps4 button down at the same time.

Pretty much. If wired the axis is on one dimension of the returned data while connected BT its on another for the HAT data. Other than that there is no difference. @kurte added the code to auto determine if you are wired or not.

yep - I have cheated that way as well. It does work.

Yep. @kurte did a great job with USBHost_t36.

1 Like

Thanks @kurte and @cyberpalin for the encouraging and kind words. I will experiment with the BT code. Thanks for the detailed instructions. I Will keep you updatedā€¦

My pleasure. However just to be clear, this is not the Phoenix code. I havenā€™t got that working yet. It is my own code base from my hexapod which i did earlier this year. Phoenix code is a big beast(or a bird as some might say ā€¦)

Its amazing!! Thanks again @kurte and @cyberpalin

2 Likes

@cbenson @dialfonzo and allā€¦

Looks like I am running into another issue with the servos firmwareā€¦

I have code in my WIP where I was trying to detect if the servos were externally configured and if so donā€™t need to configureā€¦
So I thought I would test the Gyre of the coxas knowing that half of them will need to be set different than defaultā€¦

So have a method:

//============================================================================================
// Check to see if the servos have been configured properly
//============================================================================================
void ServoDriver::checkAndInitServosConfig(bool force_defaults)
{

	use_servos_moveT = false;

	// lets see if we need to set the Origin and GYRE...
	// start off if the GYRE does not match what we believe we need... Set everything
	if (!force_defaults) {
		Serial.println(">>> Check Servo Settings <<<");
		for (uint8_t leg = 0; leg < COUNT_LEGS; leg++) {
			myLSS.setServoID(cPinTable[FIRSTCOXAPIN+leg]);
			// BUGBUG we did reset but session did not equal config...
			LSS_ConfigGyre cgyre_session =  myLSS.getGyre(LSS_QuerySession);
			LSS_ConfigGyre cgyre_config =  myLSS.getGyre(LSS_QueryConfig);
			if (myLSS.getLastCommStatus() == LSS_CommStatus_ReadSuccess) {
				Serial.printf("%d:%d:%d:%d ", myLSS.getServoID(), cGyreTable[FIRSTCOXAPIN+leg], cgyre_session, cgyre_config);
				if (cGyreTable[FIRSTCOXAPIN+leg] != cgyre_config) {
					Serial.println("\n *** checkAndInitServosConfig: Need to configure servos ***");
					force_defaults = true;  // reuse variable
					break;
				}
			}
		}

	}

	// Either the caller to setup defaults or quick check above said to...
	// First lets try broadcasts for the LSS=0 crud
	myLSS.setServoID(LSS_BroadcastID);
	myLSS.setMotionControlEnabled(0);
	delay(5);
	myLSS.setAngularHoldingStiffness(4, LSS_SetSession);
	delay(5);
	myLSS.setAngularStiffness(-4, LSS_SetSession);
	delay(5);
	myLSS.setFilterPositionCount(5, LSS_SetSession);
	delay(5);


	for (uint8_t leg = 0; leg < COUNT_LEGS; leg++) {
		legs[leg].leg_found = true;
		myLSS.setServoID(cPinTable[FIRSTCOXAPIN+leg]);
		if (myLSS.getStatus() == LSS_StatusUnknown) legs[leg].leg_found = false;
		if (force_defaults) {
			Serial.print("@");
			myLSS.setGyre(cGyreTable[FIRSTCOXAPIN+leg], LSS_SetSession);
			myLSS.setOriginOffset(cDefaultServoOffsets[FIRSTCOXAPIN+leg], LSS_SetSession);
		}

		myLSS.setServoID(cPinTable[FIRSTFEMURPIN+leg]);
		if (myLSS.getStatus() == LSS_StatusUnknown) legs[leg].leg_found = false;
		if (force_defaults) {
			myLSS.setGyre(cGyreTable[FIRSTFEMURPIN+leg], LSS_SetSession);
			myLSS.setOriginOffset(cDefaultServoOffsets[FIRSTFEMURPIN+leg], LSS_SetSession);
		}

		myLSS.setServoID(cPinTable[FIRSTTIBIAPIN+leg]);
		if (myLSS.getStatus() == LSS_StatusUnknown) legs[leg].leg_found = false;
		if (force_defaults) {
			myLSS.setGyre(cGyreTable[FIRSTTIBIAPIN+leg], LSS_SetSession);
			myLSS.setOriginOffset(cDefaultServoOffsets[FIRSTTIBIAPIN+leg], LSS_SetSession);
		}

		if (legs[leg].leg_found) Serial.printf("Servos for Leg %s **found**\n", legs[leg].leg_name);
		else Serial.printf("Servos for Leg %s **NOT found**\n", legs[leg].leg_name);
	}
}

Before this code is called the init function broadcasts a servo resetā€¦

	// Reset all servos in case any are in error state
	Serial.println("ServoDriver::Init - reset all servos");
	myLSS.setServoID(LSS_BroadcastID);
	myLSS.reset();
	delay(1500);  // make sure all servos reset.

I am running into a few issuesā€¦

If I run the above code just after powering upā€¦
You will see output showing:

Program Start
ServoDriver::Init - reset all servos
Servo(0): 8 -11
Servo(1): 14 1
Servo(2): 2 9
Servo(3): 7 -6
Servo(4): 13 5
Servo(5): 1 3
Servo(6): 10 864
Servo(7): 16 859
Servo(8): 4 823
Servo(9): 9 -859
Servo(10): 15 -856
Servo(11): 3 -862
Servo(12): 12 525
Servo(13): 18 515
Servo(14): 6 519
Servo(15): 11 -521
Servo(16): 17 -510
Servo(17): 5 -521
>>> Check Servo Settings <<<

8:-1:1:1

*** checkAndInitServosConfig: Need to configure servos ***

@Servos for Leg Right Rear **found**
@Servos for Leg Right Middle **found**
@Servos for Leg Right Front **found**
@Servos for Leg Left Rear **found**
@Servos for Leg Left Middle **found**
@Servos for Leg Left Front **found**

Notice the last part with the 8:01:1:1 saying it needs to configure servosā€¦

Now if I restart the program you see:

>>> Check Servo Settings <<<
8:-1:-1:-1 14:-1:-1:-1 2:-1:-1:-1 7:1:1:1 13:1:1:1 1:1:1:1 Servos for Leg Right Rear **found**

Note: just put in the main part hereā€¦
You see it cycled through all 6 coxa pins, and said they were all initialized properly?

Two issues:

First issue: Reset of servo I thought was supposed to revert everything back to what is stored in EEPROMā€¦

Second issue: The init code I showed above does if thinks it needs to to set the Gyre for the sessionā€¦
So why after reboot. does it show the Config setting as changedā€¦ Note: If power off and back on they again show that this value has not changed on the EEPROMā€¦

Another issue I have been running into is sending settings to broadcast IDs is not always workingā€¦ That is again in the code above we have:

	myLSS.setServoID(LSS_BroadcastID);
	myLSS.setMotionControlEnabled(0);
	delay(5);
	myLSS.setAngularHoldingStiffness(4, LSS_SetSession);
	delay(5);
	myLSS.setAngularStiffness(-4, LSS_SetSession);
	delay(5);
	myLSS.setFilterPositionCount(5, LSS_SetSession);
	delay(5);

At the start of my current offsets command code, I print out settings, to see what is going on:

	for (sSN = 0; sSN < NUMSERVOS; sSN++) {
		asOffsets[sSN] = 0;
		myLSS.setServoID(cPinTable[sSN]);
		Serial.print("Servo: ");
		Serial.print(apszLegs[sSN % CNT_LEGS]);
		Serial.print(apszLJoints[sSN / CNT_LEGS]);
		Serial.print("(");
		Serial.print(cPinTable[sSN], DEC);
		Serial.print(") Pos:");
		Serial.print(myLSS.getPosition(), DEC);
		Serial.print("\tG:");
		Serial.print(myLSS.getGyre(), DEC);
		Serial.print("\tEMC:");
		Serial.print(myLSS.getIsMotionControlEnabled(), DEC);
		Serial.print("\tFPC:");
		Serial.print(myLSS.getFilterPositionCount(), DEC);
		Serial.print("\tAS:");
		Serial.print(myLSS.getAngularStiffness(), DEC);
		Serial.print("\tAH:");
    	Serial.print(myLSS.getAngularHoldingStiffness(), DEC);
		Serial.print("\tO:");
		Serial.print(myLSS.getOriginOffset(), DEC);
		Serial.print("\tAR:");
		Serial.println(myLSS.getAngularRange(), DEC);
	}

In this last run I see:

Serial Cmd Line:o<eol>
Servo: RR Coxa(8) Pos:-2 G:-1 EMC:0 FPC:5 AS:0 AH:4 O:0 AR:1800
Servo: RM Coxa(14) Pos:-1 G:-1 EMC:0 FPC:5 AS:0 AH:4 O:0 AR:1800
Servo: RF Coxa(2) Pos:-4 G:-1 EMC:0 FPC:5 AS:0 AH:4 O:0 AR:1800
Servo: LR Coxa(7) Pos:-2 G:1 EMC:0 FPC:5 AS:0 AH:4 O:0 AR:1800
Servo: LM Coxa(13) Pos:2 G:1 EMC:0 FPC:5 AS:0 AH:4 O:0 AR:1800
Servo: LF Coxa(1) Pos:3 G:1 EMC:0 FPC:5 AS:0 AH:4 O:0 AR:1800
Servo: RR Femur(10) Pos:9 G:-1 EMC:0 FPC:5 AS:0 AH:4 O:-104 AR:1800
Servo: RM Femur(16) Pos:10 G:-1 EMC:0 FPC:5 AS:0 AH:4 O:-104 AR:1800
Servo: RF Femur(4) Pos:5 G:-1 EMC:0 FPC:5 AS:0 AH:4 O:-104 AR:1800
Servo: LR Femur(9) Pos:104 G:1 EMC:0 FPC:5 AS:0 AH:4 O:-104 AR:1800
Servo: LM Femur(15) Pos:8 G:1 EMC:0 FPC:5 AS:0 AH:4 O:-104 AR:1800
Servo: LF Femur(3) Pos:7 G:1 EMC:0 FPC:5 AS:0 AH:4 O:-104 AR:1800
Servo: RR Tibia(12) Pos:3 G:-1 EMC:0 FPC:5 AS:0 AH:4 O:-137 AR:1800
Servo: RM Tibia(18) Pos:3 G:-1 EMC:0 FPC:5 AS:0 AH:4 O:-137 AR:1800
Servo: RF Tibia(6) Pos:5 G:-1 EMC:0 FPC:5 AS:0 AH:4 O:-137 AR:1800
Servo: LR Tibia(11) Pos:7 G:1 EMC:0 FPC:5 AS:0 AH:4 O:-137 AR:1800
Servo: LM Tibia(17) Pos:6 G:1 EMC:0 FPC:5 AS:0 AH:4 O:-137 AR:1800
Servo: LF Tibia(5) Pos:4 G:1 EMC:0 FPC:5 AS:0 AH:4 O:-137 AR:1800
Find Servo Zeros.

$-Exit, +- changes, *-change servo

0-n Chooses a leg, C-Coxa, F-Femur, T-Tibia

Servo: RR Coxa(8)

In this case the AngularHoldingā€¦ does not appear to have been processed.

In other runs some servos miss one or more of the settings.

Now back to playing (or pulling hair out)

Note to self and others: Associated with previous post:

Using extra HS1 I purchased, I tried seeing what impact setting GYRE has on the offsetsā€¦
I used LSS app to reset to default, other than I changed back to 250000 and id 1

 LSS::initBus(LSS_SERIAL, LSS_BAUD);

  // Initialize LSS to position 0.0 Ā°
  myLSS.setServoID(LSS_ID);
  myLSS.reset();
  delay(1500);
  myLSS.hold();
  myLSS.moveT(0,500);
  myLSS.setOriginOffset(300);
  myLSS.setGyre(LSS_GyreCounterClockwise);

  delay(500);
  PrintServoStuff();
...
void PrintServoStuff() {
  Serial.print("Pos:");
  Serial.print(myLSS.getPosition(), DEC);
  Serial.print(" Comm Status:");
  Serial.print(myLSS.getLastCommStatus(), DEC);
  Serial.print("\tO:");
  Serial.print(myLSS.getOriginOffset(), DEC);
  Serial.print(":");
  Serial.print(myLSS.getOriginOffset(LSS_QueryConfig), DEC);
  Serial.print("\tG:");
  Serial.print(myLSS.getGyre(), DEC);
  Serial.print(":");
  Serial.print(myLSS.getGyre(LSS_QueryConfig), DEC);
  Serial.print("\tEMC:");
  Serial.print(myLSS.getIsMotionControlEnabled(), DEC);
  //Serial.print(":");
  //Serial.print(myLSS.getIsMotionControlEnabled(LSS_QueryConfig), DEC);
  Serial.print("\tFPC:");
  Serial.print(myLSS.getFilterPositionCount(), DEC);
  Serial.print(":");
  Serial.print(myLSS.getFilterPositionCount(LSS_QueryConfig), DEC);
  Serial.print("\tAS:");
  Serial.print(myLSS.getAngularStiffness(), DEC);
  Serial.print(":");
  Serial.print(myLSS.getAngularStiffness(LSS_QueryConfig), DEC);
  Serial.print("\tAH:");
  Serial.print(myLSS.getAngularHoldingStiffness(), DEC);
  Serial.print(":");
  Serial.print(myLSS.getAngularHoldingStiffness(LSS_QueryConfig), DEC);
  Serial.print("\tAR:");
  Serial.print(myLSS.getAngularRange(), DEC);
  Serial.print(":");
  Serial.println(myLSS.getAngularRange(LSS_QueryConfig), DEC);
}

Debug output:

Pos:302 Comm Status:1	O:-300:0	G:-1:-1	EMC:1	FPC:5:5	AS:0:0	AH:2:2	AR:1800:1800

So you can see that setting the Gyre to -1, updated the offset to negate it. Probably need to document this!
Also curious about the position 302ā€¦

Also again the GYRE looks like reading both config and session return the updated valueā€¦

Quick update: to setting the configuration information, in the last two posts. Fixed my issue, by making sure to update GYRE first then update the offsets, Thanks @cyberpalin for helping confirm this.

Suggestions from this:

Maybe something in your documents should mention, that setting the Gyre may impact other things like offsets.
Likewise maybe should document on how setting the offsets impacts the positionā€¦ Things like:
Set servo position to 300, then set offset to 200. Does the servo move when I set the offset? (NO), If I query the position, what should I expect to get back? (probably something near 100?)

Firmware: I think the processing of the GYRE has problems. Setting the Session value, if you then query back the config shows the session value. It also shows it in the Session return value as wellā€¦ If you reset the servo, the servo is left with the last session value, not the EEPROM version. Note: I know when you set the session value the EEPROM is not changed, as if you power it off and back on, it has the old value.

1 Like

Alcon
Please see @kurte next message on status of Phoenix code :slight_smile:

Over the last few days, @cyberPalin and myself, have worked to integrate the changes made for the new beta firmware for the servos.
We believe we have the walking reasonably. Also we finished implementing the Servo offsets code, which hopefully makes reasonably easy for everyone to setup a configuration that works. This includes both the Servo Offsets as well as the servo rotation directions.

There is more information about this in the new Readme.md files that @cyberPalin created.

This Readme has additional information, like how to pair the joysticks as well as what different buttons and Axis on the PS4 currently do.

We have also updated the LSS_PhoenixUSBJoystick.ino sketch in all three github projects (my LSS_Test_Sketches,
Mikes (mjs513) LSS_Phoenix_BT, and the SES-V2-Hexapod_beta)

Note: This updated code probably will require an updated LSS_Library code.
These changes which are part of the Pull Request: Add new static method: void setReadTimeouts(long start_response_timeout, long msg_char_timeout) by KurtE Ā· Pull Request #6 Ā· Lynxmotion/LSS_Library_Arduino Ā· GitHub , which have not been merged yet.

So you can either grab them from my Fork/Branch or from the SES Beta project, copy I put up on the beta project: https://github.com/lynxmotionbeta/SES-V2-Hexapod-Beta/tree/main/libraries/LSS_Library_Arduino

With all of this I think we accomplished my main goal for this project. Which was to enable the main portions of the Phoenix code to reasonably function on the LSS servos as configured with your SES2 system.

So we will probably call it mission accomplished for now and divert back to our other projects. Some of these will include working on the
USBHost library to so support some PS4 clones as well as working with @zenta newer floating point code base and integrate it with our PS4 code.

I expect our progress will be a lot quicker with both of us having a full setup.

We will continue to monitor the progress you make and will try to answer any question you have or help with any issue you run into.
And we will try to merge in any new stuff as time and interest permitsā€¦

2 Likes