Subversion Repositories Projects

Rev

Rev 2203 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2136 - 1
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3
 
4
//############################################################################
5
//# HISTORY  gps.c
6
//#
2200 - 7
//# 20.09.2015 Startet
8
//# - add Routine um einen Offset in Meter zu den aktuellen Koordinaten dazurechnen
9
//#    followme_calculate_offset(...)
10
//#
2136 - 11
//# 03.08.2015 cebra
12
//# - add: Routine um aus gegebenen Koordinaten mit Abstand und Winkel eine ZielKoordinate zu berechnen
13
//#    int nmea_move_horz(
14
//#    const nmeaPOS *start_pos,   /**< Start position in radians */
15
//#    nmeaPOS *end_pos,           /**< Result position in radians */
16
//#    double azimuth,             /**< Azimuth (degree) [0, 359] */
17
//#    double distance)             /**< Distance (km) */
18
//#
19
//# 27.06.2014 OG - NEU
20
//# - chg: auf #include "../gps/mymath.h" angepasst
21
//#
22
//# 20.06.2014 OG - NEU
23
//############################################################################
24
 
25
 
26
#include "../cpu.h"
27
#include <string.h>
28
#include <util/delay.h>
29
#include <avr/interrupt.h>
30
#include <stdlib.h>
31
#include <math.h>
32
#include "../main.h"
33
 
34
#include "../mk-data-structs.h"
35
#include "../gps/mymath.h"
36
#include "gps.h"
37
 
38
 
39
/*
40
// definiert in: mk_data-stucts.h
41
typedef struct
42
{
43
    u16 Distance;       // distance to target in cm
44
    s16 Bearing;        // course to target in deg
45
} __attribute__((packed)) GPS_PosDev_t;
46
*/
47
 
48
/*
49
// definiert in: mk_data-stucts.h
50
typedef struct
51
{
52
    s32 Longitude;      // in 1E-7 deg
53
    s32 Latitude;       // in 1E-7 deg
54
    s32 Altitude;       // in mm
55
    u8 Status;          // validity of data
56
} __attribute__((packed)) GPS_Pos_t;
57
*/
58
 
59
 
60
//--------------------------------------------------------------
61
 
62
#define NMEA_PI                     (3.141592653589793)             /**< PI value */
63
#define NMEA_PI180                  (NMEA_PI / 180)                 /**< PI division by 180 */
64
#define NMEA_EARTHRADIUS_KM         (6378)                          /**< Earth's mean radius in km */
65
#define R                           (6371)
66
#define NMEA_EARTHRADIUS_M          (NMEA_EARTHRADIUS_KM * 1000)    /**< Earth's mean radius in m */
67
#define NMEA_EARTH_SEMIMAJORAXIS_M  (6378137.0)                     /**< Earth's semi-major axis in m according WGS84 */
68
#define NMEA_EARTH_SEMIMAJORAXIS_KM (NMEA_EARTHMAJORAXIS_KM / 1000) /**< Earth's semi-major axis in km according WGS 84 */
69
#define NMEA_EARTH_FLATTENING       (1 / 298.257223563)             /**< Earth's flattening according WGS 84 */
70
#define NMEA_DOP_FACTOR             (5)                             /**< Factor for translating DOP to meters */
71
 
2196 - 72
 
73
// Definitonen für FollowMeStep2
74
#define LONG_DIV                    10000000
75
#define LAT_DIV                     LONG_DIV
2199 - 76
#define FOLLOWME_M2DEG              111111
77
#define FOLLOWME_ROUND_100          100
2196 - 78
 
79
 
2136 - 80
# define NMEA_POSIX(x)  x
81
 
82
 
83
 
84
/**
85
 * \fn nmea_degree2radian
86
 * \brief Convert degree to radian
87
 */
88
double nmea_degree2radian(double val)
89
{ return (val * NMEA_PI180); }
90
 
91
 
92
//------------------------------------------------------------------------------------------
93
nmeaPOS NMEApos;
94
nmeaPOS NMEATarget;
95
 
