Sweep a servo according to Proximity sensor measure

Dependencies:   Servo X_NUCLEO_6180XA1 mbed

Fork of HelloWorld_6180XA1 by ST

Middlewares/ST/STM32_HMI_HandGesture/HmiBBGesture.cpp

Committer:
gallonm
Date:
2015-10-27
Revision:
14:946e62f44f4f

File content as of revision 14:946e62f44f4f:

/* ----------------------------------------------------------------------
 * Copyright (C) 2014 STMicroelectronics. All rights reserved.
 *
 * Project: BB gesture recognition
 * Title:   HmiBBGesture
 *
 * Description: Gesture recognition - left, right, tap
 *
 * 20/10/14
 * Changed from proximity to range
 * Ultra simplified version
 *
 * -------------------------------------------------------------------- */

//#define PRINT_DEBUG_
#define USE_MICRO_

#include "HmiBBGesture.h"
#include "stm32f4xx_hal.h"
#include <stdint.h>
#include <stdio.h>

#ifdef USE_MICRO_
//#include "vl6180x_shield.h"
//#include "platform.h"
//#define GET_TIME_STAMP() ((int)timer_get_clock_time_msecs())  // for Mbed
#define GET_TIME_STAMP()  (int32_t)HAL_GetTick()   // for Cube
#else
/* PC config */
#include <windows.h>
#define GET_TIME_STAMP() ((int)timeGetTime())
#endif

#ifdef PRINT_DEBUG_
#ifdef USE_MICRO_
static char str[80];
//extern void serial_print(const char *str);
#define serial_print(str)  printf(str)
#endif
#endif

#define HMI_SIGNAL_CODE_DROP_DOWN 1
#define HMI_SIGNAL_CODE_RAISE_UP 2
#define HMI_SIGNAL_CODE_DOWN_STATE 3
#define HMI_SIGNAL_CODE_UP_STATE 4
#define HMI_SIGNAL_CODE_NULL -1

#define HMI_TAP_CODE_SINGLE 0
#define HMI_TAP_CODE_DOUBLE 1
#define HMI_TAP_CODE_HOLD 2
#define HMI_TAP_CODE_NULL -1




/**********************************************************************************
 *
 *
 *  Gesture recognition class
 *
 *
 **********************************************************************************/


void HmiBBGesture::Init(int threshold_mm, int tap_threshold_mm, int min_hold_duration_ms, int min_swipe_duration_ms, int max_gesture_duration_ms )
{
    m_motion_r.Init( threshold_mm );
    m_motion_l.Init( threshold_mm );
    m_tap_det.Init( tap_threshold_mm, 150, min_hold_duration_ms, false, 0 );
    m_fsm_state = 0;
    m_timestamp = GET_TIME_STAMP();
    m_min_swipe_ms   = min_swipe_duration_ms;
    m_max_gesture_ms = max_gesture_duration_ms;
    m_gesture_starts_from_right = false;
}

int HmiBBGesture::Update(int range_r, int range_l, int *gesture_duration_ms)
{
    int r_code, r_ms;
    int l_code, l_ms;
    int duration;
    int gesture_code = HMI_BB_GESTURE_CODE_NULL;
    *gesture_duration_ms = 0;

    r_code = m_motion_r.Update( range_r , &r_ms );
    l_code = m_motion_l.Update( range_l , &l_ms );
//        printf ("r_ms: %d l_ms: %d\n\r",r_ms, l_ms);
    switch( m_fsm_state )
    {
    case 1: // gesture ends

        duration = GET_TIME_STAMP() - m_timestamp;
        if(duration > m_max_gesture_ms)  // gesture is too long - discard it
        {
            m_fsm_state = 0;
#ifdef PRINT_DEBUG_

#ifdef USE_MICRO_
sprintf(str, "FSM 1 - Discarded %d %d %d mts %d\n",r_code,l_code,duration, m_timestamp);
serial_print(str);
#else
printf("FSM 1 - Discarded %d %d %d \n",r_code,l_code,duration);
#endif

#endif
        }
        else if( (m_gesture_starts_from_right && l_code == HMI_SIGNAL_CODE_RAISE_UP ) ||
                 (m_gesture_starts_from_right==false && r_code == HMI_SIGNAL_CODE_RAISE_UP) )
        {
            m_fsm_state = 0;
            if( duration > (m_min_swipe_ms/2) )
            {
                gesture_code = ( m_gesture_starts_from_right ) ? HMI_BB_GESTURE_CODE_RIGHT : HMI_BB_GESTURE_CODE_LEFT;
                *gesture_duration_ms = duration;
#ifdef PRINT_DEBUG_

#ifdef USE_MICRO_
sprintf(str,"FSM 2 - Recognized %d\n",gesture_code);
serial_print(str);
#else
printf("FSM 2 - Recognized %d\n",gesture_code);
#endif

#endif
            }
#ifdef PRINT_DEBUG_
            else
            {
#ifdef USE_MICRO_
sprintf(str,"FSM 1 - Discarded %d %d %d \n",r_code,l_code,duration);
serial_print(str);
#else
printf("FSM 1 - Discarded %d %d %d \n",r_code,l_code,duration);
#endif
            }
#endif
        }

        break;

    case 0: // gesture starts
        if( l_code == HMI_SIGNAL_CODE_DOWN_STATE && r_code == HMI_SIGNAL_CODE_RAISE_UP && r_ms > m_min_swipe_ms )
        {
            m_gesture_starts_from_right = true;
            m_fsm_state = 1;
            m_timestamp = GET_TIME_STAMP();
            m_var_max_gesture_ms = r_ms;
#ifdef PRINT_DEBUG_

#ifdef USE_MICRO_
sprintf(str,"FSM 0 - Right started %d\n",r_ms);
serial_print(str);
#else
printf("FSM 0 - Right started %d\n",r_ms);
#endif

#endif
        }
        else if( l_code == HMI_SIGNAL_CODE_RAISE_UP && r_code == HMI_SIGNAL_CODE_DOWN_STATE && l_ms > m_min_swipe_ms )
        {
            m_gesture_starts_from_right = false;
            m_fsm_state = 1;
            m_timestamp = GET_TIME_STAMP();
            m_var_max_gesture_ms = l_ms;
#ifdef PRINT_DEBUG_

#ifdef USE_MICRO_
sprintf(str,"FSM 0 - Left started %d\n",l_ms);
serial_print(str);
#else
printf("FSM 0 - Left started %d\n",l_ms);
#endif

#endif
        }
        break;

    default:
        break;
    };

    if( m_tap_det.Update((range_r+range_l)/2,&duration) == HMI_TAP_CODE_HOLD )
    {
        gesture_code = HMI_BB_GESTURE_CODE_TAP;
        *gesture_duration_ms = duration;
        m_fsm_state = 0;
    }

    return gesture_code;
}


