dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
tablet_control.c
Go to the documentation of this file.
1 
16 /*
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful, but
23  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25  * for more details.
26  *
27  * You should have received a copy of the GNU General Public License along
28  * with this program; if not, see <http://www.gnu.org/licenses/>
29  *
30  * Additional note on redistribution: The copyright and license notices above
31  * must be maintained in each individual source file that is a derivative work
32  * of this source file; otherwise redistribution is prohibited.
33  */
34 
35 #include "openpilot.h"
36 #include "control.h"
37 #include "tablet_control.h"
38 #include "transmitter_control.h"
39 #include "physical_constants.h"
40 
41 #include "flightstatus.h"
42 #include "gpsposition.h"
43 #include "homelocation.h"
44 #include "loitercommand.h"
45 #include "pathdesired.h"
46 #include "positionactual.h"
47 #include "tabletinfo.h"
48 #include "systemsettings.h"
49 
51 static int32_t tabletInfo_to_ned(TabletInfoData *tabletInfo, float *NED);
52 
54 #define HOME_ALTITUDE_OFFSET 15
55 #define FOLLOWME_RADIUS 20
56 
59 {
60  if (TabletInfoInitialize() == -1) {
61  return -1;
62  };
63  return 0;
64 }
65 
68 {
69  // TODO: Determine what to do when there are insufficient updates
70  // from the tablet. For now the transmitter is the authority so
71  // that is what determines whether to fall into failsafe.
72  return 0;
73 }
74 
79 int32_t tablet_control_select(bool reset_controller)
80 {
81  TabletInfoData tabletInfo;
82  TabletInfoGet(&tabletInfo);
83 
84  FlightStatusData flightStatus;
85  FlightStatusGet(&flightStatus);
86 
87  if (PathDesiredHandle() == NULL)
88  return -1;
89 
90  PathDesiredData pathDesired;
91  PathDesiredGet(&pathDesired);
92 
93  uint8_t mode = flightStatus.FlightMode;
94 
95  switch(tabletInfo.TabletModeDesired) {
96  case TABLETINFO_TABLETMODEDESIRED_POSITIONHOLD:
97  // Use the position hold FSM. This will take the current position
98  // when flight mode first is position hold. The tablet does not
99  // set the position explicitly
100  mode = FLIGHTSTATUS_FLIGHTMODE_POSITIONHOLD;
101 
102  // Command to not move. This code is identical to that in manualcontrol
103  LoiterCommandData loiterCommand;
104  loiterCommand.Pitch = 0;
105  loiterCommand.Roll = 0;
106  loiterCommand.Thrust = 0.5f;
107  loiterCommand.Frame = LOITERCOMMAND_FRAME_BODY;
108  LoiterCommandSet(&loiterCommand);
109 
110  break;
111  case TABLETINFO_TABLETMODEDESIRED_RETURNTOHOME:
112 
113  // Use the return to home FSM.
114  mode = FLIGHTSTATUS_FLIGHTMODE_RETURNTOHOME;
115 
116  break;
117  case TABLETINFO_TABLETMODEDESIRED_RETURNTOTABLET:
118  {
119  float NED[3];
120 
121  mode = FLIGHTSTATUS_FLIGHTMODE_TABLETCONTROL;
122  tabletInfo_to_ned(&tabletInfo, NED);
123 
124  pathDesired.End[0] = NED[0];
125  pathDesired.End[1] = NED[1];
126  pathDesired.End[2] = -HOME_ALTITUDE_OFFSET;
127  pathDesired.Mode = PATHDESIRED_MODE_HOLDPOSITION;
128  pathDesired.StartingVelocity = 5;
129  pathDesired.EndingVelocity = 5;
130 
131  PathDesiredSet(&pathDesired);
132  }
133 
134  break;
135  case TABLETINFO_TABLETMODEDESIRED_PATHPLANNER:
136  mode = FLIGHTSTATUS_FLIGHTMODE_PATHPLANNER;
137  break;
138  case TABLETINFO_TABLETMODEDESIRED_FOLLOWME:
139  {
140  mode = FLIGHTSTATUS_FLIGHTMODE_TABLETCONTROL;
141 
142  // Follow the tablet location at a fixed height, but always following by
143  // a set radius. This mode is updated every cycle, unlike the others.
144  float NED[3];
145  tabletInfo_to_ned(&tabletInfo, NED);
146 
147  PositionActualData positionActual;
148  PositionActualGet(&positionActual);
149 
150  float DeltaN = NED[0] - positionActual.North;
151  float DeltaE = NED[1] - positionActual.East;
152  float dist = sqrtf(DeltaN * DeltaN + DeltaE * DeltaE);
153 
154  // If outside the follow radius code to the nearest point on the border
155  // otherwise stay in the same location
156  if (dist > FOLLOWME_RADIUS) {
157  float frac = (dist - FOLLOWME_RADIUS) / dist;
158  pathDesired.End[0] = positionActual.North + frac * DeltaN;
159  pathDesired.End[1] = positionActual.East + frac * DeltaE;
160  pathDesired.End[2] = -HOME_ALTITUDE_OFFSET;
161  } else {
162  pathDesired.End[0] = positionActual.North;
163  pathDesired.End[1] = positionActual.East;
164  pathDesired.End[2] = -HOME_ALTITUDE_OFFSET;
165  }
166  pathDesired.Mode = FLIGHTSTATUS_FLIGHTMODE_PATHPLANNER;
167  pathDesired.StartingVelocity = 5;
168  pathDesired.EndingVelocity = 5;
169 
170  PathDesiredSet(&pathDesired);
171  }
172  break;
173  case TABLETINFO_TABLETMODEDESIRED_LAND:
174  default:
175  AlarmsSet(SYSTEMALARMS_ALARM_MANUALCONTROL, SYSTEMALARMS_ALARM_ERROR);
176 
177  // Fail out. This will trigger failsafe mode.
178  return -1;
179  }
180 
181  // Update mode if changed
182  if (mode != flightStatus.FlightMode) {
183  /* TODO: unsafe! */
184  flightStatus.FlightMode = mode;
185  FlightStatusSet(&flightStatus);
186  }
187 
188  return 0;
189 }
190 
196 static int32_t tabletInfo_to_ned(TabletInfoData *tabletInfo, float *NED)
197 {
198  // TODO: Abstract out this code and also precompute the part based
199  // on home location.
200 
201  HomeLocationData homeLocation;
202  HomeLocationGet(&homeLocation);
203 
204  GPSPositionData gpsPosition;
205  GPSPositionGet(&gpsPosition);
206 
207  float lat = homeLocation.Latitude / 10.0e6f * DEG2RAD;
208  float alt = homeLocation.Altitude;
209 
210  float T[3];
211  T[0] = alt+6.378137E6f;
212  T[1] = cosf(lat)*(alt+6.378137E6f);
213  T[2] = -1.0f;
214 
215  // Tablet altitude is in WSG84 but we use height above the geoid elsewhere so use the
216  // GPS GeoidSeparation as a proxy
217  // [WARNING] Android altitude can be either referenced to WGS84 ellipsoid or EGM1996 geoid. See:
218  // http://stackoverflow.com/questions/11168306/is-androids-gps-altitude-incorrect-due-to-not-including-geoid-height
219  // and https://code.google.com/p/android/issues/detail?id=53471
220  // This means that "(tabletInfo->Altitude + gpsPosition.GeoidSeparation - homeLocation.Altitude)"
221  // will be correct or incorrect depending on the device.
222  float dL[3] = {(tabletInfo->Latitude - homeLocation.Latitude) / 10.0e6f * DEG2RAD,
223  (tabletInfo->Longitude - homeLocation.Longitude) / 10.0e6f * DEG2RAD,
224  (tabletInfo->Altitude + gpsPosition.GeoidSeparation - homeLocation.Altitude)};
225 
226  NED[0] = T[0] * dL[0];
227  NED[1] = T[1] * dL[1];
228  NED[2] = T[2] * dL[2];
229 
230  return 0;
231 }
232 
Use tablet for control source.
static PathDesiredData pathDesired
Process transmitter inputs and use as control source.
uint32_t lat
Definition: msp_messages.h:97
int32_t tablet_control_update()
Process updates for the tablet controller.
int32_t AlarmsSet(SystemAlarmsAlarmElem alarm, SystemAlarmsAlarmOptions severity)
Definition: alarms.c:97
static float T[3]
Scales used in NED transform (local tangent plane approx).
Definition: attitude.c:210
struct _msp_pid_item alt
Definition: msp_messages.h:99
static HomeLocationData homeLocation
Definition: attitude.c:147
enum channel_mode mode
Definition: pios_servo.c:58
int32_t tablet_control_initialize()
Initialize the tablet controller.
Includes PiOS and core architecture components.
#define FOLLOWME_RADIUS
#define HOME_ALTITUDE_OFFSET
Private constants.
static int32_t tabletInfo_to_ned(TabletInfoData *tabletInfo, float *NED)
Private methods.
int32_t tablet_control_select(bool reset_controller)
Use the values for the tablet controller.