Facebook RSS Feed
 
Kinect & Leap Motion: Kinect ile LEGO Mindstorms NXT Robot Kontrolü
Tarih: 02.01.2013, Platform: .NET 4.5, IDE: Visual Studio 2012, Level: 200

Teknik Lego'lar 7'den 70'e meraklısı için yeri gelince oyuncak, yeri gelince ilham kaynağı, yeri gelince de prototip malzemesi olmuştur. Lego Mindstorms NXT kitleriyle; dişli sistemleri, elektrik motorları ve sensörlerden oluşan mekanizmalar yazılımsal olarak kontrol edilebiliyor. Özellikle işini içine elektroniği karıştırmadan, bir yazılımcının robotik sistemlere merhaba demesi mümkün olabiliyor.

Lego Mindstorms NXT kitleri, kendi yazılımı aracılığıyla görsel dil kullanılarak programlanıyor ve istenilen mantıkta çalışıyor. Ayrıca, dahili Bluetooth özelliği sayesinde bilgisayarlar ile bağlantı kurabiliyor, uzaktan kontrol edilebiliyor.

-

Az sonra geliştireceğimiz uygulama, Kinect'in karşısına geçip yapacağımız basit hareketlerle, Bluetooth üzerinden bir Lego robotu yönetmek üzerine olacak. Öyleyse, işe koyulalım!

Öngereksinimler

Bu sistemi kurabilmek için elinizde Kinect sensör, Lego Mindstorms NXT robot kiti ve bilgisayarınıza bağlı Bluetooth donanımı bulunması gerekiyor.

Geliştireceğimiz .NET uygulamasının Lego robotumuz ile Bluetooth üzerinden bağlantı kurması için yardımcı bir dll dosyasına ihtiyacımız var. Bram.NXTSharp.dll adlı bu dosyayı kaynak kodlarının içerisinde bulabilirsiniz.

Çalışma Mantığı

Uygulamamız, önce Kinect ile iskelet yapımızı algılayacak ve pencere içerisinde ellerimizi, omuzumuzu, boyun ve başımızı gösterecek. Sağ elimiz ile sağ omuzumuzun dikey pozisyon farkını hesaplayarak, robotumuzun sağ tekerleğinin yönünü belirleyecek. Aynı mantığı kullanarak, sol tekerleğin de yönü belirlenecek. Bu şekilde, ellerimizi omuz hizzasına göre kaldırıp indirerek robota anlık komutlar göndereceğiz.

NXT Kitinin Yapılandırılması

Öncelikle, Lego Mindstorms NXT robotumuz ile bilgisayarımız arasında Bluetooth bağlantısı kuracağız. (Halihazırda böyle  bir bağlantınız bulunuyorsa, bu aşamayı atlayabilirsiniz.) Mindstorms Brick'imizin Bluetooth ayarlarından On/Off seçeneğini kullanarak Bluetooth bağlantısını açalım ve Visibility ayarını Visible yapalım. Daha sonra, bilgisayarımızdan Bluetooth araması gerçekleştirerek robotu sistemimize ekleyelim. Ekleme tamamlandıktan sonra, Control Panel > Devices and Printers > Unspecified kategorisi altındaki Mindstorms kitinin ayarlarından Services sekmesi içerisinden COM port numarasını öğrenebilirsiniz. Bu COM numarasını uygulamada belirteceğiz.

NXT kitinin A ve B motor portlarına sırasıyla sol ve sağ motoru bağlayacağız. Bundan sonraki Lego tasarımı hayalgücünüze kalıyor...

Uygulama 

Geliştireceğimiz uygulama üzerinde bağlanma butonları, Kinect ile kontrolü aktive eden bir checkbox ve iskelet yapımızı gösteren canvas elementi yer alacak. (İskelet yapısına ulaşım hakkında detaylı bilgi için "Kinect 103: İskelet Yapısına Ulaşım" yazısına gözatabilirsiniz.)

 -

