一、PAJ7620

1.介绍

PAJ7620U2 芯片是原相科技(PixArt)公司推出的一款光学数组式传感器,芯片内置集成光源和环境光抑制滤波的 LED、镜头和手势识别传感器,能在黑暗或低光环境下工作,同时内置了支持九种手势的手势识别和物体接近检测功能。手势识别模块使用II2C接口,使用相应的库函数即可编程控制,手势识别模块返回的信号可用作为机器人接收的控制信号,从而实现对机器人的控制。内置的识别算法相当智能,能够把双手从生硬的按键中解放出来。手势识别传感器可用于非接触式控制场景如非接触式鼠标,智能家居,汽车点击设备控制,机器人交互等。

在这里插入图片描述

2.模块特性

  1. 9种手势识别
    在这里插入图片描述
  2. 接口:IIC接口通讯协议
  3. 工作电压:3.3V-5.0V
  4. 手势速度在正常模式下为60°/S至600°/S,游戏模式为60°/S至1200°/S
  5. 环境光免疫力:<100K Lux
  6. 工作电流:3mA-10mA
  7. 模块尺寸:20mm*15mm

3.模块原理

PAJ7620U2手势传感器的工作原理是基于红外线反射和类似微软Kinect的深度视觉技术实现的。

它使用一个由红外发光二极管(IR-LED)和一对红外光传感器(IR photodiode)组成的衍射贴片(Diffraction Gratings)矩阵来发射和接收红外光信号,这样可以让传感器从各个角度接收到反射回来的红外线。当用户握手、挥手或移动其他体部,手或者身体会产生细微的变化,这些变化会导致返回传感器的反射光强度和相位发生变化。PAJ7620U2手势传感器通过计算这些光学特征的变化来识别不同的手势并跟踪其运动轨迹。

与此同时,PAJ7620U2还使用类似Kinect的深度视觉技术,来辅助判断物体和用户之间的距离。 它可以通过红外光投射在用户身上产生的影子来获得深度信息。PAJ7620U2将反射和深度信息结合起来进行处理,可以更加精确地识别大量的手势。

因为它不需要用户直接接触设备,所以可以提供更加方便、舒适和卫生的交互方式。同时,PAJ7620U2的应用范围较广,不受环境光、皮肤颜色等因素的干扰,适用于室内、室外等不同场景。

4.原理图

在这里插入图片描述

5.内部框图

在这里插入图片描述
其中,I2C_SCL 和 I2C_SDA 是连接 MCU 的 IIC 接口,MCU 通过这个 IIC 接口来控制PAJ7620U2。另外 PAJ7620U2 内部还自带了 LED 驱动器、传感器感应阵列、目标信息提取阵列和手势识别阵列。PAJ7620U2 在工作时,会通过内部的 LED 驱动器驱动红外 LED 向外发射红外线信号,当传感器阵列在有效的距离中探测到物体时,目标信息提取阵列会对探测目标进行特征原始数据处理的获取,获取的数据会存储在寄存器中,同时手势识别阵列会对原始数据进行处理,最后将手势识别结果保存到寄存器中,外部控制器通过 IIC 接口可对原始数据和手势识别结果进行读取。

二、软件

以下代码来自正点原子–战舰STM32F103开发板。

1.手势识别

在这里插入图片描述
先初始化ATK-MS7620 模块,然后将 ATK-MS7620 模块配置为手势检测模式,接下来就可以获取
ATK-MS7620 模块在手势检测模式下检测到的手势,并将获取到的结果实时地通过串口输出。

/**
 * @brief       例程演示入口函数
 * @param       无
 * @retval      无
 */
