Hybrid Terrain adaption

Hi guys,

I finished the Query sub route using the fast binary command set for the SSC. The binary version is not only faster but it is also more precise since it returns 2 bytes. The original Query command only returned one byte so the center position of the servo returned “150” instead of “1500”. So this is solved with the binary version.

Here is the code:

[code];--------------------------------------------------------------------
;[QUERY SERVO POSITION] Queries the current position of the servos
; Using the SSC binary bit mask
;- byte 1 = (binary) 1 0 1 1 s3 s2 s1 s0
;- byte 2 = (binary) 0 s10 s9 s8 s7 s6 s5 s4
;- byte 3 = (binary) 0 s17 s16 s15 s14 s13 s12 s11
;- byte 4 = (binary) 0 s24 s23 s22 s21 s20 s19 s18
;- byte 5 = (binary) 0 s31 s30 s29 s28 s27 s26 s25
TA_CoxaPWM var word(6) ;SSC Read value for coxa PWM
TA_FemurPWM var word(6) ;SSC Read value for femur PWM
TA_TibiaPWM var word(6) ;SSC Read value for tibia PWM
QueryServoPositions:

; Need to query servos like defined it the config file
; Servos bitmask byte
; Command - 2, 1, 0 1011-0111 0xB7
; 10, 9, 8 - 6, 5, 4 0111-0111 0x77
; 17, 16 0110-0000 0x60
; 24, 22, 21, 20, 18 0101-1101 0x5D
; 26, 25 0000-0011 0x03
; binary command is always 5 bytes so no needed
serout cSSC_OUT, cSSC_BAUD, [0xB7, 0x77, 0x60, 0x5D, 0x03]

;read pwm inputs, 2 bytes per servo. Order from lowest pin to highest pin.
serin cSSC_IN, cSSC_BAUD, [TA_TibiaPWM(0).highbyte, TA_TibiaPWM(0).lowbyte, TA_FemurPWM(0).highbyte, TA_FemurPWM(0).lowbyte, TA_CoxaPWM(0).highbyte, TA_CoxaPWM(0).lowbyte |
,TA_TibiaPWM(1).highbyte, TA_TibiaPWM(1).lowbyte, TA_FemurPWM(1).highbyte, TA_FemurPWM(1).lowbyte, TA_CoxaPWM(1).highbyte, TA_CoxaPWM(1).lowbyte |
,TA_TibiaPWM(2).highbyte, TA_TibiaPWM(2).lowbyte, TA_FemurPWM(2).highbyte, TA_FemurPWM(2).lowbyte, TA_CoxaPWM(2).highbyte, TA_CoxaPWM(2).lowbyte |
,TA_TibiaPWM(3).highbyte, TA_TibiaPWM(3).lowbyte, TA_FemurPWM(3).highbyte, TA_FemurPWM(3).lowbyte, TA_CoxaPWM(3).highbyte, TA_CoxaPWM(3).lowbyte |
,TA_TibiaPWM(4).highbyte, TA_TibiaPWM(4).lowbyte, TA_FemurPWM(4).highbyte, TA_FemurPWM(4).lowbyte, TA_CoxaPWM(4).highbyte, TA_CoxaPWM(4).lowbyte |
,TA_TibiaPWM(5).highbyte, TA_TibiaPWM(5).lowbyte, TA_FemurPWM(5).highbyte, TA_FemurPWM(5).lowbyte, TA_CoxaPWM(5).highbyte, TA_CoxaPWM(5).lowbyte]
return
;--------------------------------------------------------------------[/code]
Xan

Hi Xan!

This looks very interesting and it looks like you’ve had some “quality time”. I hope to try this out too one time. Thanks for sharing! :smiley:

Looks great.

It has been awhile since I played with the TA type code. Back then I had code some basic code to do some experiments. What I was curious about was which would give me better approximation of where the leg servos were when the contact happened. Asking the SSC-32 about it. This took the time to respond to the contact happening, plus the time to issue the command and then for it to respond. Or to approximate the position, by knowing when we issued the last command, where the servo was at that time, where the servo was moving to and how long the command was supposed to take and when the interrupt happened. My last set of code for this included:

