#include "goalie_behaviors.hh" namespace Soccer03 { /** Proportional feedback control */ CentreGoalie::CentreGoalie(): Behavior(), compass(Compass::I()), psdl(PsdLeft::I()), psdr(PsdRight::I()), psdb(PsdBack::I()) { memset(&speed,0,sizeof(SpeedType)); centregoalie_bt *cg = (centregoalie_bt*) HDTFindEntry(B_CENTREGOALIE,0); if(cg==NULL) OSPanic("Cannot find\n CentreGoalie data\n"); dband_v = cg->dband_v; dband_w = cg->dband_w; Kv = cg->Kv; Kw = cg->Kw * M_PI / 180; left_bias = cg->left_bias; right_bias = cg->right_bias; max_speed = cg->max_speed; max_rate_of_turn = cg->max_rate_of_turn * M_PI / 180; min_rear_distance = cg->min_rear_distance; max_rear_distance = cg->max_rear_distance; reset_rear_distance = cg->reset_rear_distance; int compass_offset = cg->compass_offset; int second_offset = cg->second_offset; compass.Update(); DEBUG_WAIT(50); compass.Update(); int Q = compass.Angle() + compass_offset; while (Q > 180) { Q -= 360; } while (Q < -180) { Q += 360; } desired_angle = Q; second_angle = Q + second_offset; while (second_angle > 180) { second_angle -= 360; } while (second_angle < -180) { second_angle += 360; } reset_distance = false; } int CentreGoalie::Execute() { int max_signal = 0; int Q = 0; int Qd; int e_w; int e_v; int dist_left; int dist_right; int dist_back; bool lined_up = false; bool centred = false; bool turning = false; // Are we resetting our distance from the back of the net? // If so, we need to lineup along the second angle. if (reset_distance) { Qd = second_angle; } else { Qd = desired_angle; } //DEBUG_PRINTF("Qd: %d",Qd); compass.Update(); Q = compass.Angle(); //DEBUG_PRINTF("Q:%d\n",Q); psdl.Update(); dist_left = psdl.X(); psdb.Update(); dist_back = psdb.X(); psdr.Update(); dist_right = psdr.X(); e_w = Qd - Q; while (e_w > 180) { e_w -= 360; } while (e_w < -180) { e_w += 360; } // don't turn if ( (e_w < dband_w) && (e_w > -dband_w) ) { speed.w = 0; lined_up = true; // We are in the deadband (ie lined-up) send a HI_MAX signal //DEBUG_PRINTF("LINED UP!!\n",e_w); } else { //DEBUG_PRINTF("e_w:%d\n",e_w); speed.w = Kw*e_w; //DEBUG_PRINTF("sp w %4.2f\n",speed.w); //DEBUG_WAIT(50); turning = true; } if (!reset_distance) { // Not resetting distance. We are centring on the field (take left/right PSD) //e_v = (int)(((float)dist_right*right_bias) - ((float)dist_left*left_bias)); e_v = (int)(((float)dist_left*left_bias) - ((float)dist_right*right_bias)); } else { // Take reading to the (back) of goals e_v = reset_rear_distance - dist_right; } if ((e_v < dband_v) && (e_v > -dband_v)) { speed.v = 0.0; centred = true; } else { speed.v = -Kv * e_v; } //DEBUG_PRINTF("L,R= %d ",dist_left); //DEBUG_PRINTF("%d ",dist_back); //DEBUG_PRINTF("%d\n",dist_right); // Rate limiter if (speed.w > max_rate_of_turn) { speed.w = max_rate_of_turn; } if (speed.w < -max_rate_of_turn) { speed.w = -max_rate_of_turn; } if (!turning) { if (speed.v > max_speed) { speed.v = max_speed; } if (speed.v < -max_speed) { speed.v = -max_speed; } } else { // If we are turning, then limit the max velocity to 0.5 * max_speed. // We need to do this to prevent the turning-circle becoming too wide. if (speed.v > (max_speed*0.5)) { speed.v = (max_speed*0.5); } if (speed.v < -(max_speed*0.5)) { speed.v = -(max_speed*0.5); } } if (centred && lined_up) { //DEBUG_PRINT("CENT + LINEUP"); if (!reset_distance) { //DEBUG_PRINT("!RESET"); // Check if we are to far / close to the back of the net. if ((dist_back < min_rear_distance) || (dist_back > max_rear_distance)) { //DEBUG_PRINT("DIST BK NOK"); reset_distance = true; } else { reset_distance = false; //DEBUG_PRINT("DISK BK OK!"); } } else { //DEBUG_PRINT(""); // We are now at the correct disatnce to the back of the net. //DEBUG_PRINT("BK + CENT OK!"); reset_distance = false; } } return EXCITE_IDLE; } void CentreGoalie::Feed(SignalLink& l) { if ( !l.Generic() ) reinterpret_cast(l).Speed(speed); Behavior::Feed(l); } /**Connect SpeedLink input with source Centre. */ CentreGoalie& operator<<(SpeedLink& l, CentreGoalie& i) { SignalLinkInputToBehavior(l,i); return i; } /**Add output SpeedLink to Centre. */ SpeedLink& operator>>(CentreGoalie& n, SpeedLink& o) { BehaviorOutputToSignalLink(n,o); return o; } /** Behaviour to turn & tilt the head towards the ball AND to correct the * the raw ball position. The raw ball position is the (r,phi) relative * to the camera. The corrected (r,phi) is the (expected) position * of the ball after taking into account the orientation of the head at * the time the frame was taken * * Assumptions: * 1) All incoming links are polar * 2) The exciatation signal of the 'raw ball position' is the greatest. */ MoveHead2DOF::MoveHead2DOF(): Behavior(), compass(Compass::I()), headturn(HeadServo::I()), headtilt(TiltServo::I()) { head2dof_bt *hd = (head2dof_bt*) HDTFindEntry(B_HEAD2DOF,0); if(hd==NULL) OSPanic("Cannot find\n Head2DOF data\n"); Kp_turn = hd->Kp_turn; Kp_tilt = hd->Kp_tilt; Kp_drive = hd->Kp_drive; dband_turn = hd->dband_turn; dband_tilt = hd->dband_tilt; max_speed = hd->max_speed; range_modifier = hd->range_modifier; compass_dband = hd->compass_dband; int compass_offset = hd->compass_offset; Kw = hd->Kw * M_PI / 180; max_rate_of_turn = hd->max_rate_of_turn * M_PI / 180; compass.Update(); DEBUG_WAIT(50); compass.Update(); int Q = compass.Angle() + compass_offset; while (Q > 180) { Q -= 360; } while (Q < -180) { Q += 360; } desired_angle = Q; memset(&raw,0,sizeof(BallType)); memset(&speed,0,sizeof(SpeedType)); } int MoveHead2DOF::Execute() { float dQ, e, Q; float e_compass; int max_signal; float turn_angle, tilt_angle; SignalLink* i = inlinks.Begin(); max_signal = 0; speed.v = 0.0; speed.w = 0.0; // find the maximum input signal BallLink *bl = reinterpret_cast(FindMaxNonGenericInputSignal()); if (bl==NULL) return EXCITE_NONE; raw = bl->Ball(); // DEBUG_PRINTF("r,phi=%3.1f,",raw.r); // DEBUG_PRINTF("%3.1f\n",raw.phi); // check if compass is roughly lined up so we don't move too far from the goals compass.Update(); Q = compass.Angle(); //DEBUG_PRINTF("Q:%d\n",Q); e_compass = desired_angle - Q; while (e_compass > 180) { e_compass -= 360; } while (e_compass < -180) { e_compass += 360; } // don't turn if ( (e_compass < compass_dband) && (e_compass > -compass_dband) ) { speed.w = 0; } else { speed.w = Kw*e_compass; } // check if the distance to the object is greater than 0 // if not, turn the servo back to middle position if(!raw.visible) { tilt_angle = 0.0; turn_angle = 0.0; return EXCITE_NONE; } else { dQ = Kp_turn*raw.phi; turn_angle = headturn.AngleRad(); if(dQ > dband_turn || dQ < -dband_turn) { turn_angle += dQ; } speed.v = turn_angle * Kp_drive; e = range_modifier - raw.r; dQ = e * Kp_tilt; tilt_angle = headtilt.AngleRad(); if(dQ > dband_tilt || dQ < -dband_tilt) { tilt_angle += dQ; } // set the head angle headturn.AngleRad( turn_angle ); headturn.Update(); headtilt.AngleRad( tilt_angle ); headtilt.Update(); } if (speed.v > max_speed) { speed.v = max_speed; } if (speed.v < -max_speed) { speed.v = -max_speed; } if (speed.w > max_rate_of_turn) { speed.w = max_rate_of_turn; } if (speed.w < -max_rate_of_turn) { speed.w = -max_rate_of_turn; } return EXCITE_IDLE; } /** Feed the signal */ void MoveHead2DOF::Feed(SignalLink &l) { if (!l.Generic()) { reinterpret_cast(l).Speed(speed); } Behavior::Feed(l); } /**Connect PolarLink output with target MoveHead2DOF. */ MoveHead2DOF& operator>>(BallLink& l, MoveHead2DOF& o) { SignalLinkOutputToBehavior(l,o); return o; } /**Connect PolarLink input with source MoveHead2DOF. */ MoveHead2DOF& operator<<(SpeedLink& l, MoveHead2DOF& i) { SignalLinkInputToBehavior(l,i); return i; } /**Add output PolarLink to MoveHead2DOF. */ SpeedLink& operator>>(MoveHead2DOF& n, SpeedLink& o) { BehaviorOutputToSignalLink(n,o); return o; } /**Add input PolarLink to MoveHead2DOF. */ BallLink& operator<<(MoveHead2DOF& n, BallLink& i) { BehaviorInputToSignalLink(n,i); return i; } KickBall::KickBall(): Behavior(), boot(KickerServo::I()) { boot.Angle( 255 ); boot.Update(); kickball_bt *kb = (kickball_bt*) HDTFindEntry(B_KICKBALL,0); if(kb==NULL) OSPanic("Cannot find\n KickBall data\n"); fire_range = kb->fire_range; } /** Proportional feedback control */ int KickBall::Execute() { BallType ball; DEBUG_PRINT("KICK\n"); // find the maximum input signal BallLink *bl = reinterpret_cast(FindMaxNonGenericInputSignal()); if (bl==NULL) { if (OSGetCount() > (last_kick_time + (8*100))) { // return to rest position (ready for another kick !!) boot.Angle( 200 ); boot.Update(); DEBUG_WAIT(30); DEBUG_PRINT("KICK\n"); boot.Angle( 255 ); boot.Update(); last_kick_time = OSGetCount(); } return EXCITE_NONE; } ball = bl->Ball(); if (ball.visible && (ball.r < fire_range)) { // return to rest position (ready for another kick !!) boot.Angle( 200 ); boot.Update(); DEBUG_WAIT(30); DEBUG_PRINT("KICK\n"); boot.Angle( 200 ); boot.Update(); last_kick_time = OSGetCount(); } else { // return to rest position boot.Angle( 255 ); } boot.Update(); if (ball.visible && ball.close) { // return a signal (is passed to the 'sayattack' behaviour) return EXCITE_IDLE; } // else... say nothing return EXCITE_NONE; } KickBall& operator>>(BallLink& l, KickBall& o) { SignalLinkOutputToBehavior(l,o); return o; } /**Add input PolarLink to MoveHead2DOF. */ BallLink& operator<<(KickBall& n, BallLink& i) { BehaviorInputToSignalLink(n,i); return i; } int CheckBallFar::Execute(){ BallType ball; BallLink *bl = reinterpret_cast(FindMaxNonGenericInputSignal()); if (bl==NULL) return EXCITE_NONE; ball = bl->Ball(); if (ball.visible && !ball.close) return EXCITE_IDLE; return EXCITE_NONE; } CheckBallFar& operator>>(BallLink& l, CheckBallFar& o) { SignalLinkOutputToBehavior(l,o); return o; } /**Add input PolarLink to MoveHead2DOF. */ BallLink& operator<<(CheckBallFar& n, BallLink& i) { BehaviorInputToSignalLink(n,i); return i; } HeadSearch2DOF::HeadSearch2DOF(): Behavior(), headturn(HeadServo::I()), headtilt(TiltServo::I()) { headsearch_bt *hs = (headsearch_bt*) HDTFindEntry(B_HEADSEARCH,0); if(hs==NULL) OSPanic("Cannot find\n HeadSearch data\n"); speed_x = hs->speed_x; speed_y = hs->speed_y; look_far = hs->look_far; look_close = hs->look_far; x_min = headturn.SafeMin()+speed_y; x_max = headturn.SafeMax()-speed_y; y_min = headtilt.SafeMin(); y_max = headtilt.SafeMax(); orig_speed_x = speed_x; orig_speed_y = speed_y; } /** Move head in a search pattern */ int HeadSearch2DOF::Execute() { x_pos = headturn.Angle() + speed_x; if ( x_pos >= x_max ) { speed_x = -orig_speed_x; if (y_pos == look_close) { y_pos = look_far; } else { y_pos = look_close; } } if ( x_pos <= x_min ) { speed_x = orig_speed_x; if (y_pos == look_close) { y_pos = look_far; } else { y_pos = look_close; } } // if ( y_pos >= y_max ) { // speed_y = -orig_speed_y; // } // if ( y_pos <= y_min ) { // speed_y = orig_speed_y; // } headturn.Angle( x_pos ); //headtilt->Angle( y_pos + speed_y ); headtilt.Angle(y_pos); headturn.Update(); headtilt.Update(); return EXCITE_IDLE; } }; // namespace Soccer03