Şimdi, Visual Studio ile "KinectNXT" adında bir WPF uygulaması oluşturalım. Proje referanslarına "Microsoft.Kinect.dll" ve "Bram.NxtSharp.dll" dosyalarını ekleyelim.  ("Bram.NxtSharp.dll" dosyasını ekte bulabilirsiniz.)

Uygulama kodlarımız aşağıdaki gibi olacak:

[XAML] MainWindow.xaml

<Window x:Class="KinectNXT.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Kinect NXT" Height="419" Width="508" Loaded="Window_Loaded" Closing="Window_Closing"
        WindowStartupLocation="CenterScreen" SizeToContent="WidthAndHeight"
        ResizeMode="CanMinimize">
    <Grid>
        <Canvas Height="350" HorizontalAlignment="Left" Name="cnvSkeleton"
                VerticalAlignment="Top" Width="500" Background="#FFE7E5FF" Margin="0,38,0,0">
            <Ellipse Canvas.Left="234" Canvas.Top="69" Height="25" Name="ellipseHead"
                     Width="25" Fill="#FF0062FF" Stroke="{x:Null}"></Ellipse>
            <Ellipse Canvas.Left="35" Canvas.Top="130" Fill="#FF9A9AFF" Height="25"
                     Name="ellipseHandLeft" Stroke="{x:Null}" Width="25" />
            <Ellipse Canvas.Left="440" Canvas.Top="130" Fill="#FF9A9AFF" Height="25"
                     Name="ellipseHandRight" Stroke="{x:Null}" Width="25" />
            <Ellipse Canvas.Left="234" Canvas.Top="111" Fill="Blue" Height="25"
                     Name="ellipseShoulderCenter" Stroke="{x:Null}" Width="25" />
            <Ellipse Canvas.Left="170" Canvas.Top="130" Fill="#FFA7C8FF" Height="25"
                     Name="ellipseShoulderLeft" Stroke="{x:Null}" Width="25" />
            <Ellipse Canvas.Left="305" Canvas.Top="130" Fill="#FFA7C8FF" Height="25"
                     Name="ellipseShoulderRight" Stroke="{x:Null}" Width="25" />
        </Canvas>
        <CheckBox Content="Kinect ile Kontrol" Height="16" HorizontalAlignment="Left"
                  Margin="264,12,0,0" x:Name="chkNUI" VerticalAlignment="Top"
                  Unchecked="chkNUI_Unchecked"/>
        <Button Content="Bağlan" Height="23" HorizontalAlignment="Left" Margin="6,7,0,0"
                x:Name="btnNxtBaglan" VerticalAlignment="Top" Width="124"
                Click="btnNxtBaglan_Click"/>
        <Button Content="Bağlantıyı Kes" Height="23" HorizontalAlignment="Left" Margin="135,7,0,0"
                x:Name="btnNXTBaglantiKes" VerticalAlignment="Top" Width="124"
                Click="btnNXTBaglantiKes_Click"/>
    </Grid>
</Window>

Aşağıdaki kodların içerisinde "nxtBrick.COMPortName" özelliğini robotunuzun COM portu ile değiştirmeniz gerekiyor.