void demo_run(void)
{
    uint8_t ret;
    atk_ms7620_gesture_t gesture;
    
    /* 初始化ATK-MS7620模块 */
    ret = atk_ms7620_init();
    if (ret != 0)
    {
        printf("ATK-MS7620 init failed!\r\n");
        while (1)
        {
            LED0_TOGGLE();
            delay_ms(200);
        }
    }
    
    /* 配置ATK-MS7620模块为手势检测模式 */
    ret = atk_ms7620_mode_config(ATK_MS7620_MODE_GESTURE);
    if (ret != 0)
    {
        printf("ATK_MS7620 config failed!\r\n");
        while (1)
        {
            LED0_TOGGLE();
            delay_ms(200);
        }
    }
    
    printf("ATK-MS7620 config succedded!\r\n");
    
    while (1)
    {
        /* 获取手势 */
        ret = atk_ms7620_get_gesture(&gesture);
        if (ret == ATK_MS7620_EOK)
        {
            switch (gesture)
            {
                case ATK_MS7620_GESTURE_UP:
                {
                    printf("Gesture: Up\r\n");
                    break;
                }
                case ATK_MS7620_GESTURE_DOWN:
                {
                    printf("Gesture: Down\r\n");
                    break;
                }
                case ATK_MS7620_GESTURE_LEFT:
                {
                    printf("Gesture: Left\r\n");
                    break;
                }
                case ATK_MS7620_GESTURE_RIGHT:
                {
                    printf("Gesture: Right\r\n");
                    break;
                }
                case ATK_MS7620_GESTURE_FORWARD:
                {
                    printf("Gesture: Forward\r\n");
                    break;
                }
                case ATK_MS7620_GESTURE_BACKWARD:
                {
                    printf("Gesture: Backward\r\n");
                    break;
                }
                case ATK_MS7620_GESTURE_CLOCKWISE:
                {
                    printf("Gesture: Clockwise\r\n");
                    break;
                }
                case ATK_MS7620_GESTURE_ANTICLOCKWISE:
                {
                    printf("Gesture: Anticlockwise\r\n");
                    break;
                }
                case ATK_MS7620_GESTURE_WAVE:
                {
                    printf("Gesture: Wave\r\n");
                    break;
                }
                default:
                {
                    break;
                }
            }
        }
    }
}

1.1 初始化ATK-MS7620模块

/**
 * @brief       ATK-MS7620模块初始化
 * @param       无
 * @retval      ATK_MS7620_EOK  : ATK-MS7620模块初始化成功
 *              ATK_MS7620_ERROR: ATK-MS7620模块初始化失败
 */
uint8_t atk_ms7620_init(void)
{
    uint8_t ret;
    
    delay_ms(1);                            /* 等待至少700us */
    atk_ms7620_iic_init();                  /* 初始化IIC接口 */
    ret = atk_ms7620_get_wakeup_status();   /* 获取唤醒状态 */
    if (ret != ATK_MS7620_EOK)
    {
        return ATK_MS7620_ERROR;
    }
    atk_ms7620_initial_register();          /* 初始化寄存器配置 */
    
    return ATK_MS7620_EOK;
}

1.2 配置ATK-MS7620模块为手势检测模式

/**
 * @brief       配置ATK-MS7620模块的模式
 * @param       mode: ATK_MS7620_MODE_PS     : 接近检测模式
 *                    ATK_MS7620_MODE_GESTURE: 手势检测模式
 * @retval      ATK_MS7620_EOK   : 模式配置成功
 *              ATK_MS7620_EINVAL: 函数参数有误
 */
uint8_t atk_ms7620_mode_config(atk_ms7620_mode_t mode)
{
    uint8_t (*array)[2];
    uint8_t array_size;
    uint8_t array_index;
    
    switch (mode)
    {
        case ATK_MS7620_MODE_PS:
        {
            array = change_to_proximity_register_array;
            array_size = sizeof(change_to_proximity_register_array) / sizeof(change_to_proximity_register_array[0]);
            break;
        }
        case ATK_MS7620_MODE_GESTURE:
        {
            array = change_to_gesture_register_array;
            array_size = sizeof(change_to_gesture_register_array) / sizeof(change_to_gesture_register_array[0]);
            break;
        }
        default:
        {
            return ATK_MS7620_EINVAL;
        }
    }
    
    for (array_index=0; array_index<array_size; array_index++)
    {
        atk_ms7620_write_byte(ATK_MS7620_IIC_ADDR, array[array_index][0], array[array_index][1]);
    }
    
    return ATK_MS7620_EOK;
}

1.3 获取手势

/**
 * @brief       ATK-MS7620模块获取手势
 * @param       gesture: 手势
 * @retval      ATK_MS7620_EOK   : 获取手势成功
 *              ATK_MS7620_ERROR : 获取手势失败
 *              ATK_MS7620_EINVAL: 函数参数有误
 */
