Ejemplo n.º 1
0
//------------------------------------------------------------------------------
void ManifoldPreintegration::update(const Vector3& measuredAcc,
    const Vector3& measuredOmega, const double dt, Matrix9* A, Matrix93* B,
    Matrix93* C) {

  // Correct for bias in the sensor frame
  Vector3 acc = biasHat_.correctAccelerometer(measuredAcc);
  Vector3 omega = biasHat_.correctGyroscope(measuredOmega);

  // Possibly correct for sensor pose
  Matrix3 D_correctedAcc_acc, D_correctedAcc_omega, D_correctedOmega_omega;
  if (p().body_P_sensor)
    boost::tie(acc, omega) = correctMeasurementsBySensorPose(acc, omega,
        D_correctedAcc_acc, D_correctedAcc_omega, D_correctedOmega_omega);

  // Save current rotation for updating Jacobians
  const Rot3 oldRij = deltaXij_.attitude();

  // Do update
  deltaTij_ += dt;
  deltaXij_ = deltaXij_.update(acc, omega, dt, A, B, C); // functional

  if (p().body_P_sensor) {
    // More complicated derivatives in case of non-trivial sensor pose
    *C *= D_correctedOmega_omega;
    if (!p().body_P_sensor->translation().isZero())
      *C += *B * D_correctedAcc_omega;
    *B *= D_correctedAcc_acc; // NOTE(frank): needs to be last
  }

  // Update Jacobians
  // TODO(frank): Try same simplification as in new approach
  Matrix3 D_acc_R;
  oldRij.rotate(acc, D_acc_R);
  const Matrix3 D_acc_biasOmega = D_acc_R * delRdelBiasOmega_;

  const Vector3 integratedOmega = omega * dt;
  Matrix3 D_incrR_integratedOmega;
  const Rot3 incrR = Rot3::Expmap(integratedOmega, D_incrR_integratedOmega); // expensive !!
  const Matrix3 incrRt = incrR.transpose();
  delRdelBiasOmega_ = incrRt * delRdelBiasOmega_ - D_incrR_integratedOmega * dt;

  double dt22 = 0.5 * dt * dt;
  const Matrix3 dRij = oldRij.matrix(); // expensive
  delPdelBiasAcc_ += delVdelBiasAcc_ * dt - dt22 * dRij;
  delPdelBiasOmega_ += dt * delVdelBiasOmega_ + dt22 * D_acc_biasOmega;
  delVdelBiasAcc_ += -dRij * dt;
  delVdelBiasOmega_ += D_acc_biasOmega * dt;
}
//*************************************************************************
TEST (EssentialMatrixFactor, testData) {
    CHECK(readOK);

    // Check E matrix
    Matrix expected(3, 3);
    expected << 0, 0, 0, 0, 0, -0.1, 0.1, 0, 0;
    Matrix aEb_matrix = skewSymmetric(c1Tc2.x(), c1Tc2.y(), c1Tc2.z())
                        * c1Rc2.matrix();
    EXPECT(assert_equal(expected, aEb_matrix, 1e-8));

    // Check some projections
    EXPECT(assert_equal(Point2(0, 0), pA(0), 1e-8));
    EXPECT(assert_equal(Point2(0, 0.1), pB(0), 1e-8));
    EXPECT(assert_equal(Point2(0, -1), pA(4), 1e-8));
    EXPECT(assert_equal(Point2(-1, 0.2), pB(4), 1e-8));

    // Check homogeneous version
    EXPECT(assert_equal(Vector3(-1, 0.2, 1), vB(4), 1e-8));

    // Check epipolar constraint
    for (size_t i = 0; i < 5; i++)
        EXPECT_DOUBLES_EQUAL(0, vA(i).transpose() * aEb_matrix * vB(i), 1e-8);

    // Check epipolar constraint
    for (size_t i = 0; i < 5; i++)
        EXPECT_DOUBLES_EQUAL(0, trueE.error(vA(i), vB(i)), 1e-7);
}
Ejemplo n.º 3
0
/* ************************************************************************* */
TEST( dataSet, openGL2gtsam)
{
  Vector3 rotVec(0.2, 0.7, 1.1);
  Rot3 R = Rot3::Expmap(rotVec);
  Point3 t = Point3(0.0,0.0,0.0);
  Pose3 poseGTSAM = Pose3(R,t);

  Pose3 expected = openGL2gtsam(R, t.x(), t.y(), t.z());

  Point3 r1 = R.r1(), r2 = R.r2(), r3 = R.r3(); //columns!
  Rot3 cRw(
      r1.x(),  r2.x(),  r3.x(),
     -r1.y(), -r2.y(), -r3.y(),
      -r1.z(), -r2.z(), -r3.z());
  Rot3 wRc = cRw.inverse();
  Pose3 actual = Pose3(wRc,t);

  EXPECT(assert_equal(expected,actual));
}
Ejemplo n.º 4
0
int main()
{
  int n = 100000; long timeLog, timeLog2; double seconds;
	// create a random direction:
	double norm=sqrt(1.0+16.0+4.0);
	double x=1.0/norm, y=4.0/norm, z=2.0/norm;
  Vector v = Vector_(3,x,y,z);
  Rot3 R = Rot3::rodriguez(0.1, 0.4, 0.2), R2 = R.retract(v);

  TEST("Rodriguez formula given axis angle", Rot3::rodriguez(v,0.001))
  TEST("Rodriguez formula given canonical coordinates", Rot3::rodriguez(v))
  TEST("Expmap", R*Rot3::Expmap(v))
  TEST("Retract", R.retract(v))
  TEST("Logmap", Rot3::Logmap(R.between(R2)))
  TEST("localCoordinates", R.localCoordinates(R2))
  TEST("Slow rotation matrix",Rot3::Rz(z)*Rot3::Ry(y)*Rot3::Rx(x))
  TEST("Fast Rotation matrix", Rot3::RzRyRx(x,y,z))

  return 0;
}
Ejemplo n.º 5
0
  SimpleCamera simpleCamera(const Matrix& P) {

    // P = [A|a] = s K cRw [I|-T], with s the unknown scale
    Matrix A = P.topLeftCorner(3, 3);
    Vector a = P.col(3);

    // do RQ decomposition to get s*K and cRw angles
    Matrix sK;
    Vector xyz;
    boost::tie(sK, xyz) = RQ(A);

    // Recover scale factor s and K
    double s = sK(2, 2);
    Matrix K = sK / s;

    // Recover cRw itself, and its inverse
    Rot3 cRw = Rot3::RzRyRx(xyz);
    Rot3 wRc = cRw.inverse();

    // Now, recover T from a = - s K cRw T = - A T
    Vector T = -(A.inverse() * a);
    return SimpleCamera(Pose3(wRc, T),
        Cal3_S2(K(0, 0), K(1, 1), K(0, 1), K(0, 2), K(1, 2)));
  }