/**********************************************************************************
 *
 *
 *  MotionDetector class
 *
 *
 **********************************************************************************/

void MotionDetector::Init(int threshold)
{
    m_threshold = threshold;
    m_runonce = true;
}


int MotionDetector::Update(int sample,int *duration)
{
    int return_code;
    bool belowCurrent, isContinuous;


    // run once
    if( m_runonce )
    {
        m_runonce = false;
        m_timestamp = GET_TIME_STAMP();
        m_prev_sample = sample;
        belowCurrent  = (sample < m_threshold);
        isContinuous  = true;
        return_code = ( belowCurrent ) ? HMI_SIGNAL_CODE_DOWN_STATE : HMI_SIGNAL_CODE_UP_STATE;
        *duration = 1;
        return return_code;
    }

    *duration = 0;
    return_code = HMI_SIGNAL_CODE_NULL;
    belowCurrent  = (sample < m_threshold);
    isContinuous  = ( belowCurrent ==  (m_prev_sample < m_threshold));
    m_prev_sample = sample;

    // update
    *duration = GET_TIME_STAMP() - m_timestamp;
    if( isContinuous )
    {
        return_code = ( belowCurrent ) ? HMI_SIGNAL_CODE_DOWN_STATE : HMI_SIGNAL_CODE_UP_STATE;
    }
    else
    {
        return_code = ( belowCurrent ) ? HMI_SIGNAL_CODE_DROP_DOWN : HMI_SIGNAL_CODE_RAISE_UP;
        m_timestamp = GET_TIME_STAMP();
    }

    return return_code;
}



/**********************************************************************************
 *
 *
 *  TapDetector
 *
 *
 **********************************************************************************/
void TapDetector::Init( int threshold, int min_down_duration_ms, int min_hold_duration_ms, bool enable_double_tap, int double_tap_min_duration_ms)
{
    m_threshold = threshold;
    m_motion.Init( threshold );
    m_min_down_duration_ms = min_down_duration_ms;
    m_min_hold_duration_ms = min_hold_duration_ms;
    m_min_dtap_duration_ms = double_tap_min_duration_ms;
    m_notify_hold = true;
    m_notify_dtap = enable_double_tap;
    m_timestamp = GET_TIME_STAMP();
}

int TapDetector::Update( int sample, int *duration )
{
    int return_code;
    int motion_code,motion_duration;

    return_code = HMI_TAP_CODE_NULL;
    *duration = 0;
    motion_code = m_motion.Update(sample, &motion_duration);

    // hold condition - down_duration > hold_time
    if( motion_code == HMI_SIGNAL_CODE_DOWN_STATE && motion_duration > m_min_hold_duration_ms )
    {
        if( m_notify_hold )
        {
            return_code = HMI_TAP_CODE_HOLD;
            m_notify_hold = false; // to avoid continue notification ( anti flood )
            *duration = motion_duration;
        }
    }
    else if( motion_code == HMI_SIGNAL_CODE_RAISE_UP )
    {
        m_notify_hold = true;
        /* TODO add TAP single/double code */
    }

    return return_code;
}