Program Listing for File novatel_gps.h

Return to documentation for file (/tmp/ws/src/novatel_gps_driver/novatel_gps_driver/include/novatel_gps_driver/novatel_gps.h)

// *****************************************************************************
//
// Copyright (c) 2019, Southwest Research Institute® (SwRI®)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Southwest Research Institute® (SwRI®) nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL SOUTHWEST RESEARCH INSTITUTE BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// *****************************************************************************

#ifndef NOVATEL_GPS_DRIVER_NOVATEL_GPS_H_
#define NOVATEL_GPS_DRIVER_NOVATEL_GPS_H_

// std libraries
#include <chrono>
#include <map>
#include <queue>
#include <string>
#include <vector>

// Boost
#include <boost/asio.hpp>
#include <boost/circular_buffer.hpp>

// ROS
#include <rclcpp/rclcpp.hpp>
#include <rclcpp/time.hpp>

// Messages
#include <gps_msgs/msg/gps_fix.hpp>

#include <novatel_gps_msgs/msg/gpgga.hpp>
#include <novatel_gps_msgs/msg/gprmc.hpp>

#include <sensor_msgs/msg/imu.hpp>

// Other libraries
#include <swri_serial_util/serial_port.h>

#include <pcap.h>

// Local include files
#include <novatel_gps_driver/novatel_message_extractor.h>
#include <novatel_gps_driver/parsers/bestpos.h>
#include <novatel_gps_driver/parsers/bestxyz.h>
#include <novatel_gps_driver/parsers/bestutm.h>
#include <novatel_gps_driver/parsers/bestvel.h>
#include <novatel_gps_driver/parsers/clocksteering.h>
#include <novatel_gps_driver/parsers/corrimudata.h>
#include <novatel_gps_driver/parsers/gpgga.h>
#include <novatel_gps_driver/parsers/gpgsa.h>
#include <novatel_gps_driver/parsers/gpgsv.h>
#include <novatel_gps_driver/parsers/gphdt.h>
#include <novatel_gps_driver/parsers/gprmc.h>
#include <novatel_gps_driver/parsers/heading2.h>
#include <novatel_gps_driver/parsers/dual_antenna_heading.h>
#include <novatel_gps_driver/parsers/inscov.h>
#include <novatel_gps_driver/parsers/inspva.h>
#include <novatel_gps_driver/parsers/inspvax.h>
#include <novatel_gps_driver/parsers/insstdev.h>
#include <novatel_gps_driver/parsers/range.h>
#include <novatel_gps_driver/parsers/psrdop2.h>
#include <novatel_gps_driver/parsers/time.h>
#include <novatel_gps_driver/parsers/trackstat.h>

namespace novatel_gps_driver
{
  typedef std::map<std::string, double> NovatelMessageOpts;

  class NovatelGps
  {
    public:
      enum ConnectionType { SERIAL, TCP, UDP, PCAP, INVALID };

      enum ReadResult
      {
        READ_SUCCESS = 0,
        READ_INSUFFICIENT_DATA = 1,
        READ_TIMEOUT = 2,
        READ_INTERRUPTED = 3,
        READ_ERROR = -1,
        READ_PARSE_FAILED = -2
      };

      explicit NovatelGps(rclcpp::Node& Node);
      ~NovatelGps();

      bool Connect(const std::string& device, ConnectionType connection);

      bool Connect(const std::string& device, ConnectionType connection, NovatelMessageOpts const& opts);

      void Disconnect();

      std::string ErrorMsg() const { return error_msg_; }

