- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我对一个 bug 感到困惑,在这个 bug 中,结构的成员有时会被调用一个库函数覆盖,而这个库函数本不应该与它有任何关系。
在看似随机调用 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
...
最佳答案
一个问题是这一行:
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();
关于c++ - 结构被库函数覆盖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48352957/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!