[C#] MainWindow.xaml.cs

using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using Bram.NxtSharp;
using Microsoft.Kinect;
 
namespace KinectNXT
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
 
        #region Ayarlar
        private readonly double tolerans = 0.15;
        private readonly int robotHizi = 100;
        #endregion
 
        #region Kinect
        private Skeleton[] skeletons = new Skeleton[6];
        private KinectSensor kinect;
        #endregion
 
        #region NXT
        NxtBrick nxtBrick = new NxtBrick();
        NxtTankDrive nxtTankDrive = new NxtTankDrive();
        NxtMotor nxtMotorSol = new NxtMotor();
        NxtMotor nxtMotorSag = new NxtMotor();
        #endregion
 
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            // NXT Brick
            nxtBrick.COMPortName = "COM6";                          // Brick bağlantı portu
            nxtBrick.AttachMotor(NxtMotorPort.PortA, nxtMotorSag);  // Port A
            nxtBrick.AttachMotor(NxtMotorPort.PortB, nxtMotorSol);  // Port B
 
            // Sağ Motor
            nxtMotorSag.Port = NxtMotorPort.PortA;                  // Motor portu
            nxtMotorSag.Brick = nxtBrick;                           // Motor brick'i
 
            // Sol Motor
            nxtMotorSol.Port = NxtMotorPort.PortB;                  // Motor portu
            nxtMotorSol.Brick = nxtBrick;                           // Motor brick'i
 
            // Tank Drive
            nxtTankDrive.Motor1 = nxtMotorSol;                      // Sol motor
            nxtTankDrive.Motor2 = nxtMotorSag;                      // Sağ motor
            nxtTankDrive.Brick = nxtBrick;                          // Brick
 
            // Kinect bağlıysa, bulunan ilk Kinect'i ve iskelet algılamasını başlat
            if (KinectSensor.KinectSensors.Count > 0)
            {
                kinect = KinectSensor.KinectSensors[0];
 
                kinect.Start();
 
                TransformSmoothParameters tsp = new TransformSmoothParameters();
                tsp.Smoothing = 0.55f;
                tsp.Correction = 0.1f;
                tsp.Prediction = 0.1f;
                tsp.JitterRadius = 0.4f;
                tsp.MaxDeviationRadius = 0.4f;
 
                kinect.SkeletonStream.Enable(tsp);
 
                kinect.SkeletonFrameReady
                    += new EventHandler<SkeletonFrameReadyEventArgs>(Kinect_SkeletonFrameReady);
            }
        }
 
        private void Kinect_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
        {
            Skeleton iskelet;
 
            try
            {
                // İskelet verisini al
                if (e.OpenSkeletonFrame() != null)
                    e.OpenSkeletonFrame().CopySkeletonDataTo(skeletons);
 
                // İlk algılanan iskeleti seç
                iskelet = (from s in skeletons
                           where s.TrackingState == SkeletonTrackingState.Tracked
                           select s).FirstOrDefault();
            }
            catch (Exception)
            {
                iskelet = null;
            }
 
            if (iskelet != null)
            {
                // İskelet yapısını göster
                ElipsleriGoster(iskelet);
 
                // Robotu kontrol et
                if (chkNUI.IsChecked == true)
                    RobotKontrol(iskelet);
            }
        }
 
        private void ElipsleriGoster(Skeleton iskelet)
        {
            ElipsKonumlandir(ellipseHead, iskelet.Joints[JointType.Head]);
            ElipsKonumlandir(ellipseHandLeft, iskelet.Joints[JointType.HandLeft]);
            ElipsKonumlandir(ellipseHandRight, iskelet.Joints[JointType.HandRight]);
            ElipsKonumlandir(ellipseShoulderLeft, iskelet.Joints[JointType.ShoulderLeft]);
            ElipsKonumlandir(ellipseShoulderCenter, iskelet.Joints[JointType.ShoulderCenter]);
            ElipsKonumlandir(ellipseShoulderRight, iskelet.Joints[JointType.ShoulderRight]);
        }
 
        private void ElipsKonumlandir(FrameworkElement ellipse, Joint joint)
        {
            Canvas.SetLeft(ellipse, (joint.Position.X + 1) * (500 / 2));
            Canvas.SetTop(ellipse, (350 - (joint.Position.Y + 1) * (350 / 2)));
        }
 
        private void RobotKontrol(Skeleton iskelet)
        {
            int solPalet, sagPalet;
 
            // SOL PALET
 
            // Sol palet ileri
            if ((iskelet.Joints[JointType.HandLeft].Position.Y - tolerans)
                > iskelet.Joints[JointType.ShoulderLeft].Position.Y)
                solPalet = 1;
 
            // Sol palet geri
            else if ((iskelet.Joints[JointType.HandLeft].Position.Y + tolerans)
                < iskelet.Joints[JointType.ShoulderLeft].Position.Y)
                solPalet = -1;
 
            // Sol palet serbest
            else
                solPalet = 0;
 
            // SAĞ PALET
 
            // Sağ palet ileri
            if ((iskelet.Joints[JointType.HandRight].Position.Y - tolerans)
                > iskelet.Joints[JointType.ShoulderRight].Position.Y)
                sagPalet = 1;
 
            // Sağ palet geri
            else if ((iskelet.Joints[JointType.HandRight].Position.Y + tolerans)
                < iskelet.Joints[JointType.ShoulderRight].Position.Y)
                sagPalet = -1;
 
            // Sağ palet serbest
            else
                sagPalet = 0;
 
            // TANK DRIVE KOMUTU
 
            // Tank Drive'a ileri komutu gönder
            if (solPalet > 0 && sagPalet > 0)
                nxtTankDrive.MoveForward(robotHizi, 0);
 
            // Tank Drive'a geri komutu gönder
            else if (solPalet < 0 && sagPalet < 0)
                nxtTankDrive.MoveBack(robotHizi, 0);
 
            // Tank Drive'a sağa dönüş kontrolü gönder
            else if (solPalet > 0 && sagPalet < 0)
                nxtTankDrive.TurnRight(robotHizi, 0);
 
            // Tank Drive'a sola dönüş komutu gönder
            else if (solPalet < 0 && sagPalet > 0)
                nxtTankDrive.TurnLeft(robotHizi, 0);
 
            // Tank Drive'a serbest duruş komutu gönder
            else
                nxtTankDrive.Coast();
        }
 
        private void btnNxtBaglan_Click(object sender, RoutedEventArgs e)
        {
            // Bağlı değilse, robota bağlan
            if (!nxtBrick.IsConnected)
                nxtBrick.Connect();
        }
 
        private void btnNXTBaglantiKes_Click(object sender, RoutedEventArgs e)
        {
            // Bağlıysa, robotla olan bağlantıyı kes
            if (nxtBrick.IsConnected)
                nxtBrick.Disconnect();
        }
 
        private void chkNUI_Unchecked(object sender, RoutedEventArgs e)
        {
            // Motorları serbest moda al
            nxtTankDrive.Coast();
        }
 
        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            // Uygulama kapanırken, Kinect çalışıyorsa Kinect'i durdur
            if (kinect.IsRunning)
                kinect.Stop();
        }
    }
}

