结构被库函数覆盖

时间:2018-01-20 05:33:38

标签: c++ arduino

我对一个错误感到困惑,因为一个结构的成员有时会被一个与它无关的库函数调用所覆盖。

在看似随机数量的Navagator :: update()调用之后,GPS.parse(GPS.lastNMEA())行将覆盖导航器对象的路点变量指向的内容。

这个错误很奇怪,我有可能在某个地方放错了指针吗?

// TransAt.ino
// ---------------------
#include "motors.h"
#include "navagator.h"

Navagator* nav;
Waypoint w = { 43.36, -75.1 };

uint32_t timer = millis();

void setup()
{
  Serial.begin(115200);
  Serial.println("MIT TransAt Vehicle Debugging");

  nav = &Navagator(&w, 1);

  Serial.print("\Setup 1 Loc: "); Serial.print(nav->waypoints->lat);
  Serial.print(", "); Serial.println(nav->waypoints->lon);

  Serial.print("\nSetup 2 Loc: "); Serial.print(nav->waypoints->lat);
  Serial.print(", "); Serial.println(nav->waypoints->lon);

}

void loop() 
{ 
  Serial.print("\nOuter Loop 1 Loc: "); Serial.print(nav->waypoints->lat);
  Serial.print(", "); Serial.println(nav->waypoints->lon);

  nav->update();

  Serial.print("\nOuter Loop 2 Loc: "); Serial.print(nav->waypoints->lat);
  Serial.print(", "); Serial.println(nav->waypoints->lon);

  //delay(100000);

  if (timer > millis()) timer = millis();

  if (millis() - timer > 2000) {
    Serial.print("\nLoop 2 Loc: "); Serial.print(nav->waypoints->lat);
    Serial.print(", "); Serial.println(nav->waypoints->lon);

    timer = millis(); // reset the timer
    nav->diagnostic();

    Serial.print("\nLoop 3 Loc: "); Serial.print(nav->waypoints->lat);
    Serial.print(", "); Serial.println(nav->waypoints->lon);

    int course = nav->getCourse();
    Serial.println("\nCourse: "); Serial.println(course);

    Serial.print("\nLoop 4 Loc: "); Serial.print(nav->waypoints->lat);
    Serial.print(", "); Serial.println(nav->waypoints->lon);
  }

  Serial.print("\nLoop 5 Loc: "); Serial.print(nav->waypoints->lat);
  Serial.print(", "); Serial.println(nav->waypoints->lon);

}

-

// navagator.h
// ---------------------
#ifndef _NAVAGATOR_h
#define _NAVAGATOR_h

#if defined(ARDUINO) && ARDUINO >= 100
  #include "Arduino.h"
#else
  #include "WProgram.h"
#endif

#include <Adafruit_GPS.h>


struct Waypoint {
  double lat, lon;
};

class Navagator {
public:
  Navagator(Waypoint* w, int);
  int getCourse();  // Returns course to next waypoint (compass bearings 0-360 with 0 true North)
  void update();        // Updates navagator (Call this frequently in the main loop)
  void diagnostic();
  Waypoint* waypoints;  // Array of waypoints to pass through


private:
  int pointCount, next; // Number of waypoints, index of next waypoint
  int course;               // Last calculated course to waypoint

  bool checkWaypoint();
  void updateWaypoints();
  void startGPS();
  void updateGPS();
};


double degreesToRadians(double);
double radiansToDegrees(double);
int calculateCourse(double lat1, double lon1, double lat2, double lon2);
double calculateCoordinateDistance(double, double, double, double);
double getLatitude();
double getLongitude();

#endif

-

// 
// Library for navigator guiding the TransAt vehicle
// 
// Note:    The navigator uses 0-360 compass bearings with 0 equivalent to true North and assumes 1 degree of precision 
//          All distances are measured in km
//          The course is the ideal angle between the vehicle and a waypoint
// navagator.cpp
// -------------------

#include "navagator.h"
#include <math.h>

#define EARTH_RADIUS 6371 // in km
#define WAYPOINT_RADIUS 5 // in km

#include <Adafruit_GPS.h>
#define GPSSerial Serial3
Adafruit_GPS GPS(&GPSSerial);

Navagator::Navagator(Waypoint* w, int count) {
  waypoints = w; 
  pointCount = count;
  next = 0;                             // start with first waypoint
  course = 90;                          // Notice that initial course is due East
  startGPS();
}

// Returns course between 0-360 degrees, where 0 is true North
int Navagator::getCourse() {
  if (!GPS.fix) // Without a fix, continue along last course.
    return course;

  // Get coordinates (In decimal degrees)
  double waypointLon = waypoints->lon;
  double waypointLat = waypoints->lat;
  double currentLon = getLongitude();
  double currentLat = getLatitude();

  Serial.print("Waypoint Loc: "); Serial.print(waypoints->lat);
  Serial.print(", "); Serial.println(waypoints->lon);

  // Update course
  course = calculateCourse(currentLat, currentLon, waypointLat, waypointLon);
  return course;
}

