2

I'm having a really bad time trying to use the DJI-SDK for iOS in Swift.

This SDK is written in Objective-c and uses a key - value system to store values and send commands to the drone, so if y need to tell the drone to enable the virtual sticks you need to execute something like this:

DJISDKManager.keyManager()?.setValue(true as NSNumber, for: enableVirtualStickModeKey!, withCompletion: { (error) in......

This is pretty straightforward because our value is a Bool cast to NSNumber, the problems begin when I need to send struct values like a position of the virtual stick (Objective-c struct), this is an example of a value to make the drone ascend at 1 m/s:

var controlData = DJIVirtualStickFlightControlData()
    controlData.verticalThrottle = 1
    controlData.pitch = 0
    controlData.roll = 0
    controlData.yaw = 0

DJISDKManager.keyManager()?.setValue(controlData, for: virtualSticksKey!, withCompletion: { (error) in..

But the SDK fails with an error trying to set the values. I wrote to the DJI support team and the answer was that they hope the community can help me solve the problem....

The question is what type of cast I need to make to translate this DJIVirtualStickFlightControlData object to an Objective-C compatible type?

This is the DJIVirtualStickFlightControlData definition from DJIFlightControllerBaseTypes.h

    typedef struct
{
    float pitch;
    float roll;
    float yaw;
    float verticalThrottle;
} DJIVirtualStickFlightControlData;

And this is the definition of the setValue method from DJIKeyManager.h

/**
 *  Performs a set on a settable key, changing attributes on the  connected product.
 *  
 *  @param value A value object relevant to the given key
 *  @param key A valid settable key
 *  @param completion A set completion block.
 */
- (void)setValue:(id)value
          forKey:(DJIKey *)key
        withCompletion:(DJIKeyedSetCompletionBlock)completion;
piet.t
  • 11,718
  • 21
  • 43
  • 52
  • What error is returned for setValue? – paiv Aug 03 '17 at 13:59
  • There are ways to transform `struct` to `(NS)Data`, it's an issue not uncommon with Bluetooth Low-Energy. Check there: https://stackoverflow.com/questions/29556610/cast-a-swift-struct-to-unsafemutablepointervoid ? – Larme Aug 03 '17 at 15:39

2 Answers2

1

Finally I find a workaround to this problem through delegate methods!, actually is a much better way to use the DJI-SDK in SWIFT

First mark your class as a implementer of DJIFlightControllerDelegate

class FPVViewController: DJISDKManagerDelegate, DJIFlightControllerDelegate{

Create a method to retrieve the FlightController instance

func fetchFlightController() -> DJIFlightController?{
        let product = DJISDKManager.product()
        if (product == nil) {
            return nil
        }

        if product!.isKind(of: DJIAircraft.self){
            return (product as! DJIAircraft).flightController
        }
        return nil
    }

Call it from the productConnected method (this is actually another delegate method from DJISDKManagerDelegate) and set this class as the delegate for the FlightController

func productConnected(_ product: DJIBaseProduct?) {

    NSLog("Product Connected")

    if (product != nil) {
        //Set this class as the delegate for the hardware

        let flightController = self.fetchFlightController()
        if flightController != nil{
            flightController!.delegate = self
        }

        self.setupVideoPreviewer()
    }

}

Before you can send virtual stick commands you must enable them and to do that some conditions must be accomplished

Finally you can set the virtual sticks values this way

var controlData = DJIVirtualStickFlightControlData()
    controlData.verticalThrottle = 2
    controlData.pitch = 0
    controlData.roll = 0
    controlData.yaw = 0

let flightController = self.fetchFlightController()
        flightController?.send(controlData, withCompletion: { (error) in
            if error != nil{
                let nserror = error! as NSError
                NSLog("Error controling virtual throttle \(String(describing: nserror))")
            }
        })

One more thing: Xcode remote install and debugging is a must have to develop with the DJI-SDK is currently in the Beta versions of xCode and iOS but its working perfectly fine

0

Firstly, please note that the key SendVirtualStickFlightControlData is a key of type Action. So, the correct way to use the key is to call .performAction and not .setValue.

To pass a struct value in a key, it needs to be wrapped in an NSValue. This becomes somewhat tricky with Swift since you have to resort to using the NSValue initializer which takes UnsafeRawPointer. You can do it like this:

var controlData = DJIVirtualStickFlightControlData()
controlData.verticalThrottle = 1
controlData.pitch = 0
controlData.roll = 0
controlData.yaw = 0

let value: NSValue = NSValue.init(pointer: &controlData)

let key = DJIFlightControllerKey(param: DJIFlightControllerParamSendVirtualStickFlightControlData)

DJISDKManager.keyManager()?.performAction(for: key!, withArguments: [value], andCompletion: { (success, value, error) in
    print(success)
})
aksh1t
  • 5,410
  • 1
  • 37
  • 55
  • Thanks for your help aksh1t, I end up using the delegate methods, is easier and you gain a lot of control using the delegate methods to receive the aircraft state updates – Alvaro Menoni Aug 21 '17 at 12:57
  • Hi aksh1t, maybe you can help me with this problem? https://stackoverflow.com/questions/45872030/retrieve-images-from-a-dji-drone-with-exif-data I really appreciate if you can take a look Thanks! – Alvaro Menoni Aug 24 '17 at 22:50