[code]

;--------------------------------------------------------------------
;[ComputeFKYA] Compute FK for Y given the Femur and Tibia Angles in
; our coordinate system

#ifdef ENABLE_TA
; first try at figuring out FK for Y
FKYA var sword
FEA1 var sword
TEA1 var sword
FKY var sword
ComputeFKYA[FEA1, TEA1]:
gosub GetSinCos[900-FEA1]
FKY = (cos4 * cFemurLength)/10000 ; Sin or Cos - ???
gosub GetSinCos(900-FEA1)+(TEA1-900)]
FKY = FKY + (cos4*cTibiaLength)/10000 ; Double check these…
return FKY

FES1 var word
TES1 var word
FYKSS var sword ; do we need to invert the value
ComputeFKYS[FES1, TES1, FYKSS]
gosub ComputeFKYA(((FES1-650)*1059)/1000-900)*FYKSS, (((TES1-650)*1059)/1000-900)*FYKSS], FKY
return FKY

WKPINTTABLE bytetable WKPINT_0, WKPINT_1, WKPINT_2, WKPINT_3, WKPINT_4, WKPINT_5

#endif

'=====================================================

=======================================

’ Handle the WKPINT interrupt - This happens when a leg is moving down and the contract switch is
’ triggered.
#ifdef ENABLE_TA

_bWhichWKP var byte ’ Which WKP happened.
_lTimerWKP var long ’ Time when the WKP happened
_wDeltaTimeWKP var word ’ Delta time between start of command and when the WKP happened
_wWKPFemur var word ’ Guess for Femur
_wWKPTibia var word
_wFEMFromSSC var word
_wTIBFromSSC var word
_FKYFS var sword
_lSSCMask var long
_wFEMFromSSC2 var word
_wTIBFromSSC2 var word
_FKYFS2 var sword

Handle_WKP0:
_bWhichWKP = 0
disable WKPINT_0 ; only interrupt once per leg…
goto Handle_WKP

Handle_WKP1:
_bWhichWKP = 1
disable WKPINT_1 ; only interrupt once per leg…
goto Handle_WKP

Handle_WKP2:
_bWhichWKP = 2
disable WKPINT_2 ; only interrupt once per leg…
goto Handle_WKP

Handle_WKP3:
_bWhichWKP = 3
disable WKPINT_3 ; only interrupt once per leg…
goto Handle_WKP

Handle_WKP4:
_bWhichWKP = 4
disable WKPINT_4 ; only interrupt once per leg…
goto Handle_WKP

Handle_WKP5:
disable WKPINT_5 ; only interrupt once per leg…
_bWhichWKP = 5

Handle_WKP:
; Get the current time - interrupts not enabled so need to fix if a rollover happens
enable
gosub GetCurrentTime], _lTimerWKP

' Pass 1 lets see where we think the Y is by a few different methods... 
_wDeltaTimeWKP = ((_lTimerWKP-lTimerStart) * WTIMERTICSPERMSMUL) / WTIMERTICSPERMSDIV 

' Stop all servos...
disable	' let the serouts work
serout cSSC_OUT, cSSC_BAUD, [0xA2]		; Stop command...

' BUGBUG: using 38400 right now so can use serin/serout...
_wFEMFromSSC = 0
_wTIBFromSSC = 0
serout cSSC_OUT, cSSC_BAUD, "QP", dec cFemurPin(_bWhichWKP), "QP", dec cTibiaPin(_bWhichWKP),13] 
serin cSSC_IN, cSSC_BAUD, 10000, _HWKP_TO, [_wFEMFromSSC.lowbyte, _wTIBFromSSC.lowbyte]