// Passed coordinates in decimal degrees
// Returns course in integer compass bearings
int  calculateCourse(double lat1, double lon1, double lat2, double lon2) {
  // From https://www.movable-type.co.uk/scripts/latlong.html

  // Convert to radians
  lat1 = degreesToRadians(lat1);
  lon1 = degreesToRadians(lon1);
  lat2 = degreesToRadians(lat2);
  lon2 = degreesToRadians(lon2);

  double y = sin(lon2 - lon1) * cos(lat2);
  double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(lon2 - lon1);
  int course = ((int)radiansToDegrees(atan2(y, x)) + 360) % 360;                // We convert the -pi to pi result of atan2 to 360 degree compass bearings

  return course;
}

// Call this from the main loop to keep navigation up to date
void Navagator::update() {

  Serial.print("Update 1 Loc: "); Serial.print(waypoints->lat);
  Serial.print(", "); Serial.println(waypoints->lon);

  updateGPS();

  Serial.print("Update 2 Loc: "); Serial.print(waypoints->lat);
  Serial.print(", "); Serial.println(waypoints->lon);

  updateWaypoints();

  Serial.print("Update 3 Loc: "); Serial.print(waypoints->lat);
  Serial.print(", "); Serial.println(waypoints->lon);
}

void Navagator::updateWaypoints() {
  if (checkWaypoint()) {            // If we've reached a waypoint

    if (next + 1 < pointCount)  // If there are more waypoints,
      next++;                   // Move to the next waypoint (Else, keep seeking the last waypoint)
  }
}

// Returns true if we've reached the next waypoint, else false
bool Navagator::checkWaypoint() {
  if (!GPS.fix)     // Without a fix, assume we haven't reached a waypoint
    return false;

  // Get coordinates
  double waypointLon = (waypoints + next)->lon;
  double waypointLat = (waypoints + next)->lat;
  double currentLon = getLongitude();
  double currentLat = getLatitude();

  // Return if distance between them is less than the waypoint 
  return calculateCoordinateDistance(currentLat, currentLon, waypointLat, waypointLon) < WAYPOINT_RADIUS;
}

// Takes coordinates in decimal degrees
// Returns distance between in km
double calculateCoordinateDistance(double lat1, double lon1, double lat2, double lon2) {
  // Halversine Formula https://www.movable-type.co.uk/scripts/latlong.html

  // Convert to radians
  lat1 = degreesToRadians(lat1);
  lon1 = degreesToRadians(lon1);
  lat2 = degreesToRadians(lat2);
  lon2 = degreesToRadians(lon2);

  // Find distance on unit sphere
  double a = pow(sin((lat2 - lat1) / 2), 2) + cos(lat1) * cos(lat2) * pow(sin((lon2 - lon1) / 2), 2);   // For right triangle with sides a, b, and c
  double c = 2 * atan2(sqrt(a), sqrt(1 - a));

  return EARTH_RADIUS * c;
}

double degreesToRadians(double degrees) {
  return degrees * M_PI / 180;
}

double radiansToDegrees(double radians) {
  return radians * 180 / M_PI;
}

// Provides decimal degree latitude with ~1km of precision
double getLatitude() {
  double lat = GPS.latitude_fixed;

  if (GPS.lat == 'S') { // Note we're doing a character comparision here so the == is appropriate
    lat = -lat;         // Southern latitudes are negative
  }

  return lat / 10000000.0;
}

// Provides decimal degree latitude with ~1km of precision
double getLongitude() {
  double lon = GPS.longitude_fixed;

  if (GPS.lon == 'W') { // Note we're doing a character comparision here so the == is appropriate
    lon = -lon;         // Western lattitudes are negative
  }

  return lon / 10000000.0;
}

// Configures and begins reading GPS
void Navagator::startGPS() {
  GPS.begin(9600);

  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA); // Turn on RMC (recommended minimum) and GGA (fix data) including altitude
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);        // 1 Hz update rate (In final version, these rates should be lowered and the interupt used less frequently to conserve clock cycles)
    delay(1000);

  // Create interrupt
  OCR0A = 0xAF;         // We'll use comparison register A (OCR0A) for the ATMega's ~1Hz Timer0 (When Timer0 == OCR0A == 0xAF, the interupt will fire)
  TIMSK0 |= _BV(OCIE0A);    // enable compare A interrupts 
              // Note: TIMSK0 is a macro for the 'Timer Interrupt Mask Register' and OCIE0A is the bit mask specifing 'Timer/Counter Output Compare Match A Interrupt'

  // Wait for GPS to get fix
  // Actually we can't do that
  // Trying to loop here produces weird behavior where nothing is printed to Serial or we never get any data from the gps
  // Possibly try to figure out what is going on later?
}

// Interrupt is called once a millisecond, looks for any new GPS data, and stores it
SIGNAL(TIMER0_COMPA_vect) {
  GPS.read();   // read any new GPS data (We still have to parse completed sentences in the main loop)
}

