🔍

advanced object touching with LeapMotion in Unity/C#


THIS IS WORK IN PROGRESS.

Arduino & C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class hand_position_controller : MonoBehaviour
{
    
   public Transform lh_base;
   public Transform rh_base;

   public GameObject lh_go;
   public GameObject rh_go;
 
   public Transform orb_base;

   public static float hands_distance = 1f;

   public static int lha = 180;
   public static int rha = 180;

   bool lh_present = false;
   bool rh_present = false;
   
    // Update is called once per frame
    void Update()
    {
         
        Debug.DrawLine( lh_base.transform.position, orb_base.transform.position, Color.yellow,.01f );
 
         Debug.DrawLine( rh_base.transform.position, orb_base.transform.position, Color.yellow,.01f );
 
         Debug.DrawLine( rh_base.transform.position, lh_base.transform.position, Color.red,.01f );
 
         Debug.DrawLine( rh_base.transform.position, rh_base.transform.position+rh_base.transform.up*.1f, Color.blue,.01f );
 
          Debug.DrawLine( lh_base.transform.position, lh_base.transform.position+lh_base.transform.up*.1f, Color.blue,.01f );
 

        Vector3 lhdir = lh_base.transform.position - orb_base.transform.position;
         Vector3 rhdir = rh_base.transform.position - orb_base.transform.position;
       // lhdir = lhdir.normalized;
       

         Vector3  forward = -transform.forward;
         float lh_angle = Vector3.SignedAngle(lhdir,forward,Vector3.up);
         lha = (int)( 360f-(lh_angle+180f) );

        float rh_angle = Vector3.SignedAngle(rhdir,forward,Vector3.up);
         rha = (int)( 360f-(rh_angle+180f) );

        if(lh_go.activeSelf){lh_present=true;}else{lh_present=false;}
        if(rh_go.activeSelf){rh_present=true;}else{rh_present=false;}
        
        if(lh_present && rh_present){
        hands_distance = Vector3.Distance(rh_base.transform.position, lh_base.transform.position)*2f;
        hands_distance = Mathf.Clamp(hands_distance,0,1f); 
        }else{
            hands_distance = 1f;

        }

    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class sender_script : MonoBehaviour
{
    // Class object reference
    public PTP port;

    // Start is called before the first frame update
    void Start()
    {
        SendData();
    }

    public void SendData()
    {
        // 
        // Transfer data
        // 
        PTP.DATA d = new PTP.DATA();

        int lha = hand_position_controller.lha;//  180;// (int)Random.Range(0,270);
        int rha = hand_position_controller.rha;//180;// (int)Random.Range(0,270);
        float sum = (1f-hand_position_controller.hands_distance)*255f;// (int)(Mathf.PerlinNoise(Time.time*2.1f,12f)*255f);

         //sum *= 0f;// (Mathf.Sin(Time.time*1f)+1);
 
        // Basic primitive types
        // 
        d.PushToPackBool(true);
        d.PushToPackInt( lha );
        d.PushToPackInt( rha );
        d.PushToPackInt( (int)sum );
         
        // Handshake String
        // 
        d.PushToPackString("fikki");

        // 
        // Transfer
        // 
        port.TransceiveData(d);

        Invoke("SendData",.4f);

    }

    
}


#include "TP4/STP4.h"

#include <Adafruit_NeoPixel.h>
#include <avr/power.h>
#define PIN            6
#define NUMPIXELS      32
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

// Port speed
#define baudRate 115200

// Open serial port
STP4* port;

// 
char* str_test = "fikki";

float ta_one = 360;
float ta_two = 0;

float stepper = 11.25;
float angle_one = 0;
float angle_two = 0;

float main_sum = 0;
float  main_sum_t = 0;

float cursor_wideness =  3.2;

void setup()
{
   
  port = new STP4(baudRate);
   pinMode(13, OUTPUT);
   digitalWrite(13, LOW);

  pixels.begin();
  initLEDS();
  
  
}

void loop()
{

  
  // 1. Wait Data
  if (port->Listen())
  {
   
    
    bool          val_bool   = port->GetVal<bool>();
    int           lha    = port->GetVal<int>();
    int           rha    = port->GetVal<int>();
    int           sum    = port->GetVal<int>();

    ta_one = lha;
    ta_two = rha;
    main_sum_t = sum;
    

     // HANDSHAKE String
    // 
    char* str_chr = port->GetArr<char>();  

     // 4. Clear RAM
   // delete[] arr_int;
    delete[] str_chr;
  }


  int smooth_amount = 7;
  angle_one = angle_one + ((ta_one -angle_one)/smooth_amount);

  angle_two = angle_two + ((ta_two -angle_two)/smooth_amount);

  main_sum = main_sum + ((main_sum_t -main_sum)/(smooth_amount*.5));
 
  operateSTRIPE();
 
}


older protos

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class hand_position_controller : MonoBehaviour
{
   
   public Transform lh_base;
   public Transform rh_base;

   public Transform orb_base;
   
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
        Debug.DrawLine( lh_base.transform.position, orb_base.transform.position, Color.yellow,.01f );

         Debug.DrawLine( rh_base.transform.position, orb_base.transform.position, Color.yellow,.01f );

         Debug.DrawLine( rh_base.transform.position, lh_base.transform.position, Color.red,.01f );

         Debug.DrawLine( rh_base.transform.position, rh_base.transform.position+rh_base.transform.up*.1f, Color.blue,.01f );

          Debug.DrawLine( lh_base.transform.position, lh_base.transform.position+lh_base.transform.up*.1f, Color.blue,.01f );

    }
}


void operateSTRIPE(){

  float mainpulse =  main_sum*.3;// 0;// (sin(millis()*.001)+1)*12;

  for(int i=0;i<NUMPIXELS;i++){
 
        float disti = abs(angle_one/stepper-float(i));

       float disti2 = abs( angle_two/stepper - float(i) );

         int bri = 0;
         int bri2 = 0;

        if(disti<cursor_wideness){
              bri = (cursor_wideness-disti  )*90;
        } 

      if(disti2<cursor_wideness){
              bri2=(cursor_wideness-disti2   )*90;
        } 

        bri = constrain(bri,0,200);
        bri2 = constrain(bri2,0,200);

        int brisum =  (bri+bri2); 
        
        brisum = constrain(brisum,0,255);

        brisum *= main_sum/float(255) ;
        
        pixels.setPixelColor(i, pixels.Color(brisum ,brisum,brisum )); // Moderately bright green color.
        pixels.show(); // This sends the updated pixel color to the hardware.
  

  }

 
 }

 // ----------------------------------


 void initLEDS(){

  for(int i=0;i<NUMPIXELS;i++){

        
        pixels.setPixelColor(i, pixels.Color(0,0,0)); // Moderately bright green color.
        pixels.show(); // This sends the updated pixel color to the hardware.
  

  }
 delay(64);

}


using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class aFINGERTIP {

	public int id;
    public Transform trans;
    public bool is_inside = false;
    public bool is_touching = false;
    public Vector3 ppos = Vector3.zero;
    public Vector3 svel = Vector3.zero;

    public aFINGERTIP(int _id, Transform _tr){
       this.id = _id;
       this.trans = _tr;

    }

    public void updateFT(){

        Vector3 diff = ppos - trans.position;

        svel = Vector3.Slerp(svel,diff,.03f);
        Debug.DrawLine( trans.position, trans.position+ svel*22f,Color.blue,.01f );

        //smooth_velocity
        ppos = trans.position;
    }

}



public class fingertip_touch_tracker : MonoBehaviour
{
   

    // todo >  make surface touch event!
    // track fingertip velocity

    aFINGERTIP[] allFINGERTIPS;

    public Transform[] fingertips;
    public GameObject target_go;
    Collider target_collider;

     RaycastHit hit;

     public int touching_fingertips_sum = 0;
     public int digging_fingertips_sum = 0;
   
    // Start is called before the first frame update
    void Start()
    {
        target_collider = target_go.GetComponent<Collider>();
        init();
    }

    void init(){

        allFINGERTIPS = new aFINGERTIP[fingertips.Length];

        for(int i=0;i<fingertips.Length;i++){

            allFINGERTIPS [ i ] = new aFINGERTIP(i,fingertips[i]);
            
        }

    }

    // Update is called once per frame
    void Update()
    {
        touching_fingertips_sum = 0;
         digging_fingertips_sum = 0;

        for(int i=0;i<allFINGERTIPS.Length;i++){

            aFINGERTIP cft = allFINGERTIPS[i];

            cft.updateFT();

            Vector3 dir = target_go.transform.position - cft.trans.position;
 
             if (Physics.Raycast(cft.trans.position, transform.TransformDirection(dir), out hit, .25f))
        {
                 float cdist = Vector3.Distance(hit.point,cft.trans.position);
                 Debug.DrawRay(hit.point, hit.transform.TransformDirection(hit.normal) * cdist, Color.red);

                if(cdist<.02f){

                    cft.is_touching = true;
                    touching_fingertips_sum++;
                }

                if(cdist>.04f){
                    cft.is_touching = false;
                }

                cft.is_inside = false;
        }else{

                bool isin = IsInside(target_collider, cft.trans.position);
                if(isin){
                   // Debug.Log("is in:" + i);
                   // touching_fingertips_sum++;
                    cft.is_inside = true;
                    digging_fingertips_sum++;
                }else{
                    cft.is_inside = false;
                }

        }
         

        }


    }


    public static bool IsInside(Collider c, Vector3 point)
         {
             Vector3 closest = c.ClosestPoint(point);
             // Because closest=point if point is inside - not clear from docs I feel
             return closest == point;
         }




     void OnDrawGizmos()
    {

       // Debug.Log("yoo"+  allFINGERTIPS.Length);
        for(int i=0;i<allFINGERTIPS.Length;i++){

            aFINGERTIP cft = allFINGERTIPS[i];

            //Debug.Log(cft.trans.position);

            if(cft.is_inside){

                float s = cft.svel.magnitude*10f;
                // Draw a yellow sphere at the transform's position
                Gizmos.color = Color.yellow;
                Gizmos.DrawSphere(cft.trans.position, s);
           }
        }
    }
}