      void GetFixMessages(std::vector<gps_msgs::msg::GPSFix::UniquePtr>& fix_messages);
      void GetGpggaMessages(std::vector<novatel_gps_driver::GpggaParser::MessageType>& gpgga_messages);
      void GetGpgsaMessages(std::vector<novatel_gps_driver::GpgsaParser::MessageType>& gpgsa_messages);
      void GetGpgsvMessages(std::vector<novatel_gps_driver::GpgsvParser::MessageType>& gpgsv_messages);
      void GetGphdtMessages(std::vector<novatel_gps_driver::GphdtParser::MessageType>& gphdt_messages);
      void GetGprmcMessages(std::vector<novatel_gps_driver::GprmcParser::MessageType>& gprmc_messages);
      void GetNovatelHeading2Messages(std::vector<novatel_gps_driver::Heading2Parser::MessageType>& headings);
      void GetNovatelDualAntennaHeadingMessages(std::vector<novatel_gps_driver::DualAntennaHeadingParser::MessageType>& headings);
       void GetNovatelPsrdop2Messages(std::vector<novatel_gps_driver::Psrdop2Parser::MessageType>& psrdop2_messages);
      void GetImuMessages(std::vector<sensor_msgs::msg::Imu::SharedPtr>& imu_messages);
      void GetInscovMessages(std::vector<novatel_gps_driver::InscovParser::MessageType>& inscov_messages);
      void GetInspvaMessages(std::vector<novatel_gps_driver::InspvaParser::MessageType>& inspva_messages);
      void GetInspvaxMessages(std::vector<novatel_gps_driver::InspvaxParser::MessageType>& inspvax_messages);
      void GetInsstdevMessages(std::vector<novatel_gps_driver::InsstdevParser::MessageType>& insstdev_messages);
      void GetNovatelCorrectedImuData(std::vector<novatel_gps_driver::CorrImuDataParser::MessageType>& imu_messages);
      void GetNovatelPositions(std::vector<novatel_gps_driver::BestposParser::MessageType>& positions);
      void GetNovatelXYZPositions(std::vector<novatel_gps_driver::BestxyzParser::MessageType>& positions);
      void GetNovatelUtmPositions(std::vector<novatel_gps_driver::BestutmParser::MessageType>& utm_positions);
      void GetNovatelVelocities(std::vector<novatel_gps_driver::BestvelParser::MessageType>& velocities);
      void GetRangeMessages(std::vector<novatel_gps_driver::RangeParser::MessageType>& range_messages);
      void GetTimeMessages(std::vector<novatel_gps_driver::TimeParser::MessageType>& time_messages);
      void GetTrackstatMessages(std::vector<novatel_gps_driver::TrackstatParser::MessageType>& trackstat_msgs);
      void GetClockSteeringMessages(std::vector<novatel_gps_driver::ClockSteeringParser::MessageType>& clocksteering_msgs);

      bool IsConnected() { return is_connected_; }

      static ConnectionType ParseConnection(const std::string& connection);

      void ApplyVehicleBodyRotation(const bool& apply_rotation);

      ReadResult ProcessData();

      void SetImuRate(double imu_rate, bool force = true);

      void SetSerialBaud(int32_t serial_baud);

      bool Write(const std::string& command);

      double gpsfix_sync_tol_; //seconds
      bool wait_for_sync_; // wait until a bestvel has arrived before publishing bestpos

    private:
      bool Configure(NovatelMessageOpts const& opts);

      bool CreateIpConnection(const std::string& endpoint, NovatelMessageOpts const& opts);

      bool CreateSerialConnection(const std::string& device, NovatelMessageOpts const& opts);

      bool CreatePcapConnection(const std::string& device, NovatelMessageOpts const& opts);

      template<typename Input, typename Output>
      inline void DrainQueue(Input& in, Output& out)
      {
        out.clear();
        std::move(std::make_move_iterator(in.begin()),
            std::make_move_iterator(in.end()),
            std::back_inserter(out));
        in.clear();
      }

      void GenerateImuMessages();

      NovatelGps::ReadResult ParseBinaryMessage(const BinaryMessage& msg,
                                                const rclcpp::Time& stamp) noexcept(false);
      NovatelGps::ReadResult ParseNmeaSentence(const NmeaSentence& sentence,
                                               const rclcpp::Time& stamp,
                                               double most_recent_utc_time) noexcept(false);
      NovatelGps::ReadResult ParseNovatelSentence(const NovatelSentence& sentence,
                                                  const rclcpp::Time& stamp) noexcept(false);

      ReadResult ReadData();

      static constexpr uint16_t DEFAULT_TCP_PORT = 3001;
      static constexpr uint16_t DEFAULT_UDP_PORT = 3002;
      static constexpr size_t MAX_BUFFER_SIZE = 100;
      static constexpr size_t SYNC_BUFFER_SIZE = 10;
      static constexpr uint32_t SECONDS_PER_WEEK = 604800;
      static constexpr double IMU_TOLERANCE_S = 0.0002;
      static constexpr double DEGREES_TO_RADIANS = M_PI / 180.0;


      rclcpp::Node& node_;

      ConnectionType connection_;

      std::string error_msg_;

      bool is_connected_;
      bool imu_rate_forced_;

      double utc_offset_;

      // Serial connection
      int32_t serial_baud_;
      swri_serial_util::SerialPort serial_;

      // TCP / UDP connections
      boost::asio::io_service io_service_;
      boost::asio::ip::tcp::socket tcp_socket_;
      std::shared_ptr<boost::asio::ip::udp::socket> udp_socket_;
      std::shared_ptr<boost::asio::ip::udp::endpoint> udp_endpoint_;

      // Data buffers
      std::vector<uint8_t> data_buffer_;
      std::string nmea_buffer_;
      std::array<uint8_t, 10000> socket_buffer_;

