Creating a MapView and Waypoint Application
Using The DJI PC Simulator
1. Introduction
2. Installing and setup the DJI PC Simulator
3. Using the DJI PC Simulator
Upgrading Your Aircraft's Firmware
Setup The Map View
1. Importing The Framework and Libraries
2. Creating the Map View
3. Adding Annotations to the MapView
4. Focusing the MKMapView
5. Showing the Aircraft on Map View
Refactoring the UI
1. Adding & Handling the New UIButtons
Configuring DJIWaypoint and DJIWaypointMission
DJIWaypoint
DJIWaypointMission
Creating The DJIWaypointConfigViewController
Implementing the DJIWaypoint Mission
Adding the DJIWaypointConfigViewController to DJIRootViewController
Handling The DJIWaypoint Mission
Showtime
Summary
If you come across any mistakes or bugs in this tutorial, please let us know using a Github issue, a post on the DJI forum, or commenting in the Gitbook. Please feel free to send us Github pull request and help us fix any issues. However, all pull requests related to document must follow the document style
In this tutorial, you will learn how to implement the DJIWaypoint Mission feature and get familiar with the usages of DJIMissionManager. Also you will know how to setup the DJI PC Simulator, upgrade your Inspire 1, Phantom 3 Professional and Phantom 3 Advanced's firmware to the lastest version, and how to test the Waypoint Mission API with DJI PC Simulator too. So let's get started!
You can download the demo project from this Github Page.
Using The DJI PC Simulator
1. Introduction
The DJI PC Simulator is a flight simulator designed for SDK developers. The simulator creates a virtual 3D environment and provides data analysis from flight data transmitted to the PC via the UDP protocol.
Supported Operating Systems: Windows 7, Windows 8, and Windows 8.1
Supported DJI Platforms: Matrice 100, Inspire 1, Phantom 3 Professional, and Phantom 3 Advanced
2. Installing and setup the DJI PC Simulator
First, you should download the DJI PC Simulator and WIN Driver from here: https://developer.dji.com/mobile-sdk/downloads :
DJI PC Simulator Installer & User Manual V1.0
WIN Driver Installer
You must install the driver before running the simulator. Since the simulator only supports Windows, you should find a PC or install a Virtual Manchine(Like VMWare or Parallels Desktop) to run Windows on your Mac. Now, double click the DJI_ WIN_Driver _Installer.exe file to install it. If a dialog box saying "Please power on MC and connect it to PC via USB!" pops up, just ignore it, click "YES", and follow the rest of the instructions to install the driver.
Then, double click the DJISimulator-Installer.exe file and follow the instructions to install the program.
3. Using the DJI PC Simulator
1. The Simulator Config window will appear once you launch the DJI PC Simulator. Set the Latitude and Longitude values based on your preference. The SN represents the connected aircraft's SN number. If you do not see the SN, your aircraft is not connected properly to the PC or there is an issues with your firmware.
Note:
The aircraft will not take off if the latitude and longitude values are near a No Fly Zone.
Select show log window under the Log Settings tab to display the log window, as seen below:
2. Connect the aircraft to your PC via the Micro USB cable, turn on the remote controller and finally turn on the aircraft. Click Display Simulator, and you will see the screenshot below(it will show whatever aircraft you are using). In this case you see the Inspire 1:
Note:
Do NOT launch the DJI Pilot app when the DJI PC Simulator is running.
Do NOT mount the propellers on the aircraft when the DJI PC Simulator is running, in case the motors start by accident. That would be extremely dangerous.
3. Start the simulation by clicking Start Simulation. You can use the remote controller to change the course of the aircraft by swithing the control mode to P or bring it back home with the Return-to-Home button on the remote controller.
Please check the data on the left down corner of view, World X, Y, Z represents the North-South, East- West, and Up-Down axes (take the North, East and Up directions as positive).
4. In order to change the view angle, left-click and drag, and to scroll, zoom in and zoom out.
Note: You can also see the flight trace in the simulator when the aircraft is flying. Right click on the simulator window and select setup as shown below:
Then select show trace under the simulator UI Config tab to display the flight trace, as shown below:
Here is the result:
5. Click Stop Simulation to stop the simulation. Close the simulator, and turn off the aircraft, and turn off the remote controller after use.
Important: If you want to stop midway through a Waypoint Mission, you should click Stop Simulation and stop the mission on the device you are running it from, otherwise the simulator may run the previous waypoint mission when you start it again.
For more info about DJI PC Simulator, please check the DJI PC Simulator user manual.pdf file, which is included in the download along with the simulator.
Upgrading Your Aircraft's Firmware
It's important to make sure your aircraft's firmware supports the DJI Mobile SDK before going through the following steps. Please download the latest firmware version from here based on the aircraft you have: https://developer.dji.com/mobile-sdk/downloads/ :
Phantom 3 Professional Firmware
Phantom 3 Advanced Firmware
Inspire 1 Firmware
It's not necessary to upgrade the Remote Controller's firmware, just put the downloaded bin file in the SD Card, insert it to your aircraft's camera, and restart it to upgrade. It may take 10 ~ 30 minutes to finish the upgrade.
For the Inspire 1, you can check the upgrade status of the firmware by identifying the sound pattern from the aircraft:
Upgrading: D D D D ... (fast)
Upgrade Success: D DD ...
Upgrade Failed or Error: long beep sound
For the Phantom 3, you can check upgrade status of the firmware by looking at the camera status indicator:
Upgrading: camera status indicator will blink green and red
Upgrade Success: camera sattus indicator will stop blinking
Upgrade Failed or Error: camera status indicator will show solid red
Regardless of what aircraft you are using, you can check whether or not the firmware was upgraded by checking the txt file generated during the upgrade process. For the Phantom 3 Professional, the txt file is named "P3X_FW_RESULT_AB.txt", and for the Inspire 1, it's named "WM610_FW_RESULT_AB.txt". Here are example contents of the txt file:
Setup The Map View
1. Importing The Framework and Libraries
Now that you've finished the steps above, we can start working on the application. In our previous tutorial Creating a Camera Application, you learned how to import and activate the DJI Mobile SDK into your Xcode project. If you haven't read that previously, please take a look at it. Once you've done that, we will set up the map view.
1. Create a new project in Xcode and name it "GSDemo", download the latest DJI iOS SDK from DJI Developer Website and copy the DJISDK.framework to your Xcode project's folder. Then, select the project target and go to Build Phases -> Link Binary With Libraries. Click the "+" button at the bottom and add two libraries to your project: libstdc++.6.0.9.tbd and libz.tbd. Take a look at the screenshot below:
2. Creating the Map View
Now, let's delete the ViewController.h and ViewController.m files, which were created by Xcode when you created the project. Then, create a viewController named "DJIRootViewController" and set it as the Root View Controller in Main.storyboard. Moreover, drag a MKMapView from Object Library to DJIRootViewController, setup its AutoLayout constraints, and set its delegate to DJIRootViewController, as seen below:
After that, open the DJIRootViewController.m file, create an IBOutlet for the MKMapView, name it "mapView" and link it to the MKMapView in Main.storyboard. Import the following header files and implement MKMapView's delegate method:
Now, let's build and run the project. If everything is as it should be, you should see the following screenshot:
3. Adding Annotations to the MapView
Currently, the map view is simple. Let's add something interesting to it. Create a new NSObject file named DJIMapController, which will be used to deal with the MKAnnotations(or for our purposes, Waypoints) logic on the map. Open the DJIMapController.h file and add the following code to it:
Here, we create an NSMutableArray called editPoints to store waypoint objects and add two methods to implement Add and Remove waypoints. The last method will be used to return the current waypoint objects on the map in an array.
Let's go to the DJIMapController.m file and replace the original code with the following:
First, we initialize the editPoints array in the init method, then create MKPointAnnotation objects from CGPoint and add them to our mapView, and finally implement the cleanAllPointsWithMapView method to clean up the eidtPoints array and the annotations on the mapView.
Go back to the DJIRootViewController.m file, import the DJIMapController.h header file, and create a DJIMapController property named mapController. Since we want to add annotation pins by tapping on the map, we also need to create a UITapGestureRecognizer named as tapGesture. Lastly, add a UIButton to the DJIRootViewController scene in Main.storyboard, set its IBOutlet name as "editBtn", and add an IBAction method named "editBtnAction" for it, as shown below:
Once that is complete, open the DJIMapController.m file, initialize the mapController and tapGesture variables, and add the tapGesture to mapView to add waypoints. Furthermore, we need a boolean variable named "isEditingPoints" to store the edit waypoint state, which will also change the title of editBtn accordingly. Lastly, implement tapGesture's action method addWayPoints, as shown below:
In the above code, we also added an NSNotification observer to check the DJI Mobile SDK's state, to make sure it was sucessfully registered. At the same time, we implement the addWaypoints gesture action by calling DJIMapController's
method to add waypoints to the map. Next, we implement the IBAction method editBtn, which will update the button's title and clean up waypoints based on the value of isEditingPoints. Finally, we implement MKMapViewDelegate's method to change the pin color to purple.
When you are done with all the steps above, build and run your project and try to add waypoints on the map. If everything is fine, you will see the following animation:
4. Focusing the MKMapView
You may be wondering why the map's location is different from your current location and why it is difficult to find your location on the map. Focusing the map to your current location quickly would be helpful for the application. To implement that feature, we need to use CLLocationManager.
Open the DJIRootViewController.m file and import CoreLocation's header file. Create a CLLocationManager property named "locationManager". Then create a CLLocationCoordinate2D property named "userLocation" to store the user's location data. Next, implement CLLocationManager's CLLocationManagerDelegate protocol in the class, as shown below:
In the code above, we also added a UIButton named "Focus Map" in DJIRootViewController's scene in Main.storyboard and added an IBAction method named as focusMapAction. Here is the screenshot of the scene from Main.storyboard:
Once you are done, go back to DJIRootViewController.m file and add the following code:
First, we initialize userLocation data to kCLLocationCoordinate2DInvalid in the viewDidLoad method. Then we add a new method named as "startUpdateLocation" to initialize locationManger, set its properties and start updating location. If the Location Service is not available, we add a UIAlertView to display the warning. The startUpdateLocation is called in viewWillAppear method and is stopped in the viewWillDisappear method. Moreover, we need to implement CLLocationManagerDelegate method to update userLocation property. Finally, we implement the "focusMapAction" method to focus mapView to the user's current location.
In iOS8, we must call locationManager's requestAlwaysAuthorization first, which was done in startUpdateLocation method.
Next, add a NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription key to your project’s Info.plist containing the message to be displayed to the user when a UIAlert asking whether or not they want to allow the application to use their location. We set the messages empty here:
It's time to build and run the project to check the focus map feature. When you launch the app for the first time, a pop up alert asking for your permission to access your location will appear. Select Allow and press the Focus Map button. If the map view animates to your current location like the following animation, congratulations, you have finished the Focus Map feature!
5. Showing the Aircraft on Map View
Now, we can focus the mapView to our current location, which is a good start! However, let's do something more interesting. We're going to simulate the aircraft's GPS location using the DJI PC Simulator and show it on our map view.
You may know how to setup the DJI PC Simulator, and its basic usage. If you want to place the aircraft in your current GPS location on Map View, you can set the latitude and longitude values in the Simulator Config to yours. We take the simulator's initial values in the following example.
Let's come back to the code. Create a new subclass of MKAnnotationView named "DJIAircraftAnnotationView" and a new subclass of NSObject named DJIAircraftAnnotation. Below is the code:
DJIAircraftAnnotationView.h
DJIAircraftAnnotationView.m
In the code above, we create a MKAnnotationView for the aircraft, add a method named updateHeading to change the aircraft's rotation, and set its image to "aircraft.png"(You can get the image from this tutorial's demo project.) in the init method. Also, we disable the DJIAircraftAnnotationView's draggable property. Take a look at the code below:
DJIAircraftAnnotation.h
DJIAircraftAnnotation.m
The DJIAircraftAnnotation class implements the MKAnnotation protocol. It's used to store and update a CLLocationCoordinate2D property. Also, we can update DJIAircraftAnnotationView's heading with the updateHeading method.
Once you're done with that, open the DJIMapController.h file and import the DJIAircraftAnnotation.h file:
Then create a property of an instance of DJIAircraftAnnotation and name it aircraftAnnotation.
Furthermore, add two new methods to update the aircraft's location and it's heading on the map.
Next, let's come back to the DJIMapController.m file and implement the two methods we just added:
Also, since we don't want the aircraftAnnotation removed by the cleanAllPointsWithMapView method in the DJIMapController.m file, we need to modify it, as shown below:
We add an if statement to check if the annotation of the map view is equal to the aircraftAnnotation property, and if it is not, we remove it. By doing so, we can prevent the Aircraft's annotation from being removed.
To provide a better user experience, we need to add a status view on top of the mapView to show the aircraft's flight mode type, current GPS satellite count, vertical and horizontal flight speed and the flight altitude. Let's add the UI in Main.storyboard's RootViewController Scene, as seen below:
Once that's done, open DJIRootViewController.m file, create IBOutlets for the above UI elements and import DJISDK's header file and implement "DJIFlightControllerDelegate" and "DJISDKManagerDelegate" protocols. Also, we need to create a CLLocationCoordinate2D property named droneLocation to record the aircraft's location, as shown below:
Now, let's initialize the UI elements' values in a new method called initUI. Call the initUI method in the viewDidLoad method. Lastly, create a new method named "registerApp" and invoke it in the viewDidLoad method to register the app as shown below:
Next, implement the "DJISDKManagerDelegate" method as follows:
In the code above, we can implement DJISDKManager's sdkManagerDidRegisterAppWithError: delegate method to check the register status and invoke the DJISDKManager's "startConnectionToProduct" method to connect to the aircraft. Moreover, the sdkManagerProductDidChangeFrom:to: delegate method will be invoked when the product connectivity status changes, so we can set DJIFlightController's delegate as DJIRootViewController here when product is connected.
You may notice that there is a "DemoUtility" class here, let's implement it now. Create a new NSObject class and named it as "DemoUtility", replace its .h file and .m file with the followings:
Then in the viewWillDisappear method, we need to invoke the "stopUpdatingLocation" method of CLLocationManager to stop update location as shown below:
Moreover, update the focusMapAction method to set droneLocation as the center of the map view's region, as shown below:
Next, We need to modify the MKMapViewDelegate method to what is shown below. It will check the annotation variable's class and set its annotationView as a DJIAircraftAnnotationView Class type object:
Furthermore, let's implement the DJIFlightControllerDelegate method:
First, it will update the droneLocation with the aircraft's current location. Next, update the text for the status labels from the DJIFlightControllerCurrentState. Furthermore, update the aircraft's location and heading by calling the related methods from DJIMapController.
Now, let's test the application!
Build and run the project to install the app onto your mobile device. After that, please connect the aircraft to your PC or Virtual Machine running Windows via a Micro USB cable, and then power on the aircraft and the remote controller. Click Display Simulator. You can type in your current location's latitude and longitude data in the Simulator Config, if you would like.
Then, run the app and connect your mobile device to the remote controller using Apple's lighting cable. You may see the following screenshot:
Important: To fix this problem, please switch the Remote Controller's mode selection to the F position (which used to be the A position in the previous version) and press Retry button. If the mode selection bar is in the F position when the autopilot is powered on, the user must toggle back and forth between F and another position and then press the Retry button again.
You are required to be in the F position when using the Intelligent Navigation, Hotpoint and Joystick functions in the DJI Mobile SDK.
Next, let's go to the DJI PC Simulator on your PC and press the Start Simulation button. If you check the application now, a tiny red aircraft will be shown on the map as seen below:
If you cannot find the aircraft, press the "Focus Map" button and the map view will zoom in to center the aircraft on the center of the map view region as shown below:
Now, if you press the Stop Simulation button on the Simulator Config, the aircraft will disappear on the map, since the simulator stops providing GPS data to the aircraft.
Refactoring the UI
As you seen, the project's code structure was simple and not robust. In order to develop it further in this tutorial, it will need to be refactored and we will need to add more UI elements.
1. Adding & Handling the New UIButtons
Firstly, we will create a new file named "DJIGSButtonController", which will be subclass of UIViewController. Make sure the check box saying "Also create XIB file" is selected when creating the file. Then open the DJIGSButtonController.xib file and set its size to Freeform under the "Size" dropdown in the Simulated Metrics section. In the view section, change the width to "100" and height to "288". Take a look at the changes made below:
Next, drag eight UIButtons to the view and change their names to "Edit", "Back", "Clear", "Focus Map", "Start", "Stop", "Add" and "Config". "Edit" will sit on top of "Back", and "Focus Map" will sit on top of "Add". Make sure to hide the "Back", "Clear", "Start", "Stop", "Add" and "Config" buttons.
Then add IBOutlets and IBActions for each of the eight buttons in the DJIGSButtonViewController.h file. Also, we will add an Enum named DJIGSViewMode with the two different modes the application could be in. Next, we add serveral delegate methods to be implemented by the delegate viewcontroller when IBAction methods for the buttons are trigger. Lastly, add the method switchToMode:inGSButtonVC: to update the state of the buttons when the DJIGSViewMode changed. Take a look at the code below:
Once you've taken care of that, open the DJIGSButtonViewController.m file to replace all the code in the file with the following code: