|
1 | 1 | package com.o3dr.android.client.apis;
|
2 | 2 |
|
3 | 3 | import android.os.Bundle;
|
| 4 | +import android.support.annotation.IntDef; |
4 | 5 |
|
5 | 6 | import com.o3dr.android.client.Drone;
|
6 | 7 | import com.o3dr.services.android.lib.coordinate.LatLong;
|
7 | 8 | import com.o3dr.services.android.lib.drone.attribute.AttributeType;
|
| 9 | +import com.o3dr.services.android.lib.drone.attribute.error.CommandExecutionError; |
| 10 | +import com.o3dr.services.android.lib.drone.property.Attitude; |
8 | 11 | import com.o3dr.services.android.lib.drone.property.Gps;
|
9 | 12 | import com.o3dr.services.android.lib.model.AbstractCommandListener;
|
10 | 13 | import com.o3dr.services.android.lib.model.action.Action;
|
11 | 14 |
|
| 15 | +import java.lang.annotation.Retention; |
| 16 | +import java.lang.annotation.RetentionPolicy; |
12 | 17 | import java.util.concurrent.ConcurrentHashMap;
|
13 | 18 |
|
14 | 19 | import static com.o3dr.services.android.lib.drone.action.ControlActions.ACTION_DO_GUIDED_TAKEOFF;
|
|
23 | 28 | import static com.o3dr.services.android.lib.drone.action.ControlActions.EXTRA_VELOCITY_Y;
|
24 | 29 | import static com.o3dr.services.android.lib.drone.action.ControlActions.EXTRA_VELOCITY_Z;
|
25 | 30 | import static com.o3dr.services.android.lib.drone.action.ControlActions.EXTRA_YAW_CHANGE_RATE;
|
26 |
| -import static com.o3dr.services.android.lib.drone.action.ControlActions.EXTRA_YAW_IS_CLOCKWISE; |
27 | 31 | import static com.o3dr.services.android.lib.drone.action.ControlActions.EXTRA_YAW_IS_RELATIVE;
|
28 | 32 | import static com.o3dr.services.android.lib.drone.action.ControlActions.EXTRA_YAW_TARGET_ANGLE;
|
29 | 33 |
|
|
36 | 40 | */
|
37 | 41 | public class ControlApi extends Api {
|
38 | 42 |
|
| 43 | + public static final int EARTH_NED_COORDINATE_FRAME = 0; |
| 44 | + public static final int VEHICLE_COORDINATE_FRAME = 1; |
| 45 | + |
| 46 | + @IntDef({EARTH_NED_COORDINATE_FRAME, VEHICLE_COORDINATE_FRAME}) |
| 47 | + @Retention(RetentionPolicy.SOURCE) |
| 48 | + public @interface CoordinateFrame{} |
| 49 | + |
39 | 50 | private static final ConcurrentHashMap<Drone, ControlApi> apiCache = new ConcurrentHashMap<>();
|
40 | 51 | private static final Builder<ControlApi> apiBuilder = new Builder<ControlApi>() {
|
41 | 52 | @Override
|
@@ -113,33 +124,67 @@ public void climbTo(double altitude) {
|
113 | 124 | /**
|
114 | 125 | * Instructs the vehicle to turn to the specified target angle
|
115 | 126 | * @param targetAngle Target angle in degrees [0-360], with 0 == north.
|
116 |
| - * @param turnSpeed Speed during turn in degrees per second |
117 |
| - * @param isClockwise True for clockwise turn, false for counter clockwise turn |
| 127 | + * @param turnRate Turning rate normalized to the range [-1.0f, 1.0f]. Positive values for clockwise turns, and negative values for counter-clockwise turns. |
118 | 128 | * @param isRelative True is the target angle is relative to the current vehicle attitude, false otherwise if it's absolute.
|
119 | 129 | * @param listener Register a callback to receive update of the command execution state.
|
120 | 130 | */
|
121 |
| - public void turnTo(float targetAngle, float turnSpeed, boolean isClockwise, boolean isRelative, AbstractCommandListener listener){ |
| 131 | + public void turnTo(float targetAngle, float turnRate, boolean isRelative, AbstractCommandListener listener){ |
| 132 | + if(!isWithinBounds(targetAngle, 0, 360) || !isWithinBounds(turnRate, -1.0f, 1.0f)){ |
| 133 | + postErrorEvent(CommandExecutionError.COMMAND_FAILED, listener); |
| 134 | + return; |
| 135 | + } |
| 136 | + |
122 | 137 | Bundle params = new Bundle();
|
123 | 138 | params.putFloat(EXTRA_YAW_TARGET_ANGLE, targetAngle);
|
124 |
| - params.putFloat(EXTRA_YAW_CHANGE_RATE, turnSpeed); |
125 |
| - params.putBoolean(EXTRA_YAW_IS_CLOCKWISE, isClockwise); |
| 139 | + params.putFloat(EXTRA_YAW_CHANGE_RATE, turnRate); |
126 | 140 | params.putBoolean(EXTRA_YAW_IS_RELATIVE, isRelative);
|
127 | 141 | drone.performAsyncActionOnDroneThread(new Action(ACTION_SET_CONDITION_YAW, params), listener);
|
128 | 142 | }
|
129 | 143 |
|
130 |
| - /** |
131 |
| - * Move the vehicle along the specified velocity vector. |
132 |
| - * |
133 |
| - * @param vx x velocity in meter / s |
134 |
| - * @param vy y velocity in meter / s |
135 |
| - * @param vz z velocity in meter / s |
136 |
| - * @param listener Register a callback to receive update of the command execution state. |
137 |
| - */ |
138 |
| - public void moveAtVelocity(float vx, float vy, float vz, AbstractCommandListener listener){ |
| 144 | + private void moveAtVelocity(float vx, float vy, float vz, AbstractCommandListener listener){ |
139 | 145 | Bundle params = new Bundle();
|
140 | 146 | params.putFloat(EXTRA_VELOCITY_X, vx);
|
141 | 147 | params.putFloat(EXTRA_VELOCITY_Y, vy);
|
142 | 148 | params.putFloat(EXTRA_VELOCITY_Z, vz);
|
143 | 149 | drone.performAsyncActionOnDroneThread(new Action(ACTION_SET_VELOCITY, params), listener);
|
144 | 150 | }
|
| 151 | + |
| 152 | + /** |
| 153 | + * Move the vehicle along the specified velocity vector. |
| 154 | + * |
| 155 | + * @param referenceFrame Reference frame to use. Can be one of |
| 156 | + * {@link #EARTH_NED_COORDINATE_FRAME}, |
| 157 | + * {@link #VEHICLE_COORDINATE_FRAME} |
| 158 | + * |
| 159 | + * @param vx x velocity normalized to the range [-1.0f, 1.0f]. |
| 160 | + * @param vy y velocity normalized to the range [-1.0f, 1.0f]. |
| 161 | + * @param vz z velocity normalized to the range [-1.0f, 1.0f]. |
| 162 | + * @param listener Register a callback to receive update of the command execution state. |
| 163 | + */ |
| 164 | + public void moveAtVelocity(@CoordinateFrame int referenceFrame, float vx, float vy, float vz, AbstractCommandListener listener){ |
| 165 | + if(!isWithinBounds(vx, -1f, 1f) || !isWithinBounds(vy, -1f, 1f) || !isWithinBounds(vz, -1f, 1f)){ |
| 166 | + postErrorEvent(CommandExecutionError.COMMAND_FAILED, listener); |
| 167 | + return; |
| 168 | + } |
| 169 | + |
| 170 | + float projectedX = vx; |
| 171 | + float projectedY = vy; |
| 172 | + |
| 173 | + if(referenceFrame == VEHICLE_COORDINATE_FRAME) { |
| 174 | + Attitude attitude = drone.getAttribute(AttributeType.ATTITUDE); |
| 175 | + double attitudeInRad = Math.toRadians(attitude.getYaw()); |
| 176 | + |
| 177 | + final double cosAttitude = Math.cos(attitudeInRad); |
| 178 | + final double sinAttitude = Math.sin(attitudeInRad); |
| 179 | + |
| 180 | + projectedX = (float) (vx * cosAttitude) - (float) (vy * sinAttitude); |
| 181 | + projectedY = (float) (vx * sinAttitude) + (float) (vy * cosAttitude); |
| 182 | + } |
| 183 | + |
| 184 | + moveAtVelocity(projectedX, projectedY, vz, listener); |
| 185 | + } |
| 186 | + |
| 187 | + private static boolean isWithinBounds(float value, float lowerBound, float upperBound){ |
| 188 | + return value <= upperBound && value >= lowerBound; |
| 189 | + } |
145 | 190 | }
|
0 commit comments