You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
198 lines
6.3 KiB
198 lines
6.3 KiB
#include "agent.h"
|
|
#include <iostream>
|
|
#include <cmath>
|
|
|
|
Agent::Agent(AgentState init_state, double init_raduis, double init_blind_angle, int init_number):
|
|
state(init_state), raduis(init_raduis), blind_angle(init_blind_angle), number(init_number)
|
|
{
|
|
velocity_max.linear_velocity = 0.1;
|
|
velocity_max.angular_velocity = 1;
|
|
velocity.angular_velocity = 0.0;
|
|
velocity.linear_velocity = 0.0;
|
|
//用自身坐标初始化目标点
|
|
target.x = state.x;
|
|
target.y = state.y;
|
|
}
|
|
|
|
/**************************Parameter************************************/
|
|
void Agent::UpdateState(double v_linear, double v_angular)
|
|
{
|
|
state.x = state.x + v_linear*cos(state.head);
|
|
state.y = state.y + v_linear*sin(state.head);
|
|
state.head = state.head + v_angular;
|
|
//0-2pi yaw angle
|
|
if(state.head > 2*M_PI)
|
|
state.head = state.head - int(state.head / (2*M_PI)) * 2 * M_PI;
|
|
else if(state.head < 0)
|
|
state.head = state.head + int(-state.head / (2*M_PI) + 1) * 2 * M_PI;
|
|
}
|
|
|
|
void Agent::SetState(AgentState state)
|
|
{
|
|
this->state = state;
|
|
}
|
|
|
|
AgentState Agent::GetState()
|
|
{
|
|
return this->state;
|
|
}
|
|
|
|
Point Agent::GetPosition()
|
|
{
|
|
Point p = {state.x, state.y};
|
|
return p;
|
|
}
|
|
|
|
void Agent::AppendNeighbors(AgentState neighbor)
|
|
{
|
|
this->neigbors.push_back(neighbor);
|
|
}
|
|
std::vector<AgentState> Agent::GetNeighbors()
|
|
{
|
|
return neigbors;
|
|
}
|
|
void Agent::ClearNeighbors()
|
|
{
|
|
this->neigbors.clear();
|
|
}
|
|
double Agent::GetRaduis()
|
|
{
|
|
return this->raduis;
|
|
}
|
|
|
|
double Agent::GetHead()
|
|
{
|
|
return state.head;
|
|
}
|
|
double Agent::GetBlindAngle()
|
|
{
|
|
return blind_angle;
|
|
}
|
|
|
|
Eigen::Vector2d Agent::GetHeadVector()
|
|
{
|
|
return Eigen::Vector2d(cos(state.head),sin(state.head));
|
|
}
|
|
|
|
//判断点是否在前面
|
|
bool Agent::isInHead(Point p)
|
|
{
|
|
bool flag = false;
|
|
Eigen::Vector2d s2p = {p.x - state.x, p.y - state.y};
|
|
Eigen::Vector2d h = GetHeadVector();
|
|
double alpha = acos(s2p.dot(h) / s2p.norm());
|
|
if(alpha <= M_PI/2) return true;
|
|
else return false;
|
|
|
|
}
|
|
|
|
|
|
/******************************Algrithm***************************************/
|
|
/*calculate by neighbors*/
|
|
AgentConstraint Agent::CalculateConstraint()
|
|
{
|
|
constraint.linear = velocity_max.linear_velocity;
|
|
constraint.angularL = velocity_max.angular_velocity;
|
|
constraint.angularR = velocity_max.angular_velocity;
|
|
|
|
double beta_temp, linear_temp, angular_temp, distance_to_boundary;
|
|
for(auto n:neigbors)
|
|
{
|
|
Eigen::Vector2d n2self(state.x - n.x, state.y - n.y);
|
|
Eigen::Vector2d nighbor_head =GetVecFromHead(n.head);
|
|
double dist;
|
|
/*not in other's blind area, ensure undirected edge*/
|
|
if(acos(nighbor_head.dot(n2self)/(nighbor_head.norm()*n2self.norm())) > (M_PI - blind_angle/2))
|
|
continue;
|
|
|
|
/*1.linear velocity limit by circular bundary*/
|
|
dist = n2self.norm();
|
|
// 这里假设neighbor与自己的半径相同, 后面写算法需要注意
|
|
constraint.linear = std::min(constraint.linear, (raduis-dist)/2);
|
|
|
|
/*2.linear constraint from other agent blind area of neighbor*/
|
|
distance_to_boundary = GetDist2Bound(n, this->state, this->blind_angle);
|
|
constraint.linear = std::min(constraint.linear, distance_to_boundary/2);
|
|
|
|
/*3.linear&angular constraint from other agent position*/
|
|
distance_to_boundary = GetDist2Bound(this->state, n, this->blind_angle);
|
|
linear_temp = std::min(velocity_max.linear_velocity, distance_to_boundary/2); //assume neighbor linear constraints
|
|
constraint.linear = std::min(constraint.linear, linear_temp); //update self linear
|
|
beta_temp = acos((-GetHeadVector()).dot(-n2self)/(GetHeadVector().norm()*dist))-blind_angle/2;
|
|
angular_temp = beta_temp - asin((linear_temp+constraint.linear)/dist); //拿估计邻居的线速度与自己真实的线速度约束计算
|
|
if(GetHeadVector().cross(-n2self) >= 0)
|
|
constraint.angularL = std::min(constraint.angularL, angular_temp);
|
|
else
|
|
constraint.angularR = std::min(constraint.angularR, angular_temp);
|
|
}
|
|
|
|
return constraint;
|
|
}
|
|
|
|
/*calculate the average point by neighbors (cotain self)*/
|
|
Point Agent::GetAveragePoint()
|
|
{
|
|
Point average = {0, 0};
|
|
for(auto n:neigbors)
|
|
{
|
|
average.x += n.x;
|
|
average.y += n.y;
|
|
}
|
|
|
|
average.x = average.x / neigbors.size();
|
|
average.y = average.y / neigbors.size();
|
|
return average;
|
|
}
|
|
|
|
//以平均点为目标点
|
|
void Agent::MoveAverageStrategy()
|
|
{
|
|
double v_linear, v_angular;
|
|
double dist_linear, dist_angular;
|
|
target = GetAveragePoint();
|
|
Eigen::Vector2d p2a = (target - GetPosition()).toVector();
|
|
dist_linear = p2a.norm();
|
|
dist_angular = acos(p2a.dot(GetHeadVector())/dist_linear); //0-2pi
|
|
CalculateConstraint();
|
|
if(isInHead(target)) //目标点在前面
|
|
{
|
|
v_linear = std::min(constraint.linear, dist_linear/2);
|
|
if(isRight(state, target)) v_angular = -std::min(dist_angular, constraint.angularL);
|
|
else v_angular = std::min(dist_angular, constraint.angularR);
|
|
}
|
|
else //目标点在后面
|
|
{
|
|
v_linear = -std::min(constraint.linear, dist_linear/2);
|
|
//点在右边,后退左转
|
|
if(isRight(state, target)) v_angular = std::min(dist_angular, constraint.angularR);
|
|
else v_angular = -std::min(dist_angular, constraint.angularL);
|
|
}
|
|
UpdateState(v_linear, v_angular);
|
|
// std::cout << number << "x:" << state.x << " y:" << state.y << std::endl;
|
|
// std::cout << "tx:" << average_point.x << " ty:" << average_point.y << std::endl;
|
|
}
|
|
|
|
|
|
/**************************************************************************/
|
|
|
|
//static function init agents
|
|
void Agent::InitMultiAgent(std::vector<Agent *> *multi_agent, const std::vector<AgentState> init_states,
|
|
const std::vector<double> raduis, const std::vector<double> blind_angles)
|
|
{
|
|
if(init_states.size()!=raduis.size() || init_states.size()!=blind_angles.size())
|
|
{
|
|
std::cout << "init error\n";
|
|
return ;
|
|
}
|
|
auto states_it = init_states.begin();
|
|
auto radius_it = raduis.begin();
|
|
auto blind_it = blind_angles.begin();
|
|
int index = 0;
|
|
multi_agent->clear();
|
|
for(; states_it!=init_states.end(); states_it++,radius_it++,blind_it++)
|
|
{
|
|
multi_agent->push_back(new Agent(*states_it, *radius_it, *blind_it, index));
|
|
index++;
|
|
}
|
|
}
|