Ejemplo n.º 6
0
//------------------------------------------------------------------------------
void PreintegrationBase::update(const Vector3& j_measuredAcc,
    const Vector3& j_measuredOmega, const double dt,
    Matrix3* D_incrR_integratedOmega, Matrix9* D_updated_current,
    Matrix93* D_updated_measuredAcc, Matrix93* D_updated_measuredOmega) {

  // Save current rotation for updating Jacobians
  const Rot3 oldRij = deltaXij_.attitude();

  // Do update
  deltaTij_ += dt;
  deltaXij_ = updatedDeltaXij(j_measuredAcc, j_measuredOmega, dt,
      D_updated_current, D_updated_measuredAcc, D_updated_measuredOmega); // functional

  // Update Jacobians
  // TODO(frank): we are repeating some computation here: accessible in F ?
  Vector3 j_correctedAcc, j_correctedOmega;
  boost::tie(j_correctedAcc, j_correctedOmega) =
      correctMeasurementsByBiasAndSensorPose(j_measuredAcc, j_measuredOmega);

  Matrix3 D_acc_R;
  oldRij.rotate(j_correctedAcc, D_acc_R);
  const Matrix3 D_acc_biasOmega = D_acc_R * delRdelBiasOmega_;

  const Vector3 integratedOmega = j_correctedOmega * dt;
  const Rot3 incrR = Rot3::Expmap(integratedOmega, D_incrR_integratedOmega); // expensive !!
  const Matrix3 incrRt = incrR.transpose();
  delRdelBiasOmega_ = incrRt * delRdelBiasOmega_
      - *D_incrR_integratedOmega * dt;

  double dt22 = 0.5 * dt * dt;
  const Matrix3 dRij = oldRij.matrix(); // expensive
  delPdelBiasAcc_ += delVdelBiasAcc_ * dt - dt22 * dRij;
  delPdelBiasOmega_ += dt * delVdelBiasOmega_ + dt22 * D_acc_biasOmega;
  delVdelBiasAcc_ += -dRij * dt;
  delVdelBiasOmega_ += D_acc_biasOmega * dt;
}
Ejemplo n.º 7
0
/* ************************************************************************* */
Vector3 Rot3::CayleyChart::Local(const Rot3& R, OptionalJacobian<3,3> H) {
  if (H) throw std::runtime_error("Rot3::CayleyChart::Local Derivative");
  // Create a fixed-size matrix
  Matrix3 A = R.matrix();
  // Mathematica closed form optimization (procrastination?) gone wild:
  const double a = A(0, 0), b = A(0, 1), c = A(0, 2);
  const double d = A(1, 0), e = A(1, 1), f = A(1, 2);
  const double g = A(2, 0), h = A(2, 1), i = A(2, 2);
  const double di = d * i, ce = c * e, cd = c * d, fg = f * g;
  const double M = 1 + e - f * h + i + e * i;
  const double K = -4.0 / (cd * h + M + a * M - g * (c + ce) - b * (d + di - fg));
  const double x = a * f - cd + f;
  const double y = b * f - ce - c;
  const double z = fg - di - d;
  return K * Vector3(x, y, z);
}
Ejemplo n.º 8
0
/* ************************************************************************* */
pair<Matrix3, Vector3> RQ(const Matrix3& A) {

  double x = -atan2(-A(2, 1), A(2, 2));
  Rot3 Qx = Rot3::Rx(-x);
  Matrix3 B = A * Qx.matrix();

  double y = -atan2(B(2, 0), B(2, 2));
  Rot3 Qy = Rot3::Ry(-y);
  Matrix3 C = B * Qy.matrix();

  double z = -atan2(-C(1, 0), C(1, 1));
  Rot3 Qz = Rot3::Rz(-z);
  Matrix3 R = C * Qz.matrix();

  Vector xyz = Vector3(x, y, z);
  return make_pair(R, xyz);
}
Ejemplo n.º 9
0
/* ************************************************************************* */
Matrix PoseRTV::RRTMnb(const Rot3& att) {
  return PoseRTV::RRTMnb(att.rpy());
}
Ejemplo n.º 10
0
//******************************************************************************
// charts
TEST(Manifold, DefaultChart) {

  //DefaultChart<Point2> chart1;
  EXPECT(traits<Point2>::Local(Point2(0, 0), Point2(1, 0)) == Vector2(1, 0));
  EXPECT(traits<Point2>::Retract(Point2(0, 0), Vector2(1, 0)) == Point2(1, 0));

  Vector v2(2);
  v2 << 1, 0;
  //DefaultChart<Vector2> chart2;
  EXPECT(assert_equal(v2, traits<Vector2>::Local(Vector2(0, 0), Vector2(1, 0))));
  EXPECT(traits<Vector2>::Retract(Vector2(0, 0), v2) == Vector2(1, 0));

  {
    typedef Matrix2 ManifoldPoint;
    ManifoldPoint m;
    //DefaultChart<ManifoldPoint> chart;
    m << 1, 3,
         2, 4;
    // m as per default is in column-major storage mode. So this yields a linear representation of (1, 2, 3, 4)!
    EXPECT(assert_equal(Vector(Vector4(1, 2, 3, 4)), Vector(traits<ManifoldPoint>::Local(ManifoldPoint::Zero(), m))));
    EXPECT(traits<ManifoldPoint>::Retract(m, Vector4(1, 2, 3, 4)) == 2 * m);
  }

  {
    typedef Eigen::Matrix<double, 1, 2> ManifoldPoint;
    ManifoldPoint m;
    //DefaultChart<ManifoldPoint> chart;
    m << 1, 2;
    EXPECT(assert_equal(Vector(Vector2(1, 2)), Vector(traits<ManifoldPoint>::Local(ManifoldPoint::Zero(), m))));
    EXPECT(traits<ManifoldPoint>::Retract(m, Vector2(1, 2)) == 2 * m);
  }

  {
    typedef Eigen::Matrix<double, 1, 1> ManifoldPoint;
    ManifoldPoint m;
    //DefaultChart<ManifoldPoint> chart;
    m << 1;
    EXPECT(assert_equal(Vector(ManifoldPoint::Ones()), Vector(traits<ManifoldPoint>::Local(ManifoldPoint::Zero(), m))));
    EXPECT(traits<ManifoldPoint>::Retract(m, ManifoldPoint::Ones()) == 2 * m);
  }

  //DefaultChart<double> chart3;
  Vector v1(1);
  v1 << 1;
  EXPECT(assert_equal(v1, traits<double>::Local(0, 1)));
  EXPECT_DOUBLES_EQUAL(traits<double>::Retract(0, v1), 1, 1e-9);

  // Dynamic does not work yet !
  Vector z = zero(2), v(2);
  v << 1, 0;
  //DefaultChart<Vector> chart4;
//  EXPECT(assert_equal(traits<Vector>::Local(z, v), v));
//  EXPECT(assert_equal(traits<Vector>::Retract(z, v), v));

  Vector v3(3);
  v3 << 1, 1, 1;
  Rot3 I = Rot3::identity();
  Rot3 R = I.retract(v3);
  //DefaultChart<Rot3> chart5;
  EXPECT(assert_equal(v3, traits<Rot3>::Local(I, R)));
  EXPECT(assert_equal(traits<Rot3>::Retract(I, v3), R));
  // Check zero vector
  //DefaultChart<Rot3> chart6;
  EXPECT(assert_equal(zero(3), traits<Rot3>::Local(R, R)));
}
Ejemplo n.º 11
0
void StateEstimator::optimizationLoop()
{
  ISAM2Params parameters;
  // parameters.relinearizeThreshold = 0.0; // Set the relin threshold to zero such that the batch estimate is recovered
  // parameters.relinearizeSkip = 1; // Relinearize every time
  gtsam::IncrementalFixedLagSmoother graph(optLag_, parameters);

  double startTime;
  sensor_msgs::ImuConstPtr lastImu;
  double lastImuT;
  int imuKey = 1;
  int gpsKey = 1;

  // first we will initialize the graph with appropriate priors
  NonlinearFactorGraph newFactors;
  Values newVariables;
  FixedLagSmoother::KeyTimestampMap newTimestamps;

  sensor_msgs::NavSatFixConstPtr fix = gpsQ_.pop();
  startTime = ROS_TIME(fix);
  enu_.Reset(fix->latitude, fix->longitude, fix->altitude);

  sensor_msgs::ImuConstPtr imu = imuQ_.pop();
  lastImu = imu;
  lastImuT = ROS_TIME(imu) - 1 / imuFreq_;
  Rot3 initialOrientation =
      Rot3::Quaternion(imu->orientation.w, imu->orientation.x, imu->orientation.y, imu->orientation.z);

  // we set out initial position to the origin and assume we are stationary
  Pose3 x0(initialOrientation, Point3(0, 0, 0));
  PriorFactor<Pose3> priorPose(X(0), x0,
                               noiseModel::Diagonal::Sigmas((Vector(6) << priorOSigma_, priorOSigma_, priorOSigma_,
                                                             priorPSigma_, priorPSigma_, priorPSigma_)
                                                                .finished()));
  newFactors.add(priorPose);

  Vector3 v0 = Vector3(0, 0, 0);
  PriorFactor<Vector3> priorVel(
      V(0), v0, noiseModel::Diagonal::Sigmas((Vector(3) << priorVSigma_, priorVSigma_, priorVSigma_).finished()));
  newFactors.add(priorVel);

  imuBias::ConstantBias b0((Vector(6) << 0, 0, 0, 0, 0, 0).finished());
  PriorFactor<imuBias::ConstantBias> priorBias(
      B(0), b0,
      noiseModel::Diagonal::Sigmas(
          (Vector(6) << priorABias_, priorABias_, priorABias_, priorGBias_, priorGBias_, priorGBias_).finished()));
  newFactors.add(priorBias);

  noiseModel::Diagonal::shared_ptr imuToGpsFactorNoise = noiseModel::Diagonal::Sigmas(
      (Vector(6) << gpsTSigma_, gpsTSigma_, gpsTSigma_, gpsTSigma_, gpsTSigma_, gpsTSigma_).finished());
  newFactors.add(BetweenFactor<Pose3>(X(0), G(0), imuToGps_, imuToGpsFactorNoise));

  newVariables.insert(X(0), x0);
  newVariables.insert(V(0), v0);
  newVariables.insert(B(0), b0);
  newVariables.insert(G(0), x0.compose(imuToGps_));

  newTimestamps[X(0)] = 0;
  newTimestamps[G(0)] = 0;
  newTimestamps[V(0)] = 0;
  newTimestamps[B(0)] = 0;

  graph.update(newFactors, newVariables);  //, newTimestamps);

  Pose3 prevPose = prevPose_ = x0;
  Vector3 prevVel = prevVel_ = v0;
  imuBias::ConstantBias prevBias = prevBias_ = b0;

  // remove old imu messages
  while (!imuQ_.empty() && ROS_TIME(imuQ_.front()) < ROS_TIME(fix))
  {
    lastImuT = ROS_TIME(lastImu);
    lastImu = imuQ_.pop();
  }

  // setting up the IMU integration
  boost::shared_ptr<gtsam::PreintegrationParams> preintegrationParams =
      PreintegrationParams::MakeSharedU(gravityMagnitude_);
  preintegrationParams->accelerometerCovariance = accelSigma_ * I_3x3;
  preintegrationParams->gyroscopeCovariance = gyroSigma_ * I_3x3;
  preintegrationParams->integrationCovariance = imuIntSigma_ * I_3x3;

  PreintegratedImuMeasurements imuIntegrator(preintegrationParams, prevBias);

  Vector noiseModelBetweenBias =
      (Vector(6) << accelBSigma_, accelBSigma_, accelBSigma_, gyroBSigma_, gyroBSigma_, gyroBSigma_).finished();
  SharedDiagonal gpsNoise = noiseModel::Diagonal::Sigmas(Vector3(gpsSigma_, gpsSigma_, 3 * gpsSigma_));

  newFactors.resize(0);
  newVariables.clear();
  newTimestamps.clear();

  // now we loop and let use the queues to grab messages
  while (ros::ok())
  {
    bool optimize = false;

    // integrate imu messages
    while (!imuQ_.empty() && ROS_TIME(imuQ_.back()) > (startTime + 0.1 * imuKey) && !optimize)
    {
      double curTime = startTime + 0.1 * imuKey;
      // we reset the integrator, then integrate
      imuIntegrator.resetIntegrationAndSetBias(prevBias);

      while (ROS_TIME(lastImu) < curTime)
      {
        double dt = ROS_TIME(lastImu) - lastImuT;
        imuIntegrator.integrateMeasurement(
            Vector3(lastImu->linear_acceleration.x, lastImu->linear_acceleration.y, lastImu->linear_acceleration.z),
            Vector3(lastImu->angular_velocity.x, lastImu->angular_velocity.y, lastImu->angular_velocity.z), dt);
        lastImuT = ROS_TIME(lastImu);
        lastImu = imuQ_.pop();
      }

      // now put this into the graph
      ImuFactor imuf(X(imuKey - 1), V(imuKey - 1), X(imuKey), V(imuKey), B(imuKey - 1), imuIntegrator);
      newFactors.add(imuf);
      newFactors.add(BetweenFactor<imuBias::ConstantBias>(
          B(imuKey - 1), B(imuKey), imuBias::ConstantBias(),
          noiseModel::Diagonal::Sigmas(sqrt(imuIntegrator.deltaTij()) * noiseModelBetweenBias)));

      Rot3 orientation = Rot3::Quaternion(lastImu->orientation.w, lastImu->orientation.x, lastImu->orientation.y,
                                          lastImu->orientation.z);
      // std::cout << "adding orientation: " << orientation.xyz() << std::endl;
      newFactors.add(UnaryRotationFactor(X(imuKey), orientation.yaw(),
                                         noiseModel::Diagonal::Sigmas((Vector(1) << yawSigma_).finished())));

      NavState cur(prevPose, prevVel);
      NavState next = imuIntegrator.predict(cur, prevBias);
      prevPose = next.pose();
      prevVel = next.v();
      newVariables.insert(X(imuKey), prevPose);
      newVariables.insert(G(imuKey), prevPose.compose(imuToGps_));
      newVariables.insert(V(imuKey), prevVel);
      newVariables.insert(B(imuKey), prevBias);

      Pose3 temp = prevPose.compose(imuToGps_);
      std::cout << "imu(" << imuKey << "): " << temp.x() << " " << temp.y() << " " << temp.z() << std::endl;

      // for marginalizing out past the time window
      newTimestamps[X(imuKey)] = 0.1 * imuKey;
      newTimestamps[G(imuKey)] = 0.1 * imuKey;
      newTimestamps[V(imuKey)] = 0.1 * imuKey;
      newTimestamps[B(imuKey)] = 0.1 * imuKey;
      ++imuKey;
      optimize = true;
    }

    while (!gpsQ_.empty() && gpsKey < imuKey && optimize && ROS_TIME(gpsQ_.back()) > (startTime + gpsKey * 0.1))
    {
      fix = gpsQ_.pop();
      // we don't want all gps messages, just ones that are very close to the factors (10 hz)
      if (std::abs(ROS_TIME(fix) - (startTime + gpsKey * 0.1)) > 1e-2)
        continue;

      double E, N, U;
      enu_.Forward(fix->latitude, fix->longitude, fix->altitude, E, N, U);
      // we should maybe do a check on the GPS to make sure it's valid
      newFactors.add(GPSFactor(G(gpsKey), Point3(E, N, U), gpsNoise));
      newFactors.add(BetweenFactor<Pose3>(X(gpsKey), G(gpsKey), imuToGps_, imuToGpsFactorNoise));
      std::cout << "gps(" << gpsKey << "): " << E << " " << N << " " << U << std::endl;
      ++gpsKey;
    }

    if (!optimize)
      continue;

    try
    {
      graph.update(newFactors, newVariables);  //, newTimestamps);

      prevPose = graph.calculateEstimate<Pose3>(X(imuKey - 1));
      prevVel = graph.calculateEstimate<Vector3>(V(imuKey - 1));
      prevBias = graph.calculateEstimate<imuBias::ConstantBias>(B(imuKey - 1));

      // pass this to the other thread
      {
        std::lock_guard<std::mutex> lock(mutex_);
        prevPose_ = prevPose;
        prevVel_ = prevVel;
        prevBias_ = prevBias;
        currentTime_ = (imuKey - 1) * 0.1 + startTime;
        doneFirstOpt_ = true;
      }
    }
    catch (IndeterminantLinearSystemException ex)
    {
      // optimization blew up, not much to do just warn user
      ROS_ERROR("Indeterminant linear system error");
    }

    newFactors.resize(0);
    newVariables.clear();
    newTimestamps.clear();
  }
}
Ejemplo n.º 12
0
Vec3F toGlobal(Vec3F const & a, Rot3<float> const & r) {
  return r.rotateBack(a);
}
Ejemplo n.º 13
0
void go() {

  typedef Vec4<T> Vec;
  typedef Vec2<T> Vec2D;

  std::cout << std::endl;
  std::cout << sizeof(Vec) << std::endl;
  std::vector<Vec> vec1; vec1.reserve(50);
  std::vector<T> vect(23);
  std::vector<Vec> vec2(53);
  std::vector<Vec> vec3; vec3.reserve(50234);


  Vec x(2.0,4.0,5.0);
  Vec y(-3.0,2.0,-5.0);
  std::cout << x << std::endl;
  std::cout << Vec4<float>(x) << std::endl;
  std::cout << Vec4<double>(x) << std::endl;
  std::cout << -x << std::endl;
  std::cout << x.template get1<2>() << std::endl;
  std::cout << y << std::endl;
  std::cout << T(3.)*x << std::endl;
  std::cout << y*T(0.1) << std::endl;
  std::cout << (Vec(1) - y*T(0.1)) << std::endl;
  std::cout <<  mathSSE::sqrt(x) << std::endl;


  std::cout << dot(x,y) << std::endl; 
  std::cout << dotSimple(x,y) << std::endl;

  std::cout << "equal" << (x==x ? " " : " not ") << "ok" << std::endl;
  std::cout << "not equal" << (x==y ? " not " : " ") << "ok" << std::endl;
 
  Vec z = cross(x,y);
  std::cout << z << std::endl;


  std::cout << "rotations" << std::endl;

  T a = 0.01;
  T ca = std::cos(a);
  T sa = std::sin(a);

  Rot3<T> r1( ca, sa, 0,
	      -sa, ca, 0,
	      0,  0, 1);

  Rot2<T> r21( ca, sa,
	       -sa, ca);

  Rot3<T> r2(Vec( 0, 1 ,0), Vec( 0, 0, 1), Vec( 1, 0, 0));
  Rot2<T> r22(Vec2D( 0, 1), Vec2D( 1, 0));

  {
    std::cout << "\n3D rot" << std::endl;
    Vec xr = r1.rotate(x);
    std::cout << x << std::endl;
    std::cout << xr << std::endl;
    std::cout << r1.rotateBack(xr) << std::endl;
    
    Rot3<T> rt = r1.transpose();
    Vec xt = rt.rotate(xr);
    std::cout << x << std::endl;
    std::cout << xt << std::endl;
    std::cout << rt.rotateBack(xt) << std::endl;
    
    std::cout << r1 << std::endl;
    std::cout << rt << std::endl;
    std::cout << r1*rt << std::endl;
    std::cout << r2 << std::endl;
    std::cout << r1*r2 << std::endl;
    std::cout << r2*r1 << std::endl;
    std::cout << r1*r2.transpose() << std::endl;
    std::cout << r1.transpose()*r2 << std::endl;
  }

  {
    std::cout << "\n2D rot" << std::endl;
    Vec2D xr = r21.rotate(x.xy());
    std::cout << x.xy() << std::endl;
    std::cout << xr << std::endl;
    std::cout << r21.rotateBack(xr) << std::endl;
    
    Rot2<T> rt = r21.transpose();
    Vec2D xt = rt.rotate(xr);
    std::cout << x.xy() << std::endl;
    std::cout << xt << std::endl;
    std::cout << rt.rotateBack(xt) << std::endl;
    
    std::cout << r21 << std::endl;
    std::cout << rt << std::endl;
    std::cout << r21*rt << std::endl;
    std::cout << r22 << std::endl;
    std::cout << r21*r22 << std::endl;
    std::cout << r22*r21 << std::endl;
    std::cout << r21*r22.transpose() << std::endl;
    std::cout << r21.transpose()*r22 << std::endl;
  }


}
Ejemplo n.º 14
0
void Masseuse::Relax() {


  if(!graph->size() || !values->size()){
    std::cerr << "Pose graph not loaded. Load poses using 'LoadPosesFromFile'" <<
                 " before calling Relax()" << std::endl;
    throw runtime_error("Initial values or graph empty. Nothing to relax.");

  }

  // Global problem
  ceres::Problem problem;

  // Build the problem with the given pose graph

  if(options.enable_prior_at_origin && !options.fix_first_pose){
    // Add a prior at the origin:
    Point3 p = origin.head<3>();
    Rot3 rot(origin[3], origin[4], origin[5]);
    Pose3 orig(rot, p);

    Eigen::Vector6d cov_vec;
    cov_vec << 1e-6, 1e-6, 1e-6, 1e-4, 1e-4, 1e-4;
    Eigen::MatrixXd m = cov_vec.asDiagonal();

    Matrix sqrt_information_matrix = inverseSqrt(m);

    ceres::CostFunction* prior_cost_function =
        new ceres::AutoDiffCostFunction<PriorPoseCostFunctor<double>,
        Sophus::SE3::DoF,
        Sophus::SE3::num_parameters>
        (new PriorPoseCostFunctor<double>(orig, sqrt_information_matrix));

    problem.AddResidualBlock(prior_cost_function, NULL,
                             values->begin()->second.data());

  }

  // Now add a binary constraint for all relative and loop closure constraints
  for(Factor& f : *graph){

    Pose3& T_a = values->at(f.id1);
    Pose3& T_b = values->at(f.id2);

    Matrix sqrt_information_matrix = inverseSqrt(f.cov);

    if(options.enable_switchable_constraints && f.isLCC){
      // Use switchable constraints to selectively disable bad LCC's
      // during the optimization, see:
      // 'Switchable Constraints for Robust Pose Graph SLAM'
      ceres::CostFunction* binary_cost_function =
          new ceres::AutoDiffCostFunction<SwitchableBinaryPoseCostFunctor
          <double>, Sophus::SE3::DoF,
          Sophus::SE3::num_parameters,
          Sophus::SE3::num_parameters,
          1>
          (new SwitchableBinaryPoseCostFunctor<double>(f.rel_pose,
                                                       sqrt_information_matrix));


      HuberLoss* loss = new HuberLoss(options.huber_loss_delta);

      problem.AddResidualBlock(binary_cost_function, loss,
                               T_a.data(),
                               T_b.data(),
                               &f.switch_variable);

      // Constrain the switch variable to be between 0 and 1
      problem.SetParameterLowerBound(&f.switch_variable, 0, 0.0);
      problem.SetParameterUpperBound(&f.switch_variable, 0, 1.0);

      // Add a prior to anchor the switch variable at its initial value
      ceres::CostFunction* prior_cost_function =
          new ceres::AutoDiffCostFunction<PriorCostFunctor<double>,
          1, 1>(new PriorCostFunctor<double>(f.switch_variable,
                                             options.switch_variable_prior_cov,
                                             0));

      problem.AddResidualBlock(prior_cost_function, NULL,
                               &f.switch_variable);

    }else{

      Matrix sqrt_information_matrix = inverseSqrt(f.cov);

      ceres::CostFunction* binary_cost_function =
          new ceres::AutoDiffCostFunction<BinaryPoseCostFunctor
          <double>, Sophus::SE3::DoF,
          Sophus::SE3::num_parameters,
          Sophus::SE3::num_parameters>
          (new BinaryPoseCostFunctor<double>(f.rel_pose, sqrt_information_matrix));

      HuberLoss* loss = new HuberLoss(options.huber_loss_delta);

      problem.AddResidualBlock(binary_cost_function, loss,
                               T_a.data(),
                               T_b.data());
    }


    if(options.enable_z_prior){
      // Add a prior on z so that it anchors the height to the initial value
      // this assumes roughly planar motion to avoid the z drift.

      double initial_z = origin[2]; // first three elements are x, y, z

      // The last parameter is the index of the z in the SO3 data structure
      // It is [i j k w x y z]
      ceres::CostFunction* prior_cost_function =
          new ceres::AutoDiffCostFunction<PriorCostFunctor<double>,
          1, 7>(new PriorCostFunctor<double>(initial_z,
                                             options.cov_z_prior,
                                             6));

      problem.AddResidualBlock(prior_cost_function, NULL,
                               T_b.data());

    }

  }

  if(options.fix_first_pose && problem.HasParameterBlock(values->begin()->second.data())){
    problem.SetParameterBlockConstant(values->begin()->second.data());
  }

  ceres::LocalParameterization* local_param =
      new ceres::AutoDiffLocalParameterization
      <Sophus::masseuse::AutoDiffLocalParamSE3, 7, 6>;

  for(auto &pair : *values){
    if(problem.HasParameterBlock(pair.second.data())){
      problem.SetParameterization(pair.second.data(),
                                  local_param);
    }
  }


  ceres::Solver::Options ceres_options;
  ceres_options.linear_solver_type = ceres::SPARSE_NORMAL_CHOLESKY;
  ceres_options.trust_region_strategy_type = ceres::LEVENBERG_MARQUARDT;
  ceres_options.minimizer_progress_to_stdout = options.print_minimizer_progress;
  ceres_options.max_num_iterations = options.num_iterations;
  ceres_options.update_state_every_iteration =
      options.update_state_every_iteration;
  ceres_options.check_gradients = options.check_gradients;
  ceres_options.function_tolerance = options.function_tolearnce;
  ceres_options.parameter_tolerance = options.parameter_tolerance;
  ceres_options.gradient_tolerance = options.gradient_tolerance;

  if(options.print_error_statistics){
    std::cerr << "BEFORE RELAXATION:" << std::endl;
    PrintErrorStatistics(*values);
    std::cerr << std::endl;

    //    if(options.enable_switchable_constraints){
    //      std::cerr << "switch variables BEFORE optimizing: " << std::endl;
    //      for(const Factor& f : *graph){
    //        if(f.isLCC){
    //          fprintf(stderr, "%1.3f ",
    //                  f.switch_variable);
    //        }
    //      }
    //      std::cerr << std::endl;
    //    }

    //    double initial_cost = 0.0;
    //    std::vector<double> residuals(problem.NumResiduals());
    //    problem.Evaluate(Problem::EvaluateOptions(), &initial_cost, &residuals
    //                     , NULL, NULL);


    //    std::cerr << "num residual blocks: " << problem.NumResidualBlocks() <<
    //                 std::endl;
    //    std::cerr << "Cost BEFORE optimizing: " << initial_cost << std::endl;

  }


  ceres::Solver::Summary summary;

  std::cerr << "Relaxing graph...." << std::endl;
  double ceres_time = masseuse::Tic();
  ceres::Solve(ceres_options, &problem, &summary);
  ceres_time = masseuse::Toc(ceres_time);
  fprintf(stderr, "Optimization finished in %fs \n",
          ceres_time);

  if(options.print_full_report){
    std::cerr << summary.FullReport() << std::endl;
  }

  if(options.print_brief_report){
    std::cerr << summary.BriefReport() << std::endl;
  }


  if(options.print_error_statistics){
    std::cerr << std::endl << "AFTER REALXATION:" << std::endl;
    PrintErrorStatistics(*values);

    //    if(options.enable_switchable_constraints){
    //      std::cerr << "switch variables AFTER optimizing: " << std::endl;
    //      for(const Factor& f : *graph){
    //        if(f.isLCC){
    //          fprintf(stderr, "%1.3f ",
    //                  f.switch_variable);
    //        }
    //      }
    //      std::cerr << std::endl;
    //    }

    //    double final_cost = 0.0;
    //    std::vector<double> residuals(problem.NumResiduals());
    //    problem.Evaluate(Problem::EvaluateOptions(), &final_cost, &residuals,
    //                     NULL, NULL);

    //std::cerr << "Cost AFTER optimizing: " << final_cost << std::endl;
    //    Eigen::Map<Eigen::VectorXd> vec_residuals(residuals.data(), residuals.size());
    //    std::cerr << "Residuals: " << vec_residuals << std::endl;

    problem.NumResiduals();
  }

  // Save optimization result in a binary file
  if(options.save_results_binary){
    output_abs_poses.clear();

    Eigen::Vector6d absPoseVec;
    ceres::Covariance::Options cov_options;
    ceres::Covariance covariance(cov_options);
    vector<pair<const double*, const double*> > covariance_blocks;


    for(const auto& kvp : *values){
      const Pose3& pose = kvp.second;
      Point3 p = pose.translation();
      Rot3 R = pose.so3();
      absPoseVec.head<3>() = p;
      // unpack Euler angles: roll, pitch, yaw
      absPoseVec.tail<3>() = R.matrix().eulerAngles(0, 1, 2);

      // Now get the covariance for this pose
      covariance_blocks.clear();
      covariance_blocks.push_back(std::make_pair(pose.data(), pose.data()));

      CHECK(covariance.Compute(covariance_blocks, &problem));

      double cov[6*6];
      covariance.GetCovarianceBlockInTangentSpace(
            pose.data(),
            pose.data(),
            cov);

      // convert to an Eigen matrix
      Eigen::Map < Eigen::Matrix<double, 6, 6, Eigen::RowMajor> > cov_mat(
            cov);

      AbsPose absPose(kvp.first, absPoseVec, cov_mat);
      output_abs_poses.push_back(absPose);
    }

    SaveAbsPG(options.binary_output_path);

  }
}
Ejemplo n.º 15
0
/* ************************************************************************* */
bool Rot3::equals(const Rot3 & R, double tol) const {
  return equal_with_abs_tol(matrix(), R.matrix(), tol);
}
Ejemplo n.º 16
0
Vec3F toLocal(Vec3F const & a, Rot3<float> const & r) {
  return r.rotate(a);
}
namespace example1 {

const string filename = findExampleDataFile("5pointExample1.txt");
SfM_data data;
bool readOK = readBAL(filename, data);
Rot3 c1Rc2 = data.cameras[1].pose().rotation();
Point3 c1Tc2 = data.cameras[1].pose().translation();
PinholeCamera<Cal3_S2> camera2(data.cameras[1].pose(), Cal3_S2());
EssentialMatrix trueE(c1Rc2, Unit3(c1Tc2));
double baseline = 0.1; // actual baseline of the camera

Point2 pA(size_t i) {
    return data.tracks[i].measurements[0].second;
}
Point2 pB(size_t i) {
    return data.tracks[i].measurements[1].second;
}
Vector vA(size_t i) {
    return EssentialMatrix::Homogeneous(pA(i));
}
Vector vB(size_t i) {
    return EssentialMatrix::Homogeneous(pB(i));
}

//*************************************************************************
TEST (EssentialMatrixFactor, testData) {
    CHECK(readOK);

    // Check E matrix
    Matrix expected(3, 3);
    expected << 0, 0, 0, 0, 0, -0.1, 0.1, 0, 0;
    Matrix aEb_matrix = skewSymmetric(c1Tc2.x(), c1Tc2.y(), c1Tc2.z())
                        * c1Rc2.matrix();
    EXPECT(assert_equal(expected, aEb_matrix, 1e-8));

    // Check some projections
    EXPECT(assert_equal(Point2(0, 0), pA(0), 1e-8));
    EXPECT(assert_equal(Point2(0, 0.1), pB(0), 1e-8));
    EXPECT(assert_equal(Point2(0, -1), pA(4), 1e-8));
    EXPECT(assert_equal(Point2(-1, 0.2), pB(4), 1e-8));

    // Check homogeneous version
    EXPECT(assert_equal(Vector3(-1, 0.2, 1), vB(4), 1e-8));

    // Check epipolar constraint
    for (size_t i = 0; i < 5; i++)
        EXPECT_DOUBLES_EQUAL(0, vA(i).transpose() * aEb_matrix * vB(i), 1e-8);

    // Check epipolar constraint
    for (size_t i = 0; i < 5; i++)
        EXPECT_DOUBLES_EQUAL(0, trueE.error(vA(i), vB(i)), 1e-7);
}

//*************************************************************************
TEST (EssentialMatrixFactor, factor) {
    for (size_t i = 0; i < 5; i++) {
        EssentialMatrixFactor factor(1, pA(i), pB(i), model1);

        // Check evaluation
        Vector expected(1);
        expected << 0;
        Matrix Hactual;
        Vector actual = factor.evaluateError(trueE, Hactual);
        EXPECT(assert_equal(expected, actual, 1e-7));

        // Use numerical derivatives to calculate the expected Jacobian
        Matrix Hexpected;
        typedef Eigen::Matrix<double,1,1> Vector1;
        Hexpected = numericalDerivative11<Vector1, EssentialMatrix>(
                        boost::bind(&EssentialMatrixFactor::evaluateError, &factor, _1,
                                    boost::none), trueE);

        // Verify the Jacobian is correct
        EXPECT(assert_equal(Hexpected, Hactual, 1e-8));
    }
}

//*************************************************************************
TEST (EssentialMatrixFactor, minimization) {
    // Here we want to optimize directly on essential matrix constraints
    // Yi Ma's algorithm (Ma01ijcv) is a bit cumbersome to implement,
    // but GTSAM does the equivalent anyway, provided we give the right
    // factors. In this case, the factors are the constraints.

    // We start with a factor graph and add constraints to it
    // Noise sigma is 1cm, assuming metric measurements
    NonlinearFactorGraph graph;
    for (size_t i = 0; i < 5; i++)
        graph.add(EssentialMatrixFactor(1, pA(i), pB(i), model1));

    // Check error at ground truth
    Values truth;
    truth.insert(1, trueE);
    EXPECT_DOUBLES_EQUAL(0, graph.error(truth), 1e-8);

    // Check error at initial estimate
    Values initial;
    EssentialMatrix initialE = trueE.retract(
                                   (Vector(5) << 0.1, -0.1, 0.1, 0.1, -0.1).finished());
    initial.insert(1, initialE);
#if defined(GTSAM_ROT3_EXPMAP) || defined(GTSAM_USE_QUATERNIONS)
    EXPECT_DOUBLES_EQUAL(643.26, graph.error(initial), 1e-2);
#else
    EXPECT_DOUBLES_EQUAL(639.84, graph.error(initial), 1e-2);
#endif

    // Optimize
    LevenbergMarquardtParams parameters;
    LevenbergMarquardtOptimizer optimizer(graph, initial, parameters);
    Values result = optimizer.optimize();

    // Check result
    EssentialMatrix actual = result.at<EssentialMatrix>(1);
    EXPECT(assert_equal(trueE, actual, 1e-1));

    // Check error at result
    EXPECT_DOUBLES_EQUAL(0, graph.error(result), 1e-4);

    // Check errors individually
    for (size_t i = 0; i < 5; i++)
        EXPECT_DOUBLES_EQUAL(0, actual.error(vA(i), vB(i)), 1e-6);

}

//*************************************************************************
TEST (EssentialMatrixFactor2, factor) {
    for (size_t i = 0; i < 5; i++) {
        EssentialMatrixFactor2 factor(100, i, pA(i), pB(i), model2);

        // Check evaluation
        Point3 P1 = data.tracks[i].p, P2 = data.cameras[1].pose().transform_to(P1);
        const Point2 pi = PinholeBase::Project(P2);
        Point2 reprojectionError(pi - pB(i));
        Vector expected = reprojectionError.vector();

        Matrix Hactual1, Hactual2;
        double d(baseline / P1.z());
        Vector actual = factor.evaluateError(trueE, d, Hactual1, Hactual2);
        EXPECT(assert_equal(expected, actual, 1e-7));

        // Use numerical derivatives to calculate the expected Jacobian
        Matrix Hexpected1, Hexpected2;
        boost::function<Vector(const EssentialMatrix&, double)> f = boost::bind(
                    &EssentialMatrixFactor2::evaluateError, &factor, _1, _2, boost::none,
                    boost::none);
        Hexpected1 = numericalDerivative21<Vector2, EssentialMatrix, double>(f, trueE, d);
        Hexpected2 = numericalDerivative22<Vector2, EssentialMatrix, double>(f, trueE, d);

        // Verify the Jacobian is correct
        EXPECT(assert_equal(Hexpected1, Hactual1, 1e-8));
        EXPECT(assert_equal(Hexpected2, Hactual2, 1e-8));
    }
}

//*************************************************************************
TEST (EssentialMatrixFactor2, minimization) {
    // Here we want to optimize for E and inverse depths at the same time

    // We start with a factor graph and add constraints to it
    // Noise sigma is 1cm, assuming metric measurements
    NonlinearFactorGraph graph;
    for (size_t i = 0; i < 5; i++)
        graph.add(EssentialMatrixFactor2(100, i, pA(i), pB(i), model2));

    // Check error at ground truth
    Values truth;
    truth.insert(100, trueE);
    for (size_t i = 0; i < 5; i++) {
        Point3 P1 = data.tracks[i].p;
        truth.insert(i, double(baseline / P1.z()));
    }
    EXPECT_DOUBLES_EQUAL(0, graph.error(truth), 1e-8);

    // Optimize
    LevenbergMarquardtParams parameters;
    // parameters.setVerbosity("ERROR");
    LevenbergMarquardtOptimizer optimizer(graph, truth, parameters);
    Values result = optimizer.optimize();

    // Check result
    EssentialMatrix actual = result.at<EssentialMatrix>(100);
    EXPECT(assert_equal(trueE, actual, 1e-1));
    for (size_t i = 0; i < 5; i++)
        EXPECT_DOUBLES_EQUAL(truth.at<double>(i), result.at<double>(i), 1e-1);

    // Check error at result
    EXPECT_DOUBLES_EQUAL(0, graph.error(result), 1e-4);
}

//*************************************************************************
// Below we want to optimize for an essential matrix specified in a
// body coordinate frame B which is rotated with respect to the camera
// frame C, via the rotation bRc.

// The "true E" in the body frame is then
EssentialMatrix bodyE = cRb.inverse() * trueE;

//*************************************************************************
TEST (EssentialMatrixFactor3, factor) {

    for (size_t i = 0; i < 5; i++) {
        EssentialMatrixFactor3 factor(100, i, pA(i), pB(i), cRb, model2);

        // Check evaluation
        Point3 P1 = data.tracks[i].p;
        const Point2 pi = camera2.project(P1);
        Point2 reprojectionError(pi - pB(i));
        Vector expected = reprojectionError.vector();

        Matrix Hactual1, Hactual2;
        double d(baseline / P1.z());
        Vector actual = factor.evaluateError(bodyE, d, Hactual1, Hactual2);
        EXPECT(assert_equal(expected, actual, 1e-7));

        // Use numerical derivatives to calculate the expected Jacobian
        Matrix Hexpected1, Hexpected2;
        boost::function<Vector(const EssentialMatrix&, double)> f = boost::bind(
                    &EssentialMatrixFactor3::evaluateError, &factor, _1, _2, boost::none,
                    boost::none);
        Hexpected1 = numericalDerivative21<Vector2, EssentialMatrix, double>(f, bodyE, d);
        Hexpected2 = numericalDerivative22<Vector2, EssentialMatrix, double>(f, bodyE, d);

        // Verify the Jacobian is correct
        EXPECT(assert_equal(Hexpected1, Hactual1, 1e-8));
        EXPECT(assert_equal(Hexpected2, Hactual2, 1e-8));
    }
}

//*************************************************************************
TEST (EssentialMatrixFactor3, minimization) {

    // As before, we start with a factor graph and add constraints to it
    NonlinearFactorGraph graph;
    for (size_t i = 0; i < 5; i++)
        // but now we specify the rotation bRc
        graph.add(EssentialMatrixFactor3(100, i, pA(i), pB(i), cRb, model2));

    // Check error at ground truth
    Values truth;
    truth.insert(100, bodyE);
    for (size_t i = 0; i < 5; i++) {
        Point3 P1 = data.tracks[i].p;
        truth.insert(i, double(baseline / P1.z()));
    }
    EXPECT_DOUBLES_EQUAL(0, graph.error(truth), 1e-8);

    // Optimize
    LevenbergMarquardtParams parameters;
    // parameters.setVerbosity("ERROR");
    LevenbergMarquardtOptimizer optimizer(graph, truth, parameters);
    Values result = optimizer.optimize();

    // Check result
    EssentialMatrix actual = result.at<EssentialMatrix>(100);
    EXPECT(assert_equal(bodyE, actual, 1e-1));
    for (size_t i = 0; i < 5; i++)
        EXPECT_DOUBLES_EQUAL(truth.at<double>(i), result.at<double>(i), 1e-1);

    // Check error at result
    EXPECT_DOUBLES_EQUAL(0, graph.error(result), 1e-4);
}

} // namespace example1