I have been talking about this on the Conversion to BotBoardDuino thread, but thought I would continue it on it’s own thread.
I am working on cleaning up my port of the Phoenix code to the Arduino and trying to reduce the number of global variables… Ways I am doing it. Earlier I introduced a ServoDriver class, that I have two implementions of (like we had in basic). But the old factoring was such that for example, we did an UpdateServoDriver and a Commit. But these factorings were such that the servo driver had to know about the arrays of positions, the Move Time, etc. So I updated the class, to have a start, then had the loop through the legs in the main code, which called off to the servo driver per leg with the leg number and angles in degrees(1) and then a commit with the move time. So I was able to remove all of those arrays from the global space. Also move the pin number arrays to the Servo driver file and removed those from being global. Likewise added more methods to control the GP sequence code to the ServoDriver class and removed the globals associated with that as well.
Note: So far I have only done this with my stripped down BotBoardDuino Chr-3 SSC-32 PS2 version that I split off Thursday and removed most of the debug code and the like.
Next will be to define a Controller Class and convert the PS2 code to that. As part of that will try to move most of the remaining globals into this class, with either the variables being public or some quick and dirty functions (probably inline) for the main code to get the settings from.
Once that is done, I will go back to my main Phoenix code folder and incorporate these changes into the (without SSC-32 driver, plus the XBee Control class…_).
If anyone wishes to look/play with the intermediate version, I have uploaded it here. Note: I am using my version of the PS2x code that I uploaded a zip file of it in the other thread. Also it helps to keep a copy of this somewhere, on the off chance my disk goes…
What I am trying to say, is I hate global variables! With Bap basic for example, you need a variable, lets call it LegIndex and use it in the main code. You call off to something, that also wishes to enumerate the Legs and chooses to use a variable names LegIndex. Well it just stamped on the usage of the one who called it. So in C/C++ (and some basics like VB), you can scope a variable to a function, or make it a member of a class… So you reduce these types of problems.
I have already done it with the ServoController class, which I am happier with. I have also created an InputControl class, which I moved the PS2 code to. But now I am trying to figure out a reasonable factoring of these variables. That is the InputControl class manipulates several variables, like: BodyPosX1/Y/Z, BodyRotX1/Y/Z, …)
The question in my mind is does it make reasonable sense to say that these variables are members of the InputControl Class or should they be part of something like a HexRobotState class that is either referenced by the InputControl class either by knowing about the 1 global object or that the state is passed in… The easiest is to just make them part of the InputControl class and be done with it. Assuming I go this ways, then could choose to simply expose these variables as public variables or could make methods on the class for the main code to call to get the information… Could also go hog wild and create structures for 3D coordinates. so instead of referencing things Like BodyPosX1, BodyPosY1, we would maybe do something like BodyPos1.x…
Again depends on how far I want to take it. But for now should get something out there such that you can sell a Hex with the BotBoardDuino…
I’ve never heard of a compiled language that doesn’t have variable scope… never realized basic was limited this way. All those variables that you only need once must really hog some serious code space.
FYI - I have not done a complete job of refactoring yet. But if you wish to play with some of the current stuff, I uploaded a zip file of the current stuff…
It is set up for CHR-3, with PS2, SSC-32 on BBDuino. I have SSC-32 connected to digital pins 12 and 13, but this version can attempt to do it as well on 0,1 (USART). But you will have to disable the debug and other support for Serial… I was able to run on this fine, but doing downloads of code failed in the verify stage… So for my stuff I use Software Serial…
I loaded up the code on a AH3-R and the only thing that seems off to us is that when you turn on the servos they max out the vertical hip and things start to warm up… other than that everything seems to be working alright
Translation, the phoenix femur can go completely vertical, but the CH3-R can not. So he needs to know the best way to fix the servos from crashing at initial start up position. Is this done by changing some limits somewhere, or is there an initial start up position value that needs to be changed, or both?
I have had the best luck playing around with the Initial position… #define cHexInitXZ 80 #define CHexInitXZCos60 40 // COS(60) = .5 #define CHexInitXZSin60 69 // sin(60) = .866 #define CHexInitY 80 //30
If you are using an AHR… Then the leg information needs to be updated: My guess is that:
#define cXXCoxaLength 29 // This is for CH3-R with Type 3 legs
#define cXXFemurLength 57
#define cXXTibiaLength 141
#define cXXTarsLength 85 // 4DOF only...
Should go to:
#define cXXCoxaLength 38// This is for AH3-R with Type 1 legs
#define cXXFemurLength 57
#define cXXTibiaLength 124
#define cXXTarsLength 85 // 4DOF only...
I grabbed these values from Powerpod…
As for the initial position, You will need to experiment with the values of the variables I mentioned late yesterday. I did this with the CHR. I got the X/Z values to something that looked like it worked good. Then I adjusted the Y until the body was on the ground and the legs were just touching…
The First number 80, is a guess on how far out we want each of the legs… I had to play around with different robots to get different values that work. The values (CHexInitXZCos60, and CHexInitXZSin60 are simply the Sin and Cos of 60 degrees times the first value (CHexInitXZCos60). The CHexInitY value is how far up we should init. Again done by experiments… Note: These values are more or less the same as the BAP28 type setup…
[code]cHexInitXZ con 105 ; was 105
CHexInitY con 80
cRRInitPosX con (cHexInitXZ * 0.5 + 0.5) ;Start positions of the Right Rear leg
cRRInitPosY con cHexInitY
cRRInitPosZ con (cHexInitXZ * 0.866 + 0.5)
cRMInitPosX con cHexInitXZ ;Start positions of the Right Middle leg
cRMInitPosY con cHexInitY
cRMInitPosZ con 0[/code]
But I simply did the Mult by .5 and .866 up in constants above…
The initial position isn’t what is causing the crash. The ground position is the problem. When you first press start to turn on the bot the g_BodyYOffset is set to 0 i believe. I Think this is what’s causing the crash. This should be the case with your CH3-R as well…
Sounds good, I will try it out on mine sometime… currently my CHR-3 is set up with Arduino Mega and No SSC-32… Will also look into it on my 4DOF version which I now have the Botboarduino on…
Hint: it would be nice if all of these changes were put into a Source Control System, like Source Forge or GitHub… That way we could all be able to see what changes in builds and automatically merge…
Jim asked me to jump in. So here I am, hope to be of some help. By now Kurt is already a super master in the Phoenix code. I doubt I can add much new stuff for him but who knows I might squeeze out something new!
Configuring the software for another bot sometimes seems try and error but there actually is some logic/math behind it. I think most of the stuff is already known but I’ll start at the beginning.
I don’t have the code with me right now so I need to do this from my memory…
NOTE: The global coordinate frame is an 3D frame. The hexapod is located in such a way that: X is sideways (left, right), Y is vertical (up, down), Z is (forward, backward). This need to be kept in mind at all times
Body Lengths
Fill in the correct lengths for the body and joints. All length are measured from joint to joint. Or as for the tibia, from joint to the tip (tars). For the body the lengths are measured from the centre of the body (0,0,0) to the joints. The best way to measure this is to stretch the leg totally horizontal. Then measure the lengths by keeping the measurement tool horizontal as well. This is important for the length of the coxa. The length of the coxa is measured from the hub of the servo to the heart of the other servo. Not from hub to hub since this is a diagonal length. We only want the horizontal lengths.
Init positions
The init position has 3 variables for each leg. InitPosY refer to the vertical offset between the body and the tip (tars) of the leg. If set to zero the tars should be in the middle of the body. This value should be set to let the tars rest on the ground when the hex is in the init position.
The initPosX and initPosZ refer horizontal offset between the tars and the body. X is for sideways, Z is for forward/backward. For the middle 2 legs you only need to fill in the X since the leg only needs an offset to the left and right, not to the front.
Now this is the point where the math kicks in. For a round hexapod we want the front and back angles to start at an angle of 60 deg. But we want to have the distance from the body the same as with the middle legs. So you need to use the Pythagorean theorem to take the distance from the middle leg, and transfer it to an X and Z value with the 60 deg angle.
The best way to find a good init position is to place the hex on a flat surface. Manually set the legs to the ideal init position and measure the distance from the coxa horn to the tars. Remember to only measure the horizontal length. This is your offset for the middle leg. Then calc your way to the front and back legs. The Y value is always a bit of try and error, you can measure the distance from the horn of the femur servo to the ground. Theoretical you should enter that value. But with the play in the servos and gravity pulling down on them you need to adjust it a bit.
Min/max angles
The code also contains some min and max angles for each servo. These limits are low level which mean that they only prevent the servos from running into mechanical limits and cause them to overload. The min/max angles don’t feed back any information on the IK math so overstretching will result in a strange walking bot. But that is always better than an overloaded bot
It works like this, if your servo can only go to 42 deg because it will hit a bracket once it goes any further you can set the limit to 42 deg. Once the math sends the servo to 45 deg, the angle will be limited to 43 deg and send to it’s max angle.
The way I did this is to connect the SSC to lynxTerm and check out the min and max PWM’s of each servo. I wrote them down and used excel to fast calculate the corresponding angle. Placed those values in the config file. Done
Travel distance/speed
There are 2 variables who take care of the speed of the bot. If a bot has shorter or longer legs those values should also be checked. In my explanation about how the gaits work I used a triangle to track the motion of the tars. Having the triangle in mind, the TravelDistance is the maximum distance (in mm) the leg moves over the ground (horizontal line). I’m not sure of this but as I remember it correctly it actually is from the center of the horizontal line to the front. So the horizontal line will be TravelDistance*2. If the bot has shorter legs, this value should be reduced to prevent over stretching
The travel speed is the time it takes to do one step (going from 1 to 2 in the triangle)
That’s about it. Let me know if you’ve got any questions.
We should make a tutorial for this…
PS. I totally second you Kurt, globals are horrible! Since the Arduino does support classes with there own scoped variables it is way better!
I believe many people would finding this information useful!
Good to see you around too
A side note: I just wanted to shoot in that the (now rather old) excel program PEP is also a very useful tool for testing out init positions. You can use the X,Z,Y values from the leg sections in the body&coxa sheet.
For the most part I was trying to not have to worry about it too much That is, if it worked on the BAP and I ported the code properly, it should work on the Arduino with the same, lengths, angles, inits… But sometimes I find that when I tried to merge in some of the changes from the 2.1 changes on the BAP, I may have missed a few…
Some of the hidden gotchas of porting the code includes, all math on the BAP28 is done using 32 bit math, whereas with C on the Arduino, the number of bits involved with the math depends on the size of the variables/constants involved. For example if you are adding one byte to another, the code will generate 8 bit math instructions… That is why there are lots of castings in the code, to tell the system to up-size…
Earlier on I had instrumented versions of both the BAP and Arc32 and Arduino code and would run restricted input and check the outputs of different functions to verify the code… Stripped most of that out.
Probably need to put the BotBoarduino back on the reclaimed CHR-3, to check out the changes that were Devon’s changes and to follow along with other issues. My problem is that too many fun projects to do… My version .02 of the Atmega644 boards arrive tomorrow. So will be busy soldering.
I put in the changes you did, although they are just simply startup changes. Like instead of starting off with legs such that body is resting on ground, you have the body up a ways…
I could not tell from your video where the crsahes were… Here is an updated version. Note: This has some changes in it to factor stuff…