96
/**
97
 * \brief Horizontal move of point position
98
 */
99
int nmea_move_horz(
100
    const nmeaPOS *start_pos,   /**< Start position in radians */
101
    nmeaPOS *end_pos,           /**< Result position in radians */
102
    double azimuth,             /**< Azimuth (degree) [0, 359] */
103
    double distance             /**< Distance (km) */
104
    )
105
{
106
    nmeaPOS p1 = *start_pos;
107
    int RetVal = 1;
108
 
109
    distance /= NMEA_EARTHRADIUS_KM; /* Angular distance covered on earth's surface */
110
    azimuth = nmea_degree2radian(azimuth);
111
 
112
    end_pos->lat = asin( sin(p1.lat) * cos(distance) + cos(p1.lat) * sin(distance) * cos(azimuth));
113
 
114
    end_pos->lon = p1.lon + atan2( sin(azimuth) * sin(distance) * cos(p1.lat), cos(distance) - sin(p1.lat) * sin(end_pos->lat));
115
 
116
    if(NMEA_POSIX(isnan)(end_pos->lat) || NMEA_POSIX(isnan)(end_pos->lon))
117
    {
118
        end_pos->lat = 0; end_pos->lon = 0;
119
        RetVal = 0;
120
    }
121
 
122
    return RetVal;
123
}
124
 
125
 
2204 - 126
 
127
 
128
 
129
// Fügt den Startpostition einen Offset hinzu und gibt es als Zielposition zurück
130
//
2200 - 131
// Benutzt die c_cos_8192 der FC
132
// TODO: move to followme.c
2204 - 133
// TODO: *8192 optimieren
2136 - 134
 
2204 - 135
uint8_t followme_add_offset(
136
    const nmeaPOS *pPktPos,                     /**< Start position in radians */
137
    nmeaPOS *target_pos,                        /**< Result position in radians */
138
        positionOffset *pFollowMeOffset         /**< Position Offset in Millimeters */
2196 - 139
    )
140
{
2200 - 141
        nmeaPOS pktPos = *pPktPos;
2204 - 142
        positionOffset followMeOffset = * pFollowMeOffset;
2200 - 143
 
2204 - 144
    target_pos->lat = pktPos.lat + ( followMeOffset.offset_lat * 1000 * ( LAT_DIV  / FOLLOWME_M2DEG ) );
145
    target_pos->lon = pktPos.lon + ( followMeOffset.offset_long * 1000 * ( LONG_DIV  / FOLLOWME_M2DEG ) * 8192 ) / abs ( c_cos_8192( (int16_t)(pktPos.lat / LONG_DIV ) ) );
2196 - 146
 
147
        return 1;
148
}
149
 
150
 
2204 - 151
// Rechnet einen Offset aus Radius und Winkel nach Lat/Long
152
// !!! Vorzeichen der Quadranten noch zu verifizeiren!!!
153
// Benutzt die c_cos_8192 und c_sin_8192 der FC
154
// TODO: move to followme.c
155
// TODO: /8192 optimieren
156
 
157
uint8_t followme_calculate_offset(
158
                uint16_t radius,
159
                int16_t angle,
160
                positionOffset *followMeOffset
161
                )
162
{
163
        angle %= 360;                   // map angle to 0° - 360°
164
 
165
        if(angle < 90)                  // Q1
166
        {
167
                followMeOffset->offset_lat = ( radius * c_cos_8192( angle ) ) / 8192;
168
                followMeOffset->offset_long = ( radius * c_sin_8192( angle ) ) / 8192;
169
        }
170
        else
171
                if(angle < 180)         // Q2
172
                {
173
                        followMeOffset->offset_lat = ( radius * c_cos_8192( angle ) ) / 8192;
174
                        followMeOffset->offset_long = - ( radius * c_sin_8192( angle ) ) / 8192;
175
 
176
                }
177
                else
178
                        if(angle < 270) // Q3
179
                        {
180
                                followMeOffset->offset_lat = - ( radius * c_cos_8192( angle ) ) / 8192;
181
                                followMeOffset->offset_long = - ( radius * c_sin_8192( angle ) ) / 8192;
182
                        }
183
                        else                    //  Q4
184
                        {
185
                                followMeOffset->offset_lat = - ( radius * c_cos_8192( angle ) ) / 8192;
186
                                followMeOffset->offset_long = ( radius * c_sin_8192( angle ) ) / 8192;
187
                        }
188
        return 1;
189
}
190
 
