/* ----------------------------------------------------------------- */ /* 'ZControlClass.cc' */ /* Control- Class */ /* */ /* last modified 07/04/2003 */ /* comprises methods for balancing (interruot-driven) */ /* */ /* */ /* */ /* */ /* (C) Jochen Zimmermann */ /* ----------------------------------------------------------------- */ #include "ZHeaders.h" /* //Headerfile is included by ZHeaders.h #include "ZControlClass.h" */ //Single Instance is globally created Control Control::SingleInstance; //constructor //initialises members Control::Control() { double temp[4]={0,0,0,1}; int i; measuredcog.Equals(temp,4,1); virtualcog.Equals(temp,4,1); lcog.Equals(temp,4,1); rcog.Equals(temp,4,1); roll= pitch= deltay= deltaz= lastdeltay= lastdeltaz= onebeforelastdeltay= onebeforelastdeltaz=0; proll =0.1; ppitch=proll; iroll = 1.5; ipitch=iroll; droll =0.0; dpitch=droll; for(i=0;ihold_left =hleft; this->hold_right=hright; this->load=percent_on_right_foot; if(wason) InterruptOn(); } //calculate measured centre of gravity locally for controlling LinearAlgebra Control::CalcMeasCOG(LinearAlgebra lfoot,LinearAlgebra rfoot) { int liftinfo; double temp[4]={28,0,0,1}; lcog.Equals(temp,4,1); rcog=lcog; Feet* feet=Feet::GetTheInstance(); //read liftinformation with refresh liftinfo=feet->Lifted(true); //both feet are not attached to the ground if(liftinfo!=3) { //if not lifted, read cog if(liftinfo!=1) feet->GetCOG(lcog,1,0); //retrieving left foot's values after refresh if(liftinfo!=2) feet->GetCOG(rcog,2,0); //retrieving values of right foot, no refresh feet->LoadDistribution(&temp[0],&temp[1],&temp[2],false); } else temp[1]=0.5; //calculate total measured cog lcog+=lfoot; //probalby should be moved into according if-branch rcog+=rfoot; //probalby should be moved into according if-branch measuredcog =lcog + ( (rcog-lcog)*temp[1] ); return measuredcog; } //virtual cog is calculated out of distribution and location of masses //not necessary during control loop, only for additional information //needed for slope-calculation LinearAlgebra Control::CalcVirtCOG(bool project_to_footlevel) { //vector{x,y,z,1} are the positions of the cog DenavitHartenberg link; LinearAlgebra vect; double foot= 114.75, //a foot's mass in g shank= 69.25, //a shank's mass in g thigh= 153.25, //a thigh's mass in g body= 765.50, // body's mass in g total=1440.00, //=>2*foot+2*shank+2*thigh+body vector[4]={0,0,0,0};//buffer for internal use //weights have been estimated as well as their position relative to link /**************************FEET**************************/ vector[0]=12;vector[1]= 10;vector[2]= 18;vector[3]=1; //setup vector in link coordinate system vect.Equals(vector,4,1); //transpose vector to LinearAlgebra member link.Calc(LFOOT); //calculate matrix(link->base) link*=vect; //calculate this vector relative to base coordinate system link*=(foot /total); //stretch vector by the link's wheight virtualcog=link; //add vector to total virtual cog /** **/ vector[0]=12;vector[1]=-10;vector[2]= 18;vector[3]=1; vect.Equals(vector,4,1); link.Calc(RFOOT); link*=vect; link*=(foot /total); virtualcog+=link; /*************************SHANKS*************************/ vector[0]=-15;vector[1]=0;vector[2]=-17;vector[3]=1; vect.Equals(vector,4,1); link.Calc(LSHANK); link*=vect; link*=(shank /total); virtualcog+=link; /** **/ vector[0]=-15;vector[1]=0;vector[2]= 17;vector[3]=1; vect.Equals(vector,4,1); link.Calc(RSHANK); link*=vect; link*=(shank /total); virtualcog+=link; /*************************THIGHS*************************/ vector[0]=-30;vector[1]=0;vector[2]=-17;vector[3]=1; vect.Equals(vector,4,1); link.Calc(LTHIGH); link*=vect; link*=(thigh /total); virtualcog+=link; /** **/ vector[0]=-30;vector[1]=0;vector[2]= 17;vector[3]=1; vect.Equals(vector,4,1); link.Calc(RTHIGH); link*=vect; link*=(thigh /total); virtualcog+=link; /**************************BODY**************************/ vector[0]=-60;vector[1]=0;vector[2]=-31;vector[3]=1; vect.Equals(vector,4,1); //link.Calc(BODY); //identity matrix link=vect; //then I*vect=vect link*=(body /total); virtualcog+=link; /** **/ if(project_to_footlevel) { LinearAlgebra temp; link.Calc(-LFOOT); temp=link*virtualcog; link.Calc(-RFOOT); temp+=link*virtualcog; virtualcog=temp*-0.5; } return virtualcog; } //member retrievig function LinearAlgebra Control::GetMeasCOG() { return measuredcog; } //calculate slope angles of subsurface void Control::CalcSlope(int* roll,int* pitch) { LinearAlgebra tmp; Display* lcd=Display::GetTheInstance(); double vect[4],height; CalcVirtCOG(); virtualcog.GetData(vect,4,1); height=vect[0]+28; tmp=virtualcog-measuredcog; //lcd->Print(virtualcog); //lcd->Print(measuredcog); tmp.GetData(vect,4,1); rollslope =OwnArcSin(vect[1]/(-height)); //pos rollsplope=sloped from left foot to right foot pitchslope=OwnArcSin(vect[2]/(-height)); //pos pitchsplope=uphill *roll=rollslope; *pitch=pitchslope; } //retrieve member void Control::GetSlope(int* roll,int* pitch) { *roll=rollslope; *pitch=pitchslope; } //local arc sine using 1°-resoluted look-up table int Control::OwnArcSin(double val) { int i=0,sign=1; if(val<0) sign=-1; val*=sign; if(val> 1) return sign*90; while(ownsin[i]89) return -100; if(angle<0) return ownsin[-angle]; return ownsin[angle]; } //member retrieving LinearAlgebra Control::GetVirtCOG() { return virtualcog; } //member retrieving LinearAlgebra Control::GetLeftCOG () { return lcog; } //member retrieving LinearAlgebra Control::GetRightCOG() { return rcog; } //central controller, running in interrupt if kicked so void Control::Balance() { /*This function represents the whole control loop running only one cycle: Input represents the desired position of the feet. Output says wether servos have been driven or not. It reads in 'CalcMeasCOG()' the values of the sensors, preprocesses them to one central central cog, applies a 'cut-off'-low-pass filter to the values, calculates the forward control differences with a digital PID- Algorithm, deals with the different generations of control errors, controls servo-movements, and stores integral and differential parts of these. To close the control loop and run it repeatedly, this fuction has to be implemented in a loop itself, respectively an interrupt. */ LinearAlgebra hold_centre,delta; Servo* servo=Servo::GetTheInstance(); bool drive=false; int i; double temp[4]= {0,0,0,1}, dbw, lowpass; //refresh measured COG CalcMeasCOG(hold_left,hold_right); //calculte desired value hold_centre=hold_left+((hold_right-hold_left)*load); //calculate control error delta=hold_centre-measuredcog; //extract relevant data delta.GetData(temp,4,1); deltay=temp[1]; deltaz=temp[2]; // //filtering out too small changes // //this function is just for steady standing issues to // //minimize servo movements and thereby save energy // //as long as the filter is not in use, comment the code // //to save computation time dbw=0; //filter width if(deltay-dbw) deltay=0; if(deltaz-dbw) deltaz=0; //PID- Control Parameters //proportional amplification of control error proll =0.01; ppitch=proll; //iroll=T/Tn integral parameter should >1 iroll = 2.0; //ipitch=T/Tn ipitch=iroll; //droll=Tv/T differential parameter (differential amplification not used by now) droll =0.0; //dpitch=Tv/T dpitch=droll; //calculate set value with PID control algorithm acc. to Lutz&Wendt: Taschenbuch der Regelungstechnik, 4.,korrigierte Auflage 2002, Page 447 roll = -1*proll *((1+iroll+droll )*deltay-((1+2*droll )*lastdeltay)+droll *onebeforelastdeltay); pitch= ppitch*((1+ipitch+dpitch)*deltaz-((1+2*dpitch)*lastdeltaz)+dpitch*onebeforelastdeltaz); //software lowpass (has to be replaced by HW LP on strain gauges) lowpass=10; if((roll>lowpass)||(roll<-lowpass)) roll=lowpass; if((pitch>lowpass)||(pitch<-lowpass)) pitch=lowpass; //save recursive values onebeforelastdeltay=lastdeltay; lastdeltay=deltay; onebeforelastdeltaz=lastdeltaz; lastdeltaz=deltaz; //for(i=0;iMove(deltaservo,speed); } //Lookup Table initialisation //1°-resoluted local sine table (consumes 360Byte memory) float Control::ownsin[90]={ 0.000,0.017,0.035,0.052,0.070,0.087,0.105,0.122,0.139,0.156, 0.174,0.191,0.208,0.225,0.242,0.259,0.276,0.292,0.309,0.326, 0.342,0.358,0.375,0.391,0.407,0.423,0.438,0.454,0.469,0.485, 0.500,0.515,0.530,0.545,0.559,0.574,0.588,0.602,0.616,0.629, 0.643,0.656,0.669,0.682,0.695,0.707,0.719,0.731,0.743,0.755, 0.766,0.777,0.788,0.799,0.809,0.819,0.829,0.839,0.848,0.857, 0.866,0.875,0.883,0.891,0.899,0.906,0.914,0.921,0.927,0.934, 0.940,0.946,0.951,0.956,0.961,0.966,0.970,0.974,0.978,0.982, 0.985,0.988,0.990,0.993,0.995,0.996,0.998,0.999,0.999,1.000};