uint8_t atk_ms7620_get_gesture(atk_ms7620_gesture_t *gesture)
{
    uint8_t ret;
    union
    {
        uint8_t byte[2];
        uint16_t halfword;
    }_flag;
    
    if (gesture == NULL)
    {
        return ATK_MS7620_EINVAL;
    }
    
    atk_ms7620_switch_reg_bank(ATK_MS7620_BANK0);
    ret = atk_ms7620_read_byte(ATK_MS7620_IIC_ADDR, ATK_MS7620_REG_INT_FLAG_1, &_flag.byte[0]);
    ret += atk_ms7620_read_byte(ATK_MS7620_IIC_ADDR, ATK_MS7620_REG_INT_FLAG_2, &_flag.byte[1]);
    if (ret != ATK_MS7620_EOK)
    {
        return ATK_MS7620_ERROR;
    }
    
    switch (_flag.halfword)
    {
        case ATK_MS7620_GES_UP_FLAG:
        {
            *gesture = ATK_MS7620_GESTURE_UP;
            break;
        }
        case ATK_MS7620_GES_DOWN_FLAG:
        {
            *gesture = ATK_MS7620_GESTURE_DOWN;
            break;
        }
        case ATK_MS7620_GES_LEFT_FLAG:
        {
            *gesture = ATK_MS7620_GESTURE_LEFT;
            break;
        }
        case ATK_MS7620_GES_RIGHT_FLAG:
        {
            *gesture = ATK_MS7620_GESTURE_RIGHT;
            break;
        }
        case ATK_MS7620_GES_FORWARD_FLAG:
        {
            *gesture = ATK_MS7620_GESTURE_FORWARD;
            break;
        }
        case ATK_MS7620_GES_BACKWARD_FLAG:
        {
            *gesture = ATK_MS7620_GESTURE_BACKWARD;
            break;
        }
        case ATK_MS7620_GES_CLOCKWISE_FLAG:
        {
            *gesture = ATK_MS7620_GESTURE_CLOCKWISE;
            break;
        }
        case ATK_MS7620_GES_ANTICLOCKWISE_FLAG:
        {
            *gesture = ATK_MS7620_GESTURE_ANTICLOCKWISE;
            break;
        }
        case ATK_MS7620_GES_WAVE_FLAG:
        {
            *gesture = ATK_MS7620_GESTURE_WAVE;
            break;
        }
        default:
        {
            return ATK_MS7620_ERROR;
        }
    }
    
    return ATK_MS7620_EOK;
}

2.接近检测

这段代码的作用是初始化ATK-MS7620模块,配置为接近检测模式,并不断获取物体的亮度和大小信息,并将这些信息通过串口打印输出。

/**
 * @brief       例程演示入口函数
 * @param       无
 * @retval      无
 */
void demo_run(void)
{
    uint8_t ret;
    uint8_t brightness;
    uint16_t size;
    
    /* 初始化ATK-MS7620模块 */
    ret = atk_ms7620_init();
    if (ret != 0)
    {
        printf("ATK-MS7620 init failed!\r\n");
        while (1)
        {
            LED0_TOGGLE();
            delay_ms(200);
        }
    }
    
    /* 配置ATK-MS7620模块为接近检测模式 */
    ret = atk_ms7620_mode_config(ATK_MS7620_MODE_PS);
    if (ret != 0)
    {
        printf("ATK_MS7620 config failed!\r\n");
        while (1)
        {
            LED0_TOGGLE();
            delay_ms(200);
        }
    }
    
    printf("ATK-MS7620 config succedded!\r\n");
    
    while (1)
    {
        /* 获取物体亮度和大小 */
        ret  = atk_ms7620_get_obj_brightness(&brightness);
        ret += atk_ms7620_get_obj_size(&size);
        if (ret == ATK_MS7620_EOK)
        {
            printf("Object brightness: %d, size: %d\r\n", brightness, size);
        }
    }
}

1.1 初始化ATK-MS7620模块

/**
 * @brief       ATK-MS7620模块初始化
 * @param       无
 * @retval      ATK_MS7620_EOK  : ATK-MS7620模块初始化成功
 *              ATK_MS7620_ERROR: ATK-MS7620模块初始化失败
 */
uint8_t atk_ms7620_init(void)
{
    uint8_t ret;
    
    delay_ms(1);                            /* 等待至少700us */
    atk_ms7620_iic_init();                  /* 初始化IIC接口 */
    ret = atk_ms7620_get_wakeup_status();   /* 获取唤醒状态 */
    if (ret != ATK_MS7620_EOK)
    {
        return ATK_MS7620_ERROR;
    }
    atk_ms7620_initial_register();          /* 初始化寄存器配置 */
    
    return ATK_MS7620_EOK;
}