_HWKP_TO:
_wFEMFromSSC = _wFEMFromSSC * 10
_wTIBFromSSC = _wTIBFromSSC * 10
enable
; try bitmask way
disable
_lSSCMask = (1<<cFemurPin(_bWhichWKP))| (1 << cTibiaPin(_bWhichWKP)) ; generate the mask
serout cSSC_Out, cSSC_BAUD, [0xB0|(_lSSCMask & 0xf),(_lSSCMask>>4) & 0x7f, (_lSSCMask>>11) & 0x7f,(_lSSCMask>>18) & 0x7f,(_lSSCMask>>25) & 0x7f]
serin cSSC_In, cSSC_BAUD, 10000, _HWKP_TO2,[_wFEMFromSSC2.highbyte, _wFEMFromSSC2.lowbyte,_wTIBFromSSC2.highbyte, _wTIBFromSSC2.lowbyte];
_HWKP_TO2:

if prevssctime then

	_wWKPFemur = awSSCFemurAnglePrev(_bWhichWKP) + |
		((awSSCFemurAngle(_bWhichWKP)-awSSCFemurAnglePrev(_bWhichWKP)) * _wDeltaTimeWKP) / PrevSSCTime
	_wWKPTibia = awSSCTibiaAnglePrev(_bWhichWKP) + |
		((awSSCTibiaAnglePrev(_bWhichWKP)-awSSCTibiaAngle(_bWhichWKP)) * _wDeltaTimeWKP) / PrevSSCTime
		
	if _bWhichWKP < 3 then
		gosub ComputeFKYS[_wFEMFromSSC, _wTIBFromSSC, -1], _FKYFS
		gosub ComputeFKYS[_wFEMFromSSC2, _wTIBFromSSC2, -1], _FKYFS2
		gosub ComputeFKYS[_wWKPFemur, _wWKPTibia, -1]
	else
		gosub ComputeFKYS[_wTIBFromSSC, _wTIBFromSSC, 1], _FKYFS
		gosub ComputeFKYS[_wTIBFromSSC2, _wTIBFromSSC2, 1], _FKYFS2
		gosub ComputeFKYS[_wWKPFemur, _wWKPTibia, 1]
	endif