// Parses new NMEA sentences
void Navagator::updateGPS() {
  Serial.print("UpdateGPS 1 Loc: "); Serial.print(waypoints->lat);
  Serial.print(", "); Serial.println(waypoints->lon);
  if (GPS.newNMEAreceived())
    Serial.print("**UpdateGPS 2 Loc: "); Serial.print(waypoints->lat);
    Serial.print(", "); Serial.println(waypoints->lon);
    Serial.println(GPS.parse(GPS.lastNMEA()));

  Serial.print("UpdateGPS 3 Loc: "); Serial.print(waypoints->lat);
  Serial.print(", "); Serial.println(waypoints->lon);
}

void Navagator::diagnostic() {

  Serial.print("\nNav 1 Loc: "); Serial.print(waypoints->lat);
  Serial.print(", "); Serial.println(waypoints->lon);

  Serial.println("\n\nNavagation Diagnostic");
  Serial.print("Time: ");
  Serial.print(GPS.hour, DEC); Serial.print(':');
  Serial.print(GPS.minute, DEC); Serial.print(':');
  Serial.print(GPS.seconds, DEC); Serial.print('.');
  Serial.println(GPS.milliseconds);
  Serial.print("Date: ");
  Serial.print(GPS.day, DEC); Serial.print('/');
  Serial.print(GPS.month, DEC); Serial.print("/20");
  Serial.println(GPS.year, DEC);
  Serial.print("Fix: "); Serial.print((int)GPS.fix);
  Serial.print(" quality: "); Serial.println((int)GPS.fixquality);
  if (GPS.fix) {
    Serial.print("Location: ");
    Serial.print(getLatitude()); Serial.print(GPS.lat); // Decimal Degrees (1/10,000,000 of a degree)
    Serial.print(", ");
    Serial.print(getLongitude()); Serial.println(GPS.lon); // Decimal Degrees (1/10,000,000 of a degree)
    Serial.print("Speed (knots): "); Serial.println(GPS.speed);
    Serial.print("Angle: "); Serial.println(GPS.angle);
    Serial.print("Altitude: "); Serial.println(GPS.altitude);
    Serial.print("Satellites: "); Serial.println((int)GPS.satellites);
  }
  Serial.print("Waypoint: "); Serial.println(next);

  Serial.print("\nNav 2 Loc: "); Serial.print(waypoints->lat);
  Serial.print(", "); Serial.println(waypoints->lon);
}

-

输出

...

0
UpdateGPS 3 Loc: 43.36, -75.10
Update 2 Loc: 43.36, -75.10
Update 3 Loc: 43.36, -75.10

Outer Loop 2 Loc: 43.36, -75.10

Loop 5 Loc: 43.36, -75.10

Outer Loop 1 Loc: 43.36, -75.10
Update 1 Loc: 43.36, -75.10
UpdateGPS 1 Loc: 43.36, -75.10
**UpdateGPS 2 Loc: 43.36, -75.10
1
UpdateGPS 3 Loc: 0.00, 0.00
Update 2 Loc: 0.00, 0.00
Update 3 Loc: 0.00, 0.00

Outer Loop 2 Loc: 0.00, 0.00

Loop 5 Loc: 0.00, 0.00

Outer Loop 1 Loc: 0.00, 0.00
Update 1 Loc: 0.00, 0.00
UpdateGPS 1 Loc: 0.00, 0.00
0.00, 0.00
1
UpdateGPS 3 Loc: 0.00, 0.00
Update 2 Loc: 0.00, 0.00
Update 3 Loc: 0.00, 0.00

Outer Loop 2 Loc: 0.00, 0.00

Loop 5 Loc: 0.00, 0.00

Outer Loop 1 Loc: 0.00, 0.00
Update 1 Loc: 0.00, 0.00
UpdateGPS 1 Loc: 0.00, 0.00
0.00, 0.00
1

...

2 个答案:

答案 0 :(得分:2)

这一行有一个问题:

nav = &Navagator(&w, 1);

创建Navigator对象,然后立即销毁。它的一生就是那个陈述,所以你要记下那些不会出现的事情的地址。因此,如果您使用nav,程序将显示未定义的行为,假设它仍然指向某个有效的地方。

由于nav是指向Navigator的指针,并且您当前的程序将此声明为全局变量(有问题,但这是另一个故事),所以这是使用std::unique_ptr<Navigator>。这将允许动态创建Navigator,并在std::unique_ptr超出范围时(将在您的程序终止时)自动删除。

例如:

#include <memory>
//...
std::unique_ptr<Navigator> nav;

然后在setup()函数中:

nav = std::make_unique<Navigator>(&w, 1);

然后,如果您想要访问基础nav指针,请使用get()提供的std::unique_ptr函数:

Navigator* ptr = nav.get();

答案 1 :(得分:1)

非常感谢。

我以为我正在将导航分配到一个实例,但实际上我将它指向一个临时对象,这是我所有艰难的来源。

我可以使用new来创建对象,但我听说这不适用于微控制器,因此我会在全局范围内创建对象以避免此问题。