In this post I will talk in a bit more detail how to create a new application that uses the .NET DroneController. The application I create will be a WPF application mostly because WPF has native support for WritebleBitmap. If we would use a windows forms application we would need to find a way to bind the WritebleBitmap to a PictureBox control. I did not yet spend time doing this.

When creating a new application there are basically three different phases to take care off:

  • Implement a method that creates a new DroneController instance, configures it and connects it to the ARDrone.
  • Implement methods that pass commands via the DroneController instance to the ARDrone.
  • Implement event handlers that allow to work with data coming from the ARDrone.

Let’s go over each of these phases in more detail:

Create a new DroneController instance:

When you create a new instance of the DroneController class you pass an instance of a DroneControllerConfiguration class. This can be done explicitly or implicitly.

Suppose I want to create a new instance of the DroneController using all the defaults I can do just:

DroneController droneController = new DroneController();

In this case the DroneController instance will be configured using the defaults of the DroneControllerConfiguration class:

/// <summary>
/// Initializes a new instance of the <see cref=”DroneControllerConfiguration”/> class.
/// </summary>
public DroneControllerConfiguration()
{
this.NetworkIdentifier = “ardrone_229”;
this.DroneIpAddress = “192.168.1.1”;
this.GuestIpAddress = “192.168.1.2”;
this.NavigationDataPort = 5554;
this.VideoStreamPort = 5555;
this.CommandPort = 5556;
this.ControlInfoPort = 5559;
this.EnableATCommandThread = true;
this.EnableNavigationDataThread = true;
this.EnableVideoStreamThread = true;
this.EnableControlInfoThread = false;
this.EnableInputFeedback = false;

this.RollThrottle = Constants.DefaultRollThrottleValue;
this.PitchThrottle = Constants.DefaultPitchThrottleValue;
this.HeightThrottle = Constants.DefaultHeightThrottleValue;
this.YawThrottle = Constants.DefaultYawThrottleValue;

DroneInfoTimerInterval = Constants.DroneInfoTimerInterval;
}

Here you see that the network identifier of the adhoc network created by the ARDrone is called ‘ardrone_229’. Yours will most probably be different, in this case you can change the default constructor of the DroneControllerConfiguration class.

Another way would be to construct a DroneController instance as follows:

DroneController droneController = new DroneController(“[your network identifier]”);

Here the DroneController instance will be created with all default values but

If you want to have more control you can create first an instance of a DroneControllerConfiguration class and pass this on when you create a new instance of the DroneController.

droneControllerConfiguration = new DroneControllerConfiguration();

droneControllerConfiguration.NetworkIdentifier = “ardrone_229”;
droneControllerConfiguration.EnableNavigationDataThread = true;
droneControllerConfiguration.EnableVideoStreamThread = true;
droneControllerConfiguration.EnableATCommandThread = true;
droneControllerConfiguration.EnableControlInfoThread = false;
droneControllerConfiguration.VideoFilePath = videosPath;
droneControllerConfiguration.PictureFilePath = picturesPath;
droneControllerConfiguration.EnableATCommandSimulation = simulate;
droneControllerConfiguration.EnableInputFeedback = true;

#region Throttle Values

droneControllerConfiguration.RollThrottle = .2f;
droneControllerConfiguration.PitchThrottle = .2f;
droneControllerConfiguration.YawThrottle = .6f;
droneControllerConfiguration.HeightThrottle = .4f;

#endregion

droneController = new DroneController(droneControllerConfiguration);

Remark:

I included the concept of throttle values because not everyone has a large empty warehouse at their disposition, in my case I only had +/- 2 m2 in my living room to spare. By playing with the throttle values you can minimize the effect of your input values on the ARDrone movement so that you can use and experiment with it in smaller places. Although this is also possible by changing some parameters on the ARDrone itself I decided to provide more accessible support with these throttle parameters on the DroneControllerConfiguration instance.

In order to be able to monitor the DroneController we can subscribe to the different events that this class exposes:

droneController.TraceNotificationLevel = TraceNotificationLevel.Verbose;
droneController.OnNotifyTraceMessage += new EventHandler<TraceNotificationEventArgs>(droneController_OnNotifyTraceMessage);
droneController.OnNotifyVideoMessage += new EventHandler<VideoNotificationEventArgs>(droneController_OnNotifyVideoMessage);
droneController.OnNotifyDroneInfoMessage += new EventHandler<DroneInfoNotificationEventArgs>(droneController_OnNotifyDroneInfoMessage);
droneController.OnConnectionStatusChanged += new EventHandler<ConnectionStatusChangedEventArgs>(droneController_OnConnectionStatusChanged);

Now we can connect to the ARDrone:

droneController.Connect();

Pass commands to the ARDrone

After you have created an instance of a DroneController class, it knows how to communicate with the ARDrone, you only have to tell it what commands it should send. This can be done in two ways:

Commands send directly to the DroneController instance

e.g.

if (droneController != null && droneController.ConnectionStatus == ConnectionStatus.Open)
{
droneController.SetFlatTrim();
droneController.StartEngines();
}
Commands send via an InputProvider

e.g.

if (droneController != null && droneController.ConnectionStatus == ConnectionStatus.Open)
{
inputProvider = new WiimoteInputProvider(droneController);
inputProvider.Initialize(droneController.RollThrottleValue, droneController.PitchThrottleValue, droneController.HeightThrottleValue, droneController.YawThrottleValue);
}

In this case no explicit commands are send to the DroneController instance. The object that implements the IInputProvider interface consumes the methods exposed by the IDroneCommander interface.

Implement the DroneController event handlers

The DroneController class exposes several events that provide feedback on different aspects. It is not mandatory to subscribe to these events but it makes working with the DroneController a lot easier.

These are the different events that are exposed:

  • OnNotifyTraceMessage – This event is used for general diagnostic messages. The TraceNotificationLevel enumeration can be used to throttle the level of detail.
  • OnNotifyVideoMessage – This event conveys the current video frame captured by the ARDrone cameras. The composition of the video frame depends on the selected video channel.
  • OnNotifyDroneInfoMessage – This event provides feedback on several aspects of the ARDrone, e.g. Battery Level. The existing code can be adapted if more information is needed.
  • OnConnectionStatusChanged – This event provides connection status feedback.
  • OnNotifyInputMessage – This event provides feedback on changes in flight parameters. This can be used to provide visual feedback on screen.
  • OnVisionDetectMessage – This event is triggered when tag detection is activated, it will tell whether a tag is detected an provide information on the detected tag.

Do not forget that the event handlers are not activated on the UI thread, if you need to access controls from within the event handler you need to go via the dispatcher (look in the sample source code how to do this if you are not familiar with this concept).

In the next post I will talk a small bit about the more advanced multi-touch WPF interface.