191
 
2136 - 192
//###############################################################################################
193
 
194
 
195
 
196
//--------------------------------------------------------------
197
GPS_PosDev_t gps_Deviation( GPS_Pos_t pos1, GPS_Pos_t pos2 )
198
{
199
    int32_t      lat1, lon1, lat2, lon2;
200
    int32_t      d1, dlat;
201
    GPS_PosDev_t PosDev;
202
 
203
    lon1 = pos1.Longitude;
204
    lat1 = pos1.Latitude;
205
 
206
    lon2 = pos2.Longitude;
207
    lat2 = pos2.Latitude;
208
 
209
    d1   = (1359 * (int32_t)(c_cos_8192((lat1 + lat2) / 20000000)) * ((lon1 - lon2)/10))/ 10000000;
210
    dlat = (1113 * (lat1 - lat2) / 10000);
211
 
212
    PosDev.Bearing  = (my_atan2(d1, dlat) + 540) % 360;         // 360 +180 besserer Vergleich mit MkCockpit
213
    PosDev.Distance = sqrt32( d1 * d1 + dlat * dlat );          //
214
    //PosDev.Distance = sqrt32( d1 * d1 + dlat * dlat ) * 10;       // *10 um von dm auf cm zu kommen
215
 
216
    return PosDev;
217
}
218
 
219
 
220
///**
221
// * \brief Calculate distance between two points
222
// * \return Distance in meters
223
// */
224
//int32_t nmea_distance(
225
//        const nmeaPOS *from_pos,    /**< From position in radians */
226
//        const nmeaPOS *to_pos       /**< To position in radians */
227
//        )
228
//{
229
//  int32_t dist = ((int32_t)NMEA_EARTHRADIUS_M) * acos(
230
//        sin(to_pos->lat) * sin(from_pos->lat) +
231
//        cos(to_pos->lat) * cos(from_pos->lat) * cos(to_pos->lon - from_pos->lon)
232
//        );
233
//    return dist;
234
//}
235
 
236
 
237
 
238
//// Berechnung von Distanz und Winkel aus GPS-Daten home(MK eingeschaltet)
239
//// zur aktuellen Position(nach Motorstart)
240
//geo_t calc_geo(HomePos_t *home, GPS_Pos_t *pos)
241
//{ double lat1, lon1, lat2, lon2, d1, dlat;
242
//        geo_t geo;
243
//
244
//        lon1 = MK_pos.Home_Lon;
245
//        lat1 = MK_pos.Home_Lat;
246
//        lon2 = (double)pos->Longitude   / 10000000.0;
247
//        lat2 = (double)pos->Latitude    / 10000000.0;
248
//
249
//        // Formel verwendet von http://www.kompf.de/gps/distcalc.html
250
//        // 111.3 km = Abstand zweier Breitenkreise und/oder zweier Längenkreise am Äquator
251
//        // es wird jedoch in Meter weiter gerechnet
252
//        d1       = 111300 * (double)cos((double)(lat1 + lat2) / 2 * DEG_TO_RAD) * (lon1 - lon2);
253
//        dlat = 111300 * (double)(lat1 - lat2);
254
//        // returns a value in metres http://www.kompf.de/gps/distcalc.html
255
//        geo.bearing = fmod((RAD_TO_DEG * (double)atan2(d1, dlat)) + 180, 360); // +180 besserer Vergleich mit MkCockpit
256
//        if (geo.bearing > 360) geo.bearing -= 360; // bekam schon Werte über 400
257
//        geo.distance = sqrt(d1 * d1 + dlat * dlat);
258
//        return(geo);
259
//}
260
 
