Buenas,
today already we will create an application that allows us to control the Lance missiles using Kinect gestures. For this I have thought of the following controls
- The right hand controls the direction of the Lance missiles. You can go to the right, left, up or down.
- The left hand controls the firing of the missile, shoot is raise your hand above the head.
- If both hands are below the waist stop movements of the Lance missile
On this basis, and taking advantage of Visual controls of "Microsoft.Samples.Kinect.WpfViewers" I created a WPF application with the following code in the main window
1: using System.Linq;
2: using System.Windows;
3: using Microsoft.Kinect;
4:
5: namespace ElBruno.Rocket.Ui
6: {
7: public partial class MainWindow
8: {
9: private KinectSensor _sensor;
10: private Rocket _rocket;
11: public MainWindow()
12: {
13: InitializeComponent();
14: Loaded += MainWindowLoaded;
15: }
16:
17: private void MainWindowLoaded(object sender, RoutedEventArgs e)
18: {
19: InitRocket();
20: InitKinectSensor();
21: }
22:
23: private void InitRocket()
24: {
25: _rocket = new Rocket(@"vid_0a81", @"pid_ff01");
26: _rocket.Connect();
27: }
28:
29: private void InitKinectSensor()
30: {
31: // validate
32: if (KinectSensor.KinectSensors.Count == 0) return;
33:
34: // init Kinect
35: var parameters = new TransformSmoothParameters
36: {
37: Smoothing = 0.75f,
38: Correction = 0.1f,
39: Prediction = 0.0f,
40: JitterRadius = 0.05f,
41: MaxDeviationRadius = 0.08f
42: };
43:
44: _sensor = KinectSensor.KinectSensors[0];
45: _sensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
46: _sensor.DepthStream.Enable(DepthImageFormat.Resolution320x240Fps30);
47: _sensor.SkeletonStream.Enable(parameters);
48: _sensor.Start();
49: colorViewer.Kinect = _sensor;
50: skeletonViewer.Kinect = _sensor;
51: _sensor.SkeletonFrameReady += SensorSkeletonFrameReady;
52: }
53:
54: private void SensorSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
55: {
56: Skeleton[] skeletons = null;
57: using (var frame = e.OpenSkeletonFrame())
58: {
59: if (frame != null)
60: {
61: skeletons = new Skeleton[frame.SkeletonArrayLength];
62: frame.CopySkeletonDataTo(skeletons);
63: }
64: }
65:
66: if (skeletons == null) return;
67:
68: foreach (var kinectRocketGestures in (
69: from skeleton in skeletons
70: where skeleton.TrackingState == SkeletonTrackingState.Tracked
71: let headJoint = skeleton.Joints[JointType.Head]
72: where headJoint.TrackingState != JointTrackingState.NotTracked
73: select skeleton).Select(skeleton => new KinectRocketGestures(skeleton, _rocket)))
74: {
75: var gesture = kinectRocketGestures.ValidateGestures();
76: textBlockInformation.Text = gesture;
77: }
78: }
79: }
80: }
It is important to note that this window has almost nothing interesting logic only starts the sensors of the Kinect and the Lance missiles and then subscribe to the skeleton update notifications.
In this notification (line 54), it validates that the tracking of the skeleton is correct and then we use a class KinectRocketGestures that is what makes a little magic between Kinect and the Lance missiles.
This class code is as follows
1: using Microsoft.Kinect;
2:
3: namespace ElBruno.Rocket.Ui
4: {
5: class KinectRocketGestures
6: {
7: private readonly Skeleton _skeleton;
8: private readonly Rocket _rocket;
9:
10: public KinectRocketGestures(Skeleton skeleton, Rocket rocket)
11: {
12: _skeleton = skeleton;
13: _rocket = rocket;
14: }
15:
16: public string ValidateGestures()
17: {
18: var gesture = @"Not defined";
19: // STOP
20: // Right hand and Left hand hanging at the side
21: if (_skeleton.Joints[JointType.HandRight].Position.Y < _skeleton.Joints[JointType.HipCenter].Position.Y &&
22: _skeleton.Joints[JointType.HandLeft].Position.Y < _skeleton.Joints[JointType.HipCenter].Position.Y)
23: {
24: _rocket.StopAll();
25: _rocket.StopFiring();
26: _rocket.StopMovements();
27: gesture = @"STOP";
28: return gesture;
29: }
30:
31: // FIRE
32: if (_skeleton.Joints[JointType.HandLeft].Position.Y > _skeleton.Joints[JointType.Head].Position.Y)
33: {
34: gesture = @"FIRE";
35: _rocket.FireOnce();
36: }
37:
38: // MOVE RIGHT OR LEFT
39: // Right hand in front of right shoulder
40: // Right hand below shoulder height but above hip height
41: if (
42: (_skeleton.Joints[JointType.HandRight].Position.Z < _skeleton.Joints[JointType.ElbowRight].Position.Z &&
43: _skeleton.Joints[JointType.HandLeft].Position.Y < _skeleton.Joints[JointType.HipCenter].Position.Y)
44: &&
45: (_skeleton.Joints[JointType.HandRight].Position.Y < _skeleton.Joints[JointType.Head].Position.Y &&
46: _skeleton.Joints[JointType.HandRight].Position.Y > _skeleton.Joints[JointType.HipCenter].Position.Y)
47: )
48: {
49: // Right hand right of right shoulder
50: if (_skeleton.Joints[JointType.HandRight].Position.X > _skeleton.Joints[JointType.ShoulderRight].Position.X)
51: {
52: gesture = @"MOVE RIGHT";
53: _rocket.MoveRight();
54: }
55: // Right hand left of left Shoulder
56: if (_skeleton.Joints[JointType.HandRight].Position.X < _skeleton.Joints[JointType.ShoulderLeft].Position.X)
57: {
58: gesture = @"MOVE LEFT";
59: _rocket.MoveLeft();
60: }
61: }
62:
63: // MOVE UP OR DOWN
64: // Right hand in front of body with Left hand hanging at the side
65: // Right hand between shoulders
66: if (
67: (_skeleton.Joints[JointType.HandRight].Position.Z < _skeleton.Joints[JointType.ShoulderCenter].Position.Z &&
68: _skeleton.Joints[JointType.HandLeft].Position.Y < _skeleton.Joints[JointType.HipCenter].Position.Y)
69: &&
70: (_skeleton.Joints[JointType.HandRight].Position.X < _skeleton.Joints[JointType.ShoulderRight].Position.X &&
71: _skeleton.Joints[JointType.HandRight].Position.X > _skeleton.Joints[JointType.ShoulderLeft].Position.X)
72: )
73: {
74: // Right hand above the shoulders
75: if (_skeleton.Joints[JointType.HandRight].Position.Y > _skeleton.Joints[JointType.ShoulderCenter].Position.Y)
76: {
77: gesture = @"MOVE UP";
78: _rocket.MoveUp();
79: }
80: // Right hand below the chest/gut
81: if (_skeleton.Joints[JointType.HandRight].Position.Y < _skeleton.Joints[JointType.Spine].Position.Y)
82: {
83: gesture = @"MOVE DOWN";
84: _rocket.MoveDown();
85: }
86: return gesture;
87: }
88: }
89: }
90: }
And that’s it! A bit of validation of the right hand and left hand positions and have control of the Lance missiles using Kinect.
Now I’m going fast to the MadridDotNet event and in the next post I put a video and the example of the application code.
Saludos @ La Finca
El Bruno
Leave a comment