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.
		
		
		
		
		
			
		
			
				
					
					
						
							144 lines
						
					
					
						
							4.5 KiB
						
					
					
				
			
		
		
	
	
							144 lines
						
					
					
						
							4.5 KiB
						
					
					
				#define _USE_MATH_DEFINES
 | 
						|
 | 
						|
#include <iostream>
 | 
						|
#include <cmath>
 | 
						|
#include <eigen3/Eigen/Dense>
 | 
						|
 | 
						|
#include "common/transformations/orientation.hpp"
 | 
						|
#include "common/transformations/coordinates.hpp"
 | 
						|
 | 
						|
Eigen::Quaterniond ensure_unique(Eigen::Quaterniond quat){
 | 
						|
  if (quat.w() > 0){
 | 
						|
    return quat;
 | 
						|
  } else {
 | 
						|
    return Eigen::Quaterniond(-quat.w(), -quat.x(), -quat.y(), -quat.z());
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
Eigen::Quaterniond euler2quat(Eigen::Vector3d euler){
 | 
						|
  Eigen::Quaterniond q;
 | 
						|
 | 
						|
  q = Eigen::AngleAxisd(euler(2), Eigen::Vector3d::UnitZ())
 | 
						|
    * Eigen::AngleAxisd(euler(1), Eigen::Vector3d::UnitY())
 | 
						|
    * Eigen::AngleAxisd(euler(0), Eigen::Vector3d::UnitX());
 | 
						|
  return ensure_unique(q);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
Eigen::Vector3d quat2euler(Eigen::Quaterniond quat){
 | 
						|
  // TODO: switch to eigen implementation if the range of the Euler angles doesn't matter anymore
 | 
						|
  // Eigen::Vector3d euler = quat.toRotationMatrix().eulerAngles(2, 1, 0);
 | 
						|
  // return {euler(2), euler(1), euler(0)};
 | 
						|
  double gamma = atan2(2 * (quat.w() * quat.x() + quat.y() * quat.z()), 1 - 2 * (quat.x()*quat.x() + quat.y()*quat.y()));
 | 
						|
  double asin_arg_clipped = std::clamp(2 * (quat.w() * quat.y() - quat.z() * quat.x()), -1.0, 1.0);
 | 
						|
  double theta = asin(asin_arg_clipped);
 | 
						|
  double psi = atan2(2 * (quat.w() * quat.z() + quat.x() * quat.y()), 1 - 2 * (quat.y()*quat.y() + quat.z()*quat.z()));
 | 
						|
  return {gamma, theta, psi};
 | 
						|
}
 | 
						|
 | 
						|
Eigen::Matrix3d quat2rot(Eigen::Quaterniond quat){
 | 
						|
  return quat.toRotationMatrix();
 | 
						|
}
 | 
						|
 | 
						|
Eigen::Quaterniond rot2quat(const Eigen::Matrix3d &rot){
 | 
						|
  return ensure_unique(Eigen::Quaterniond(rot));
 | 
						|
}
 | 
						|
 | 
						|
Eigen::Matrix3d euler2rot(Eigen::Vector3d euler){
 | 
						|
  return quat2rot(euler2quat(euler));
 | 
						|
}
 | 
						|
 | 
						|
Eigen::Vector3d rot2euler(const Eigen::Matrix3d &rot){
 | 
						|
  return quat2euler(rot2quat(rot));
 | 
						|
}
 | 
						|
 | 
						|
Eigen::Matrix3d rot_matrix(double roll, double pitch, double yaw){
 | 
						|
  return euler2rot({roll, pitch, yaw});
 | 
						|
}
 | 
						|
 | 
						|
Eigen::Matrix3d rot(Eigen::Vector3d axis, double angle){
 | 
						|
  Eigen::Quaterniond q;
 | 
						|
  q = Eigen::AngleAxisd(angle, axis);
 | 
						|
  return q.toRotationMatrix();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
Eigen::Vector3d ecef_euler_from_ned(ECEF ecef_init, Eigen::Vector3d ned_pose) {
 | 
						|
  /*
 | 
						|
    Using Rotations to Build Aerospace Coordinate Systems
 | 
						|
    Don Koks
 | 
						|
    https://apps.dtic.mil/dtic/tr/fulltext/u2/a484864.pdf
 | 
						|
  */
 | 
						|
  LocalCoord converter = LocalCoord(ecef_init);
 | 
						|
  Eigen::Vector3d zero = ecef_init.to_vector();
 | 
						|
 | 
						|
  Eigen::Vector3d x0 = converter.ned2ecef({1, 0, 0}).to_vector() - zero;
 | 
						|
  Eigen::Vector3d y0 = converter.ned2ecef({0, 1, 0}).to_vector() - zero;
 | 
						|
  Eigen::Vector3d z0 = converter.ned2ecef({0, 0, 1}).to_vector() - zero;
 | 
						|
 | 
						|
  Eigen::Vector3d x1 = rot(z0, ned_pose(2)) * x0;
 | 
						|
  Eigen::Vector3d y1 = rot(z0, ned_pose(2)) * y0;
 | 
						|
  Eigen::Vector3d z1 = rot(z0, ned_pose(2)) * z0;
 | 
						|
 | 
						|
  Eigen::Vector3d x2 = rot(y1, ned_pose(1)) * x1;
 | 
						|
  Eigen::Vector3d y2 = rot(y1, ned_pose(1)) * y1;
 | 
						|
  Eigen::Vector3d z2 = rot(y1, ned_pose(1)) * z1;
 | 
						|
 | 
						|
  Eigen::Vector3d x3 = rot(x2, ned_pose(0)) * x2;
 | 
						|
  Eigen::Vector3d y3 = rot(x2, ned_pose(0)) * y2;
 | 
						|
 | 
						|
 | 
						|
  x0 = Eigen::Vector3d(1, 0, 0);
 | 
						|
  y0 = Eigen::Vector3d(0, 1, 0);
 | 
						|
  z0 = Eigen::Vector3d(0, 0, 1);
 | 
						|
 | 
						|
  double psi = atan2(x3.dot(y0), x3.dot(x0));
 | 
						|
  double theta = atan2(-x3.dot(z0), sqrt(pow(x3.dot(x0), 2) + pow(x3.dot(y0), 2)));
 | 
						|
 | 
						|
  y2 = rot(z0, psi) * y0;
 | 
						|
  z2 = rot(y2, theta) * z0;
 | 
						|
 | 
						|
  double phi = atan2(y3.dot(z2), y3.dot(y2));
 | 
						|
 | 
						|
  return {phi, theta, psi};
 | 
						|
}
 | 
						|
 | 
						|
Eigen::Vector3d ned_euler_from_ecef(ECEF ecef_init, Eigen::Vector3d ecef_pose){
 | 
						|
  /*
 | 
						|
    Using Rotations to Build Aerospace Coordinate Systems
 | 
						|
    Don Koks
 | 
						|
    https://apps.dtic.mil/dtic/tr/fulltext/u2/a484864.pdf
 | 
						|
  */
 | 
						|
  LocalCoord converter = LocalCoord(ecef_init);
 | 
						|
 | 
						|
  Eigen::Vector3d x0 = Eigen::Vector3d(1, 0, 0);
 | 
						|
  Eigen::Vector3d y0 = Eigen::Vector3d(0, 1, 0);
 | 
						|
  Eigen::Vector3d z0 = Eigen::Vector3d(0, 0, 1);
 | 
						|
 | 
						|
  Eigen::Vector3d x1 = rot(z0, ecef_pose(2)) * x0;
 | 
						|
  Eigen::Vector3d y1 = rot(z0, ecef_pose(2)) * y0;
 | 
						|
  Eigen::Vector3d z1 = rot(z0, ecef_pose(2)) * z0;
 | 
						|
 | 
						|
  Eigen::Vector3d x2 = rot(y1, ecef_pose(1)) * x1;
 | 
						|
  Eigen::Vector3d y2 = rot(y1, ecef_pose(1)) * y1;
 | 
						|
  Eigen::Vector3d z2 = rot(y1, ecef_pose(1)) * z1;
 | 
						|
 | 
						|
  Eigen::Vector3d x3 = rot(x2, ecef_pose(0)) * x2;
 | 
						|
  Eigen::Vector3d y3 = rot(x2, ecef_pose(0)) * y2;
 | 
						|
 | 
						|
  Eigen::Vector3d zero = ecef_init.to_vector();
 | 
						|
  x0 = converter.ned2ecef({1, 0, 0}).to_vector() - zero;
 | 
						|
  y0 = converter.ned2ecef({0, 1, 0}).to_vector() - zero;
 | 
						|
  z0 = converter.ned2ecef({0, 0, 1}).to_vector() - zero;
 | 
						|
 | 
						|
  double psi = atan2(x3.dot(y0), x3.dot(x0));
 | 
						|
  double theta = atan2(-x3.dot(z0), sqrt(pow(x3.dot(x0), 2) + pow(x3.dot(y0), 2)));
 | 
						|
 | 
						|
  y2 = rot(z0, psi) * y0;
 | 
						|
  z2 = rot(y2, theta) * z0;
 | 
						|
 | 
						|
  double phi = atan2(y3.dot(z2), y3.dot(y2));
 | 
						|
 | 
						|
  return {phi, theta, psi};
 | 
						|
}
 | 
						|
 | 
						|
 |