261
// Berechnung von Distanz und Winkel aus GPS-Daten home(MK eingeschaltet)
262
// zur aktuellen Position(nach Motorstart)
263
//--------------------------------------------------------------
264
//--------------------------------------------------------------
265
 
266
/*
267
geo_t calc_geo( HomePos_t *home, GPS_Pos_t *pos )
268
{
269
    int32_t lat1, lon1, lat2, lon2;
270
        int32_t d1, dlat;
271
        geo_t geo;
272
 
273
        lon1 = home->Home_Lon;
274
        lat1 = home->Home_Lat;
275
        lon2 = pos->Longitude;
276
        lat2 = pos->Latitude;
277
 
278
        if( !CheckGPS )
279
        {
280
            writex_gpspos(  0, 3, home->Home_Lat , MNORMAL,  0,0);    // Anzeige: Breitengrad (Latitude)
281
            writex_gpspos( 11, 3, home->Home_Lon , MNORMAL,  0,0);    // Anzeige: Laengengrad (Longitude)
282
            writex_gpspos(  0, 4, pos->Latitude  , MNORMAL,  0,0);    // Anzeige: Breitengrad (Latitude)
283
            writex_gpspos( 11, 4, pos->Longitude , MNORMAL,  0,0);    // Anzeige: Laengengrad (Longitude)
284
 
285
            //lcd_puts_at (0, 3, my_itoa(home->Home_Lat, 10, 7, 7), 0);     // 30.05.2014 OG: my_itoa() gibt es nicht mehr
286
            //lcd_puts_at (11, 3, my_itoa(home->Home_Lon, 10, 7, 7), 0);    // 30.05.2014 OG: my_itoa() gibt es nicht mehr
287
            //lcd_puts_at (0, 4, my_itoa(pos->Latitude, 10, 7, 7), 0);      // 30.05.2014 OG: my_itoa() gibt es nicht mehr
288
            //lcd_puts_at (11, 4, my_itoa(pos->Longitude, 10, 7, 7), 0);    // 30.05.2014 OG: my_itoa() gibt es nicht mehr
289
        }
290
 
291
        // Formel verwendet von http://www.kompf.de/gps/distcalc.html
292
        // 111.3 km = Abstand zweier Breitenkreise und/oder zweier Langenkreise am Äquator
293
        // es wird jedoch in dm Meter weiter gerechnet
294
        // (tlon1 - tlon2)/10) sonst uint32_t-Ãœberlauf bei cos(0) gleich 1
295
        d1       = (1359 * (int32_t)(c_cos_8192((lat1 + lat2) / 20000000)) * ((lon1 - lon2)/10))/ 10000000;
296
        dlat = 1113 * (lat1 - lat2) / 10000;
297
        geo.bearing = (my_atan2(d1, dlat) + 540) % 360; // 360 +180 besserer Vergleich mit MkCockpit
298
        geo.distance = sqrt32(d1 * d1 + dlat * dlat);
299
        if( !CheckGPS )
300
        {
301
            lcd_printp_at (0, 5, PSTR("Bear:"), 0);
302
 
303
            lcdx_printf_at_P( 5, 5, MNORMAL, 0,0, PSTR("%3d"), geo.bearing );
304
            //lcd_puts_at (5, 5, my_itoa((uint32_t)geo.bearing, 3, 0, 0), 0);       // 30.05.2014 OG: my_itoa() gibt es nicht mehr
305
 
306
            lcd_printp_at (8, 5, PSTR("\x1e"), 0);
307
            lcd_printp_at (9, 5, PSTR("Dist:"), 0);
308
 
309
            lcdx_printf_at_P( 15, 5, MNORMAL, 0,0, PSTR("%3d"), geo.distance );
310
            //lcd_puts_at (15, 5, my_itoa((uint32_t)geo.distance, 3, 1, 1), 0);     // 30.05.2014 OG: my_itoa() gibt es nicht mehr
311
 
312
            lcd_printp_at (20, 5, PSTR("m"), 0);
313
        }
314
 
315
 
316
        return(geo);
317
}
318
*/
319