iosswiftdji-sdk

DJI SDK waypoint Missions - swift, IOS


I want to program a system where co-ordinates can be passed to the drone as waypoints and the drone will carry out the actions. The DJI API is documented with OBJ-c and while the concepts will be the same im struggling to understand how a mission is programmed.

If someone can help me with the basic structure of a waypoint mission and passing this to the drone it would be very helpful. Maybe I'm not understanding things well but the DJI API doesn't seem to be very descriptive of how things work.

I'm not asking to be spoon fed but someone with insight who could give me an explanation


Solution

  • This is how I wrote the waypoint function with swift and you can read code comments from below to understand the mission specification!

    /// Build a waypoint function that allows the drone to move between points according to its altitude, longitude, and latitude
        func waypointMission() -> DJIWaypointMission? {
            /// Define a new object class for the waypoint mission
            let mission = DJIMutableWaypointMission()
            
            mission.maxFlightSpeed = 15 
            mission.autoFlightSpeed = 8
            mission.finishedAction = .noAction
            mission.headingMode = .usingInitialDirection
            mission.flightPathMode = .normal
            mission.rotateGimbalPitch = false /// Change this to True if you want the camera gimbal pitch to move between waypoints
            mission.exitMissionOnRCSignalLost = true
            mission.gotoFirstWaypointMode = .pointToPoint
            mission.repeatTimes = 1
            
            /// Keep listening to the drone location included in latitude and longitude
            guard let droneLocationKey = DJIFlightControllerKey(param: DJIFlightControllerParamAircraftLocation) else {
                return nil
            }
            guard let droneLocationValue = DJISDKManager.keyManager()?.getValueFor(droneLocationKey) else {
                return nil
            }
            let droneLocation = droneLocationValue.value as! CLLocation
            let droneCoordinates = droneLocation.coordinate
            /// Check if the returned coordinate value is valid or not
            if !CLLocationCoordinate2DIsValid(droneCoordinates) {
                return nil
            }
            mission.pointOfInterest = droneCoordinates
           
            let loc1 = CLLocationCoordinate2DMake(droneCoordinates.latitude, droneCoordinates.longitude)
            let waypoint1 = DJIWaypoint(coordinate: loc1)
            
            waypoint1.altitude = 2.0 /// The altitude which the drone flies to as the first point and should be of type float
            waypoint1.heading = 0 /// This is between [-180, 180] degrees, where the drone moves when reaching a waypoint. 0 means don't change the drone's heading
            waypoint1.actionRepeatTimes = 1 /// Repeat this mission just for one time
            waypoint1.actionTimeoutInSeconds = 60
            // waypoint1.cornerRadiusInMeters = 5
            waypoint1.turnMode = .clockwise /// When the drones changing its heading. It moves clockwise
            waypoint1.gimbalPitch = 0 /// This is between [-90, 0] degrees, if you want to change this value, then change rotateGimbalPitch to True. The drone gimbal will move by the value when the drone reaches its waypoint
            waypoint1.speed = 0.5 /// Note that this value does not make the drone move with speed 0.5 m/s because this is an error from the firmware and can't be fixed. However, we need to trigger it to be able to change the next one
            
            let loc2 = CLLocationCoordinate2DMake(droneCoordinates.latitude, droneCoordinates.longitude)
            let waypoint2 = DJIWaypoint(coordinate: loc2)
            waypoint2.altitude = 15.0 /// should be of type float
            waypoint2.heading = 0
            waypoint2.actionRepeatTimes = 1
            waypoint2.actionTimeoutInSeconds = 60
            //waypoint2.cornerRadiusInMeters = 5
            waypoint2.turnMode = .clockwise
            waypoint2.gimbalPitch = 0
            /// Chnage the velocity of the drone while moving to this waypoint
            waypoint2.speed = 0.5
            
            mission.add(waypoint1)
            mission.add(waypoint2)
            
            return DJIWaypointMission(mission: mission)
        }
    
    

    Now when you call the previous function, you need to pass it to the timeline of the mission, and here is an example flow of a full timeline mission

    /// Set up the drone misison and strart its timeline
        func goUpVerticallyMission() {
            /// Check if the drone is connected
            let product = DJISDKManager.product()
            
            if (product?.model) != nil {
                
                /// This is the array that holds all the timline elements to be executed later in order
                var elements = [DJIMissionControlTimelineElement]()
                
                /// Reset Gimbal Position
                let attitude = DJIGimbalAttitude(pitch: 0.0, roll: 0.0, yaw: 0.0)
                let pitchAction: DJIGimbalAttitudeAction = DJIGimbalAttitudeAction(attitude: attitude)!
                elements.append(pitchAction) // task number 0
                
                
                let takeOff = DJITakeOffAction()
                elements.append(takeOff) // task number 1
    
                /// Set up and start a new waypoint mission
                var mission: DJIWaypointMission?
                guard let result = self.waypointMission() else {return}
                mission = result
                elements.append(mission!) // task number 2
                
                /// After the waypoint mission finishes stop recording the video
                let stopVideoAction = DJIRecordVideoAction(stopRecordVideo: ())
                elements.append(stopVideoAction!) // task number 3
                
                /// This is landing action after finishing the  task
                // let landAction = DJILandAction()
                // elements.append(landAction)
                
                /// This is the go home and landing action in which the drone goes back to its starting point when the first time started the mission
                let goHomeLandingAction = DJIGoHomeAction()
                elements.append(goHomeLandingAction) /// task number 4
                
                /// Check if there is any error while appending the timeline mission to the array.
                let error = DJISDKManager.missionControl()?.scheduleElements(elements)
                if error != nil {
                    print("Error detected with the mission")
                } else {
                    /// If there is no error then start the mission
                    DispatchQueue.main.asyncAfter(deadline: .now()) {
                        DJISDKManager.missionControl()?.startTimeline()
                    }
                }
            }
        }
    
    

    Please let me know if you misunderstand anything or you need any help with other things!!!