      pcap_t* pcap_;
      bpf_program pcap_packet_filter_;
      char pcap_errbuf_[MAX_BUFFER_SIZE];
      std::vector<uint8_t> last_tcp_packet_;

      NovatelMessageExtractor extractor_;

      // Message parsers
      BestposParser bestpos_parser_;
      BestxyzParser bestxyz_parser_;
      BestutmParser bestutm_parser_;
      BestvelParser bestvel_parser_;
      Heading2Parser heading2_parser_;
      DualAntennaHeadingParser dual_antenna_heading_parser_;
      ClockSteeringParser clocksteering_parser_;
      CorrImuDataParser corrimudata_parser_;
      GpggaParser gpgga_parser_;
      GpgsaParser gpgsa_parser_;
      GpgsvParser gpgsv_parser_;
      GphdtParser gphdt_parser_;
      GprmcParser gprmc_parser_;
      InscovParser inscov_parser_;
      InspvaParser inspva_parser_;
      InspvaxParser inspvax_parser_;
      InsstdevParser insstdev_parser_;
      Psrdop2Parser psrdop2_parser_;
      RangeParser range_parser_;
      TimeParser time_parser_;
      TrackstatParser trackstat_parser_;

      // Message buffers
      boost::circular_buffer<novatel_gps_driver::ClockSteeringParser::MessageType> clocksteering_msgs_;
      boost::circular_buffer<novatel_gps_driver::CorrImuDataParser::MessageType> corrimudata_msgs_;
      boost::circular_buffer<novatel_gps_driver::GpggaParser::MessageType> gpgga_msgs_;
      boost::circular_buffer<novatel_gps_driver::GpgsaParser::MessageType> gpgsa_msgs_;
      boost::circular_buffer<novatel_gps_driver::GpgsvParser::MessageType> gpgsv_msgs_;
      boost::circular_buffer<novatel_gps_driver::GphdtParser::MessageType> gphdt_msgs_;
      boost::circular_buffer<novatel_gps_driver::GprmcParser::MessageType> gprmc_msgs_;
      boost::circular_buffer<sensor_msgs::msg::Imu::SharedPtr> imu_msgs_;
      boost::circular_buffer<novatel_gps_driver::InscovParser::MessageType> inscov_msgs_;
      boost::circular_buffer<novatel_gps_driver::InspvaParser::MessageType> inspva_msgs_;
      boost::circular_buffer<novatel_gps_driver::InspvaxParser::MessageType> inspvax_msgs_;
      boost::circular_buffer<novatel_gps_driver::InsstdevParser::MessageType> insstdev_msgs_;
      boost::circular_buffer<novatel_gps_driver::BestposParser::MessageType> novatel_positions_;
      boost::circular_buffer<novatel_gps_driver::BestxyzParser::MessageType> novatel_xyz_positions_;
      boost::circular_buffer<novatel_gps_driver::BestutmParser::MessageType> novatel_utm_positions_;
      boost::circular_buffer<novatel_gps_driver::BestvelParser::MessageType> novatel_velocities_;
      boost::circular_buffer<novatel_gps_driver::BestposParser::MessageType> bestpos_sync_buffer_;
      boost::circular_buffer<novatel_gps_driver::BestvelParser::MessageType> bestvel_sync_buffer_;
      boost::circular_buffer<novatel_gps_driver::Heading2Parser::MessageType> heading2_msgs_;
      boost::circular_buffer<novatel_gps_driver::DualAntennaHeadingParser::MessageType> dual_antenna_heading_msgs_;
      boost::circular_buffer<novatel_gps_driver::Psrdop2Parser::MessageType> psrdop2_msgs_;
      boost::circular_buffer<novatel_gps_driver::RangeParser::MessageType> range_msgs_;
      boost::circular_buffer<novatel_gps_driver::TimeParser::MessageType> time_msgs_;
      boost::circular_buffer<novatel_gps_driver::TrackstatParser::MessageType> trackstat_msgs_;

      novatel_gps_driver::Psrdop2Parser::MessageType latest_psrdop2_;

      // IMU data synchronization queues
      std::queue<novatel_gps_driver::CorrImuDataParser::MessageType> corrimudata_queue_;
      std::queue<novatel_gps_driver::InspvaParser::MessageType> inspva_queue_;
      novatel_gps_driver::InsstdevParser::MessageType latest_insstdev_;
      novatel_gps_driver::InscovParser::MessageType latest_inscov_;
      double imu_rate_;

      // Additional Options
      bool apply_vehicle_body_rotation_;
  };
}

#endif  //NOVATEL_GPS_DRIVER_NOVATEL_GPS_H_