1.2 配置ATK-MS7620模块为接近检测模式

/**
 * @brief       配置ATK-MS7620模块的模式
 * @param       mode: ATK_MS7620_MODE_PS     : 接近检测模式
 *                    ATK_MS7620_MODE_GESTURE: 手势检测模式
 * @retval      ATK_MS7620_EOK   : 模式配置成功
 *              ATK_MS7620_EINVAL: 函数参数有误
 */
uint8_t atk_ms7620_mode_config(atk_ms7620_mode_t mode)
{
    uint8_t (*array)[2];
    uint8_t array_size;
    uint8_t array_index;
    
    switch (mode)
    {
        case ATK_MS7620_MODE_PS:
        {
            array = change_to_proximity_register_array;
            array_size = sizeof(change_to_proximity_register_array) / sizeof(change_to_proximity_register_array[0]);
            break;
        }
        case ATK_MS7620_MODE_GESTURE:
        {
            array = change_to_gesture_register_array;
            array_size = sizeof(change_to_gesture_register_array) / sizeof(change_to_gesture_register_array[0]);
            break;
        }
        default:
        {
            return ATK_MS7620_EINVAL;
        }
    }
    
    for (array_index=0; array_index<array_size; array_index++)
    {
        atk_ms7620_write_byte(ATK_MS7620_IIC_ADDR, array[array_index][0], array[array_index][1]);
    }
    
    return ATK_MS7620_EOK;
}

1.3 获取物体亮度和大小

/**
 * @brief       ATK-MS7620模块获取物体亮度
 * @param       brightness: 物体亮度,范围0~255
 * @retval      ATK_MS7620_EOK   : 获取物体亮度成功
 *              ATK_MS7620_ERROR : 获取物体亮度失败
 *              ATK_MS7620_EINVAL: 函数参数有误
 */
uint8_t atk_ms7620_get_obj_brightness(uint8_t *brightness)
{
    uint8_t ret;
    uint8_t _brightness[1];
    
    if (brightness == NULL)
    {
        return ATK_MS7620_EINVAL;
    }
    
    atk_ms7620_switch_reg_bank(ATK_MS7620_BANK0);
    ret = atk_ms7620_read_byte(ATK_MS7620_IIC_ADDR, ATK_MS7620_REG_OBJ_BRIGHTNESS, _brightness);
    if (ret != ATK_MS7620_EOK)
    {
        return ATK_MS7620_ERROR;
    }
    
    *brightness = _brightness[0];
    
    return ATK_MS7620_EOK;
}

/**
 * @brief       ATK-MS7620模块获取物体大小
 * @param       size: 物体大小,范围0~900
 * @retval      ATK_MS7620_EOK   : 获取物体大小成功
 *              ATK_MS7620_ERROR : 获取物体大小失败
 *              ATK_MS7620_EINVAL: 函数参数有误
 */
uint8_t atk_ms7620_get_obj_size(uint16_t *size)
{
    uint8_t ret;
    uint8_t _size[2];
    
    if (size == NULL)
    {
        return ATK_MS7620_EINVAL;
    }
    
    atk_ms7620_switch_reg_bank(ATK_MS7620_BANK0);
    ret  = atk_ms7620_read_byte(ATK_MS7620_IIC_ADDR, ATK_MS7620_REG_OBJ_SIZE_1, &_size[0]);
    ret += atk_ms7620_read_byte(ATK_MS7620_IIC_ADDR, ATK_MS7620_REG_OBJ_SIZE_2, &_size[1]);
    
    if (ret != ATK_MS7620_EOK)
    {
        return ATK_MS7620_ERROR;
    }
    
    *size = (((uint16_t)_size[1] << 8) & 0x0F00) | _size[0];
    
    return ATK_MS7620_EOK;
}


三、总结

今天主要讲了手势识别模块PAJ7620的简单应用:手势识别和接近检测。

PAJ7620U2手势传感器相比于传统机械按键等方式,具有更便捷、舒适的使用体验,并且能够减少因操作过度而损坏设备的风险。不过需要注意的是,其识别和跟踪手势的功能可能存在一定局限性,同时也需要针对不同场景进行相关设置和调试,以达到最佳效果。

感谢你的观看!

在这里插入图片描述

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