#ifdef HSP_DEBUG
hserout HSP_DEBUG, [13, “WC: “, dec _bWhichWKP, " “, dec awSSCFemurAnglePrev(_bWhichWKP) ,”-”,dec awSSCFemurAngle(_bWhichWKP),|
" “, dec awSSCTibiaAnglePrev(_bWhichWKP), “-”, dec awSSCTibiaAngle(_bWhichWKP), |
" T:”, dec _wDeltaTimeWKP, “:”, dec prevssctime, |
“(”, dec _wWKPFemur,”,",dec _wWKPTibia,"=",sdec FKY,")"]
hserout HSP_DEBUG, “{”, dec _wFEMFromSSC, “,”,dec _wTIBFromSSC, “=”, sdec _FKYFS,"}","<", dec _wFEMFromSSC2, “,”,dec _wTIBFromSSC2, “=”, sdec _FKYFS2,">",13];
#else
disable
serout s_out, i9600, “WC: “, dec _bWhichWKP, “(”, dec _wWKPFemur,”,”,dec _wWKPTibia,"=",sdec FKY,")",13];
enable
#endif
endif
resume
#endif [/code]
This code is where I found the offset issue with the SSC-32. Should try it again, now that the bug was fixed. Also need to try on a hard surface to see if I can get better triggering with the SSC-32. If the approximation code looks at all promising, I may change the actual interrupt code to be in ASM, where it captures which leg and the time, and then probably does the rest in basic. Could be another triggered interrupt or could have the code check a state variable at several key points in the program…

I am also glad that you are getting some time to work on this again and can not wait to see how you process the leg information when contact is made.

Great work!
Kurt

Hi Kurt,

sounds interesting. Calculating position from taking a point in time. So if it takes 200mS to get from point A to point B and the tars sensor get tripped after 50mS this will say that it traveled 25% of it’s movement. Interesting theory, I’m curious about how accurate that will be. This will remove the need to do FK btw. And it will be easier to adjust by an overshoot as well. Just take 23% or so.

Xan

Hi guys,

With the T(A)-Hex coming together pretty fast and Kurt willing to join me on this project I want to share some thoughts and work I did on this.

[size=150]TA Methods[/size]
The following methods came up to my path. There might be more or better ones. Feel free to fill me in.
1. Small steps
I won’t go in to detail on this one since I’ve already demonstrated this in a video on youtube and talked about this a lot in my previous posts. It is pretty easy since there is no need to do FK for the legs and IK for the body. But it is very slow.
2. Stop command
Like explained earlier, the leg goes down until it hits an object (ground). The BAP will see this end sends the stop all command to the SSC to stop further movement. Then the servo positions will be queried. The positions of the legs and body will be determined using Forward Kinematics for the legs and Inverse Kinematics for the Body. With the new known position the gait can move to his next step.
3. Time measurement
I read this idea from Kurt on the forum. The idea is that once the leg is going down. The full sequence should take 200mS to travel from position A(0,0,0) to position B(12,20,40). If the leg hits the ground after 150mS it means that it only took 3/4 of the total time. This should mean that the distance traveled is also 3/4 of the total distance. The final position will be at (4,15,30).

[size=150]Route to follow[/size]
With the 3 TA methods laid out I want to talk about which method would be the best.
Method 1 is shown in this youtube video. As I said, it is to slow. It sure can be improved with the faster binary command set and the full speed connection. It even can be increased a bit by using the ARC since there is no communication between the 2 boards. But still, the hex should take really small steps to decrease the amount of overshoot and accuracy. Method 3 shouldn’t be to hard to implement. But I’ve got kinda doubts about how accurate it will be. And I kinda have a strange feeling about determine position by measuring time. This would only work if we have the exact time of the movement and the movement should be fully linear. Maybe the errors will be small enough to get away with it though. Method 2 is the hardest of 3 but also the most accurate, has almost no overshoot and is pretty fast. The reason why this method is so hard to accomplish is that once the leg touches the ground all servos stop and a lot of positions are lost! it is possible to query the servo angles but we still need to calculate so see where the leg(s) and body really are. This doubles the calculations needed.

I’ve been currently working to method 3 since I think this is the most professional way to go…

[size=150]Balance Calculations are the key to success[/size]
I’m convinced that Zenta’s Balance Calculations are the key to success then wit comes to Terrain Adaption. As most of you may know the balance calculation ensures that the body always stays relative to the position of the 6 tars. This is not only in all positions (x,y,z) but also in all angles (pitch, yaw, roll). Since TA will make our Gait engine into a full closed-loop system needs to take care of the environment. This means that the origin = ground will change from now on. To show this I made a small drawing.

img713.imageshack.us/img713/3163/functionbalancemode.jpg

In the first set of drawings you can see that the origin will stay put when the hex crawls over an object. Even if we increase the height Y it will still become a problem since it isn’t possible to put a infinite large number in a word :wink:

With the balance calculations turned on, the origin will move with the hex. This makes the height Y always the relatively height between the tars and the body. Not the height from the origin starting point to the body.

This is why the balance calculations is the key to success

Next up I will talk more into detail about the needed calculations for method 3 and how to implement in the current phoenix code.

Very good summary of the methods Xan! :smiley:

Method 3 sure sounds interesting since you always know (almost) exactly where you are and don’t have to do any FK or body IK. I believe one big challenge is the gait engine too, since the positions always will be different. Some sort of a dynamic gait based upon the balance mode might be a way to go.

Looking forward to your next “step”! :wink:

Method 2 seems the most practical way to go. Method 3 will be inaccurate at best and probably a waste of time. Method 1 looks interesting, but the methodology (as best as I have followed it) appears to be combersome. In the fifth post in this discussion (~1.5 years ago) I gave a quick statement of what I’ve seen what can be done with an ssc-32. With the current version of the ssc-32, the “all servos stop” does not have to be used. Individual servos can be stopped when they make ground contact. I can see moving three legs in the down direction at the same time, stopping each as it made ground contact. The positions of the three can be obtained from the ssc-32 to evaluate against the current down positions of all legs to determine the general position of the bot body in relation to the general ground position. As I’ve mentioned in the past ~2.5 years on the A topic, it may be good to start with getting a basic bot walking, then develop in all the extras.

I think it will be a lot of fun to get this up and running and to see what techniques work and don’t work. As Xan mentioned there are issues with all of thd different techniques and it may easily turn out the best solution is some form of combination between the different ones.

#1 - Is too slow for normal type robot operation. I think this might be interesting if we for example had double sensor per leg. With for example some form of Sharp IR sensor that detects how close we are getting to something. You run at full speed until one of these sensors says you are about to hit something and then you scale down the movements to actually find the object…

#2 - Is interesting, but for sure you will always overshoot by some. That is by the time the switch triggers, the foot is on the ground, so much time will delay before the code (interrupt or the like happens). Then you have two choices. You can stop a servo with the STOP n command. Not sure if it handles: STOP n n n or not. But if it does than it will probably take something like: STOPnn nn nn or 13 characters at 115200 this will take something like 1.1ms to send out, which the servos will keep on moving during this time.

Alternatively we can issue the new binary stop command, but I believe this stops all servos, which only takes 1 byte so is reasonably fast. But then what do we do after this? If lets say the front right leg hits the ground about half way through 1 step of a gait what do we do next and all legs are stopped. What next. My assumption is that we reissue the last move for the other N legs that have not hit something, with a guesstimate of the time remaining in that last step… What about the leg that hit. Could not issue move for these servos, or we query it’s position and reissue it, or could try to fudge it with the idea of we were delayed by time N and move it back to where we think it should have hit. Do we leave the servos in the position where they hit, or do we calculate what the servos should be at for the position the foot currently is at? …

#3 - Is the approach I started to play with as I think it has some potential. It does have the problem of knowing exact timings, which may turn on not to work well. But as I mentioned before we may have the same issues in #2. Also are the moves linear or not? May not be, but we may be able to give reasonable guesses. That is we can also do our own ramping in the guess. As for computing power to do this, it may depend on which way we compute things. Example: if we are moving from (X1, Y1, Z1) to (X2, Y2, Z2) in time Tm and we hit at Th, we may compute this by percentages of the differences of X1 to X2, which may take some time and the like, or we could know that the Servo Pulses for the three servos are going from P1 to P2, which we can do a simple linear approximation for where the P is when the hit happened. The computation after this point would be the same as #2 as in #2 we would be doing a query command, for the three servos to get the actual positions… Again not sure it will work, but I think it is worth a try.

Regardless of what approach we take, I do have some concerns about how we organize the code. With the current code (without TA), in order to get as smooth as possible gaits, with as little as possible overhead, the code works sort of like:

Step 1: Get the time of when the Last SSC command commit happened: Tlast
Step 2: compute the next servo positions.
Step 3: Issue as much of the SSC command as possible with out committing it.
Step 4: Sleep appropriate time: - (Tcurrent - tLast)
Step 5: Issue the commit to SSC (1 byte if non binary, 3 bytes if binary…)
go back to step 1…

Above is simplified, like there is a step 0, that goes out to talk to your controller and the like. But there are issues with the above with TA. That is suppose we are in Step 4 when the leg hits, what happens with all of the data we already sent to the SSC-32? Can we cancel it? If we issue new data for all of the servos that would probably work… Note, even if we did away with step 3 like the original code and had step 5 issues the complete SSC-32 command, we still have issues of suppose we have issued the servo data for 4 of the legs when the leg hit happens…

As Xan mentioned, this would probably be simplified if we did this all on an Arc32 as we are in complete control here and you don’t have the serial delays in the mix…

That is all for now. Should be lots of fun!!! :smiley:

Kurt

I forgot to mention in the previous post, that if we use an Arc32 for this, it more or less makes #2 and #3 the same. That is we no longer have to keep our own idea of where we think the servos are, we simply do an HSERVOPOS for the 3/4 servos of that leg and then respond, with either simply setting those servos to stay where they are or back up slightly… We no longer have the serial delays involved, which is what #3 is trying to eliminate.

Personally I think Arc32 would be the best approach here… Should work for 3/4 DOF assume 4 so 24 servos, plus 6 IO pins for feedback. We hang a PS2 off of the 4 Aux pins, plus optionally XBee on second UART. The only issue would be if you wish to do an RC version, with 6 IO pins… I know there are hacks for Hitec and some other receivers to use one pin (did on mine to test), but wonder if we could do with spectrum as well. If so would be less overhead as welll…

Just a thought
Kurt

Just thinking out loud here, but if TE is to advance on the SSC-32, it would be nice to incorporate the foot sense in it’s code. I know, there is no concept of a “leg” in the SSC-32, I.E., no specific groupings of servos or tripods. This would get the “intelligence” of moving a leg down to where the critical timing is. No simple task!

Otherwise, as mentioned, the ARC-32 might be the (interim?) answer…

Alan KM6VV

… and timing is very easy in ARC32 using HSERVOTIME

Hi Zoomkat,

I do not totally agree with you on this part. Like said in my previous post, balance calc is the key to this. With balance mode on the body will always move relatively to all 6 legs. So if one leg goes down, the body will follow that leg. This means that ALL servos move with every step. So it is not possible to only stop a single leg since the body will still move downwards. I hope this makes sense.

Oh yes, I totally agree on this. There are a lot of issues to solve once we’ve got the basic steps to work. Think about what to do if the gap is to deep and the leg becomes overstreched. etc.

Thanks for your input.

Xan

Hi Kurt,

I’m my previous post I described how the balance calculations are involved in this process. Since the body moves with the leg that is going down it is not possible to only stop the single leg. We have to stop all servos at all time. To demonstrate this you could try the single leg control on your hex with balance mode on. You will see that if the leg goes down the body will follow as well.

My idea is to use the binary stop all command. Then use the binary query command to only query the needed bytes for the 24 servos. All @115200 offcourse.

I did some tests with the stop command to test the overshoot created by the mechanical sensor and delay in software. I created a small program which lowered the leg until the sensor was hit. Then it send the stop command. The overshoot was there, but not that big. Off course it got bigger once the speed went up but It’s a good thing to repeat this test once the T-Hex is in. I also hooked up the logic analyzer but I can’t remember the values. I really should start writing more down. :confused:

Good question. I was planning on going into further detail later but lets talk about this now.

Let’s say we start with the most TA compatible gait.

If leg A is moving down from position 2 to position 3. At the same time a leg (say B) is moving from position 4 to 5. If leg A hits the ground at half hight all servos stop. This will also mean that leg B is half way. But let B is on the ground and that position is static at that time. Then we calculate so we know where all legs are. (I get back on that) Once all legs are on a known position again we can finish the rest of the move horizontal. This way ONLY the vertical movement stopped and the horizontal movement will be finished.

When you study the gait you will see that ALL gaits will have the same pattern that we can use as reference. In each gait the hex will have 3 legs on the ground that form a triangle. This triangle is always formed by left front, left rear and middle right OR right front, right rear or left middle. Since the legs are always on the ground we can calculate from the static tars to the body. From the body we can calculate to the unknown leg positions. I’m planning an detailed post on this including the needed Math.

I agree, this sure has some potential. I’m not throwing this idea from the table we just have to see what the best method would be. I really have to think about his one a bit more.

I do not agree on this part. In #2 we stop the servos and query the servo angles. We need to do FK to determain the position for each joint relatively to the origin. In method #3 we can do a approximation to the new position which lies somewhere in the path between point P1 and P2. This approximation should directly give us a position. So there is no need to do FK.

I’ve made a flow diagram that shows where to do what in the code. I think it should work for our first test setup. This is also the flowchart of the last program I’ve send to you kurt. But it isn’t bug free :wink:

img40.imageshack.us/img40/8287/softwareflowdiagram.jpg
The red part shows the newly added parts. It would be great if you could study it and see if I forgot something.

Note: I used a masked byte for the flag. This makes it possible to have more legs which are going down at once. I suggest we only use a simple gait that only has one leg going down at the time but with the masked byte we could get this to work with a tripodgait in the future.

About the ARC vs SSC/BAP: the ARC has a big plus on his side that we don’t have to send commands down and forward the serial connection which spares us time. But with the send/receive part already done it is fine by me to go with either setups. The time it takes to send/receive the data only takes a bit more time that we could improve once we’ve got a working prototype.

That’s all for now.

Xan

Hi Xan,

Looks like you have a good handle on this stuff! Can not wait to get my hands on to it and see how well it is working. I will wait until then to comment much on the code flow until then.

It will be good to retry this type of code out again and see the different results. This will also help me to optimize the interrupt handlers and try out different approaches. As you mentioned we will should try to document this.

You are probably correct, that you would not need to do the FK. That is my initial thought as well. That is if we are moving from point (X,Y,Z) of lets say (100, 100, 100) to (500, 500, 500) in 100 units of time and we know we made contact in 50 units of time. We can guess that contact was made at (X, Y, Z) of (300, 300, 300). Likewise I would expect that the servo pulse widths for the Tars, Tibia, and coxa servos would each have 50% of their delta from the starting to ending pulse widths.

What I was wondering is that if I did a IK for the position (300, 300, 300), would the IK choose the same servo angles(pulse widths) of where we stopped, or might it choose a different solution. If so does that matter?

My initial thoughts on this was, yeah it might choose a different solution, but it will probably correct this when it issues a new move…
So I am hoping that this will be a non-issue. Not sure if I am making any sense here.

That is all for now.
Kurt

Has anybody tested sending the stop command in series to three servos that are moving to check the response time? I would think that due to the flex in the legs that undershoot might be the issue. Below is the simple aluminum foil/paper clip test I did ~2 years ago checking the position every 20ms at 9600bps. If you can shorten this time then better response would be expected. As to the balancing, a simple approach of averaging the positions of the legs on a side and comparing that value to a desired median position band would be a simple place to start. If the the average is outside the band, then add/subtract the difference from the center position of the median band and increase/decrease the positions of all the legs on that side the amount of the difference to reparallel that side with the assumed ground surface. And once again for those on a budget or those that don’t want to wait for the ground switches, the critical testing can be done using aluminum foil.

youtube.com/watch?v=3zQalB0bfNE

in my test
viewtopic.php?p=70612#p70612
using WKPINT it overshoot by apx. 1mm, but the error will be more if speed of HSERVO is more than servospeed

How maxed out is the AtomPro in processing?

As for the terrain adaption have you ever thought about using a Gyro mounted flat on the bot and working some code around that?
I had picked up a Gyro at sparkfun and wired it up to an LM315 I think it was made a nice little package that plugs into the botboard. I have some ideas for simple gyro code as I had written some to figure out exactly how a gyro worked electronically, so it appears to me you just sample data and run it though constant loops and monitor changes… so with that said, it seems like a cpu/io intensive task… I’m all ears if I’m wrong.

It would be cool if you could use the AtomPro with the DynaMixle servos since they are all serial and provide feedback, the phoenix would probably be 4x more money but HEY you could have it carry your groceries!

Looking cool so far guys.

–Aaron

Could probably implement PID loops to keep the body in the horizontal plane? Corrections would attempt to keep body level.

Alan KM6VV

Yeah from the diagrams above it looks like having the body level is the incorrect method, but then again I guess it depends on what your trying to accomplish… Haha I bet Zenta would make another A pod with a coaster on its back and walk over books while keeping the can of soda level on its back :stuck_out_tongue:

terrain adaptive quadruped robot. very cool. 8)