Sistemi çalıştırmak için, öncelikle Lego robotunuzu açın ve ana ekranda bekletin. Yazdığımız uygulamayı çalıştırarak bağlan butonuna basın. "Kinect ile Kontrol" checkbox'ı seçili olduğu sürece el hareketlerinizle robotu kontrol edebileceksiniz. checkbox'ın seçimini kaldırdığınızda, robotunuzun tekerlekleri serbest moda geçecek (duracak) ve Kinect ile kontrolü devre dışı kalacaktır...


Ek Dosya: Uygulama Kodları ve NxtSharp Kütüphanesi
Okunma Sayısı: 3646

comments powered by Disqus
 
Hoşgeldiniz!
Son güncelleme: 25.12.2016
-
Yeni Teknik Yazılar
Latte Panda İncelemesi
Turta IoT HAT İncelemesi
USB Gamepad Kullanımı
GPIO Kullanımı
VEML6075 UV Sensör Kullan...
-
İlgili Gruplar
.NET MF ve Gadgeteer FB Grubu
İst. IoT & Wearables Meet-up
-
 

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.Copyright © 1999 - 2017, Umut Erkal. Bu materyal, "Creative Commons Public Licence" ile sunulmuştur.
Kaynak göstererek ve ücretsiz olarak, aynı şartlar altında paylaşabilir ve kullanabilirsiniz. | Kullanım Sözleşmesi