normalplay的地位

流程图如下所示:

整个足球机器人的比赛规则中如果没有发生犯规的话,SOM软件一直执行的就是normalplay脚本。其实,在正常比赛中,因为小型机器人并没有像人一样这么智能,人会自主最大程度上的避免犯规,但是机器不会,所有犯规还是很常见的,甚至可以说在1个小时的比赛中,有半个小时甚至是半个小时以上SOM软件都是在执行犯规脚本,因此normalplay固然重要,但是也要注重其他场景的脚本哦(尤其是角球脚本,这点我会在我的另外一篇博客中进行讲解)。

接球速度和射门动作

经过实际测试发现,足球机器人在快要碰到球的时候会有一个减速的动作,经过后来与机器人公司的工作人员沟通了之后确认是下载到板子上的程序限定了这个动作,是我们用户改变不了的。但是我们团队一名同学发现了当把足球机器人的目标点设定到实际目标点前面一段距离的时候,足球机器人的运行速度会得到质的提升!  拿到球了之后是射门动作,这个射门动作也比较简单,前锋在去拿球的过程中会一直判断是否拿到了球,如果拿到了球就执行射门动作,射门动作是这样的,持球之后将足球机器人的朝向变为敌方球门,当足球机器人转到敌方球门中点和持球装置朝向几乎相同时就进行射门,我画一个示意图。

代码讲解

这个是我前锋skill的主要函数。

PlayerTask player_plan(const WorldModel* model, int robot_id){
  PlayerTask task;
  const float& dir = model->get_our_player_dir(robot_id);
  const point2f& vel = model->get_ball_vel();
  const point2f& ball = model->get_ball_pos();
  const point2f& last_ball = model->get_ball_pos(1);
  const point2f& runner = model->get_our_player_pos(robot_id);
  const point2f opp_right(300,25);
  const point2f opp_left(300, -25);
  point2f opp_goal = -FieldPoint::Goal_Center_Point;
  const point2f& goalie_pos = model->get_our_player_pos(model->get_our_goalie());
  point2f temp(0, 0);
  vector ball_points;
  float b_interrupt(0);
  float k_slope(0);
  float angle (0);//小球运动的角度
  bool ismove = (ball - last_ball).length() > ball_movingdist ? true : false;
  float r2b_dist = (runner - ball).length();
  float change_track = (ball-last_ball).length();
 
  get_k_b(model, b_interrupt, k_slope, ball_points);
  get_angle(angle , k_slope, vel);
  //get_cross(temp, runner, b_interrupt, k_slope);
 
  if (is_getball(ball,runner, dir) ){
    if (dir > (opp_left-runner).angle() && dir < (opp_right-runner).angle()){
      task.needKick = true;
      task.kickPower = 127;
    }
    task.target_pos = runner + Maths::vector2polar(runcircle, dir);
    task.orientate = (opp_goal-runner).angle();
  }
  else{
    if (ismove){
      if (is_ready_pass(ball, runner, opp_goal,angle) && r2b_dist < 60 ){
        task.target_pos = runner;
        task.orientate = (ball-runner).angle();
      }
      else{
        task.target_pos = ball + Maths::vector2polar(change_track*magnification, angle);
        task.orientate = (ball - runner).angle();
      }
    }
    else{
      task.orientate = (ball - runner).angle();
      task.target_pos = ball;
    }
  }
 
  if (r2b_dist<50){
    task.needCb = true;
  }
 
  return task;
}

下面这个函数是一个功能函数,用来判断在这帧图像里面,球是否在足球机器人朝向的延长线上,示意图如下,在接球,追球,守门员等很多地方都可以用到。

bool is_getball(const point2f& ball, const point2f& runner, const float& dir){
  //miss参数需要在比赛时实地调试
  cout << "进入is_getball的判断" << endl;
  bool get_ball = (ball - runner).length() < miss && (fabs(anglemod(dir - (ball - runner).angle())) < getangle);
  cout << "前锋里的(ball - runner).length()   " << (ball - runner).length() << endl;
  cout << "前锋里的fabs(anglemod(dir - (ball - runner).angle())   " << fabs(anglemod(dir - (ball - runner).angle())) << endl;
  if (get_ball){
    return true;
  }
  else{
    return false;
  }
}

在该skill主要函数里面,这个条件判断是一直在运行的,所以要离开追球的状态就需要拿到球,所以在这个if判断下面就是拿球之后的操作啦。

下面这个就是追球的具体动作设计了(“嘴”就是小车的持球装置):