1、官网下载SDK
SDK API 值得说明的是,IR170这块开发板提供的API是基于C语言的,与LeapMotion提供的基于C++的API不同,但配置过程基本相同。
2、配置环境
添加附加依赖项
项目-属性-连接器-输入-附加依赖项添加LeapC.lib
添加包含目录和库目录
包含目录: D:\CODING\LeapCEnv\LeapCEnv\LeapSDK\include 库目录:D:\CODING\LeapCEnv\LeapCEnv\LeapSDK\lib\x64 官方提供的SDK里,LeapSDK\lib下包含x64和x86,需要在库目录里写明选用哪种架构,不然会报找不到lib的错误。
环境变量
完成以上两步,官网提供的sample就已经能跑了,但是有的教程里还是说明了要配置系统环境变量,所以在这里记录一下,如果以上两步之后还是有问题可以再试试这一步。 (1)把lib\x64文件夹下的LeapC.dll添加进环境变量,路径为:\LeapSDK\lib\x64 添加环境变量的作用是让你编译生成的EXE程序能访问到对应目录里的dll,如果不想添加进环境变量可以把dll拷贝进调试目录,直接把那些dll拷贝到EXE的目录就可以直接访问而不用添加环境变量。 (2)把lib\x64文件夹下的LeapC.dll拷贝进调试目录,路径为 \Code\Debug 和 \Code\Code\Debug 我不知道拷贝到哪一个Debug目录生效,可以自行排查一下。
3、测试
在工程中添加以下三段代码:
CallbackSample.c
#undef __cplusplus
#include <stdio.h>
#include <stdlib.h>
#include "LeapC.h"
#include "ExampleConnection.h"
static LEAP_CONNECTION* connectionHandle;
static void OnConnect() {
printf("Connected.\n");
}
static void OnDevice(const LEAP_DEVICE_INFO *props) {
printf("Found device %s.\n", props->serial);
}
static void OnFrame(const LEAP_TRACKING_EVENT *frame) {
printf("Frame %lli with %i hands.\n", (long long int)frame->info.frame_id, frame->nHands);
for (uint32_t h = 0; h < frame->nHands; h++) {
LEAP_HAND* hand = &frame->pHands[h];
printf(" Hand id %i is a %s hand with position (%f, %f, %f).\n",
hand->id,
(hand->type == eLeapHandType_Left ? "left" : "right"),
hand->palm.position.x,
hand->palm.position.y,
hand->palm.position.z);
}
}
static void OnImage(const LEAP_IMAGE_EVENT *image) {
printf("Image %lli => Left: %d x %d (bpp=%d), Right: %d x %d (bpp=%d)\n",
(long long int)image->info.frame_id,
image->image[0].properties.width, image->image[0].properties.height, image->image[0].properties.bpp * 8,
image->image[1].properties.width, image->image[1].properties.height, image->image[1].properties.bpp * 8);
}
static void OnLogMessage(const eLeapLogSeverity severity, const int64_t timestamp,
const char* message) {
const char* severity_str;
switch (severity) {
case eLeapLogSeverity_Critical:
severity_str = "Critical";
break;
case eLeapLogSeverity_Warning:
severity_str = "Warning";
break;
case eLeapLogSeverity_Information:
severity_str = "Info";
break;
default:
severity_str = "";
break;
}
printf("[%s][%lli] %s\n", severity_str, (long long int)timestamp, message);
}
static void* allocate(uint32_t size, eLeapAllocatorType typeHint, void* state) {
void* ptr = malloc(size);
return ptr;
}
static void deallocate(void* ptr, void* state) {
if (!ptr)
return;
free(ptr);
}
void OnPointMappingChange(const LEAP_POINT_MAPPING_CHANGE_EVENT *change) {
if (!connectionHandle)
return;
uint64_t size = 0;
if (LeapGetPointMappingSize(*connectionHandle, &size) != eLeapRS_Success || !size)
return;
LEAP_POINT_MAPPING* pointMapping = (LEAP_POINT_MAPPING*)malloc(size);
if (!pointMapping)
return;
if (LeapGetPointMapping(*connectionHandle, pointMapping, &size) == eLeapRS_Success &&
pointMapping->nPoints > 0) {
printf("Managing %u points as of frame %lld at %lld\n", pointMapping->nPoints, (long long int)pointMapping->frame_id, (long long int)pointMapping->timestamp);
}
free(pointMapping);
}
void OnHeadPose(const LEAP_HEAD_POSE_EVENT *event) {
printf("Head pose:\n");
printf(" Head position (%f, %f, %f).\n",
event->head_position.x,
event->head_position.y,
event->head_position.z);
printf(" Head orientation (%f, %f, %f, %f).\n",
event->head_orientation.w,
event->head_orientation.x,
event->head_orientation.y,
event->head_orientation.z);
}
int main(int argc, char** argv) {
ConnectionCallbacks.on_connection = &OnConnect;
ConnectionCallbacks.on_device_found = &OnDevice;
ConnectionCallbacks.on_frame = &OnFrame;
ConnectionCallbacks.on_image = &OnImage;
ConnectionCallbacks.on_point_mapping_change = &OnPointMappingChange;
ConnectionCallbacks.on_log_message = &OnLogMessage;
ConnectionCallbacks.on_head_pose = &OnHeadPose;
connectionHandle = OpenConnection();
{
LEAP_ALLOCATOR allocator = { allocate, deallocate, NULL };
LeapSetAllocator(*connectionHandle, &allocator);
}
LeapSetPolicyFlags(*connectionHandle, eLeapPolicyFlag_Images | eLeapPolicyFlag_MapPoints, 0);
printf("Press Enter to exit program.\n");
getchar();
DestroyConnection();
return 0;
}
ExampleConnection.h
#ifndef ExampleConnection_h
#define ExampleConnection_h
#include "LeapC.h"
LEAP_CONNECTION* OpenConnection();
void CloseConnection();
void DestroyConnection();
LEAP_TRACKING_EVENT* GetFrame();
LEAP_DEVICE_INFO* GetDeviceProperties();
const char* ResultString(eLeapRS r);
extern bool IsConnected;
typedef void(*connection_callback) ();
typedef void(*device_callback) (const LEAP_DEVICE_INFO *device);
typedef void(*device_lost_callback) ();
typedef void(*device_failure_callback) (const eLeapDeviceStatus failure_code,
const LEAP_DEVICE failed_device);
typedef void(*policy_callback) (const uint32_t current_policies);
typedef void(*tracking_callback) (const LEAP_TRACKING_EVENT *tracking_event);
typedef void(*log_callback) (const eLeapLogSeverity severity,
const int64_t timestamp,
const char* message);
typedef void(*config_change_callback) (const uint32_t requestID, const bool success);
typedef void(*config_response_callback)(const uint32_t requestID, LEAP_VARIANT value);
typedef void(*image_callback) (const LEAP_IMAGE_EVENT *image_event);
typedef void(*point_mapping_change_callback)(const LEAP_POINT_MAPPING_CHANGE_EVENT *point_mapping_change_event);
typedef void(*head_pose_callback)(const LEAP_HEAD_POSE_EVENT *head_pose_event);
struct Callbacks {
connection_callback on_connection;
connection_callback on_connection_lost;
device_callback on_device_found;
device_lost_callback on_device_lost;
device_failure_callback on_device_failure;
policy_callback on_policy;
tracking_callback on_frame;
log_callback on_log_message;
config_change_callback on_config_change;
config_response_callback on_config_response;
image_callback on_image;
point_mapping_change_callback on_point_mapping_change;
head_pose_callback on_head_pose;
};
extern struct Callbacks ConnectionCallbacks;
extern void millisleep(int milliseconds);
#endif
ExampleConnection.c
#include "ExampleConnection.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#if defined(_MSC_VER)
#include <Windows.h>
#include <process.h>
#define LockMutex EnterCriticalSection
#define UnlockMutex LeaveCriticalSection
#else
#include <unistd.h>
#include <pthread.h>
#define LockMutex pthread_mutex_lock
#define UnlockMutex pthread_mutex_unlock
#endif
#if defined(_MSC_VER)
static void serviceMessageLoop(void * unused);
#else
static void* serviceMessageLoop(void * unused);
#endif
static void setFrame(const LEAP_TRACKING_EVENT *frame);
static void setDevice(const LEAP_DEVICE_INFO *deviceProps);
bool IsConnected = false;
static volatile bool _isRunning = false;
static LEAP_CONNECTION connectionHandle = NULL;
static LEAP_TRACKING_EVENT *lastFrame = NULL;
static LEAP_DEVICE_INFO *lastDevice = NULL;
struct Callbacks ConnectionCallbacks;
#if defined(_MSC_VER)
static HANDLE pollingThread;
static CRITICAL_SECTION dataLock;
#else
static pthread_t pollingThread;
static pthread_mutex_t dataLock;
#endif
LEAP_CONNECTION* OpenConnection(){
if(_isRunning){
return &connectionHandle;
}
if(connectionHandle || LeapCreateConnection(NULL, &connectionHandle) == eLeapRS_Success){
eLeapRS result = LeapOpenConnection(connectionHandle);
if(result == eLeapRS_Success){
_isRunning = true;
#if defined(_MSC_VER)
InitializeCriticalSection(&dataLock);
pollingThread = (HANDLE)_beginthread(serviceMessageLoop, 0, NULL);
#else
pthread_create(&pollingThread, NULL, serviceMessageLoop, NULL);
#endif
}
}
return &connectionHandle;
}
void CloseConnection(){
if(!_isRunning){
return;
}
_isRunning = false;
LeapCloseConnection(connectionHandle);
#if defined(_MSC_VER)
WaitForSingleObject(pollingThread, INFINITE);
CloseHandle(pollingThread);
#else
pthread_join(pollingThread, NULL);
#endif
}
void DestroyConnection(){
CloseConnection();
LeapDestroyConnection(connectionHandle);
}
void CloseConnectionHandle(LEAP_CONNECTION* connectionHandle){
LeapDestroyConnection(*connectionHandle);
_isRunning = false;
}
static void handleConnectionEvent(const LEAP_CONNECTION_EVENT *connection_event){
IsConnected = true;
if(ConnectionCallbacks.on_connection){
ConnectionCallbacks.on_connection();
}
}
static void handleConnectionLostEvent(const LEAP_CONNECTION_LOST_EVENT *connection_lost_event){
IsConnected = false;
if(ConnectionCallbacks.on_connection_lost){
ConnectionCallbacks.on_connection_lost();
}
}
static void handleDeviceEvent(const LEAP_DEVICE_EVENT *device_event){
LEAP_DEVICE deviceHandle;
eLeapRS result = LeapOpenDevice(device_event->device, &deviceHandle);
if(result != eLeapRS_Success){
printf("Could not open device %s.\n", ResultString(result));
return;
}
LEAP_DEVICE_INFO deviceProperties = { sizeof(deviceProperties) };
deviceProperties.serial_length = 1;
deviceProperties.serial = malloc(deviceProperties.serial_length);
result = LeapGetDeviceInfo(deviceHandle, &deviceProperties);
if(result == eLeapRS_InsufficientBuffer){
deviceProperties.serial = realloc(deviceProperties.serial, deviceProperties.serial_length);
result = LeapGetDeviceInfo(deviceHandle, &deviceProperties);
if(result != eLeapRS_Success){
printf("Failed to get device info %s.\n", ResultString(result));
free(deviceProperties.serial);
return;
}
}
setDevice(&deviceProperties);
if(ConnectionCallbacks.on_device_found){
ConnectionCallbacks.on_device_found(&deviceProperties);
}
free(deviceProperties.serial);
LeapCloseDevice(deviceHandle);
}
static void handleDeviceLostEvent(const LEAP_DEVICE_EVENT *device_event){
if(ConnectionCallbacks.on_device_lost){
ConnectionCallbacks.on_device_lost();
}
}
static void handleDeviceFailureEvent(const LEAP_DEVICE_FAILURE_EVENT *device_failure_event){
if(ConnectionCallbacks.on_device_failure){
ConnectionCallbacks.on_device_failure(device_failure_event->status, device_failure_event->hDevice);
}
}
static void handleTrackingEvent(const LEAP_TRACKING_EVENT *tracking_event){
setFrame(tracking_event);
if(ConnectionCallbacks.on_frame){
ConnectionCallbacks.on_frame(tracking_event);
}
}
static void handleLogEvent(const LEAP_LOG_EVENT *log_event){
if(ConnectionCallbacks.on_log_message){
ConnectionCallbacks.on_log_message(log_event->severity, log_event->timestamp, log_event->message);
}
}
static void handleLogEvents(const LEAP_LOG_EVENTS *log_events){
if(ConnectionCallbacks.on_log_message){
for (int i = 0; i < (int)(log_events->nEvents); i++) {
const LEAP_LOG_EVENT* log_event = &log_events->events[i];
ConnectionCallbacks.on_log_message(log_event->severity, log_event->timestamp, log_event->message);
}
}
}
static void handlePolicyEvent(const LEAP_POLICY_EVENT *policy_event){
if(ConnectionCallbacks.on_policy){
ConnectionCallbacks.on_policy(policy_event->current_policy);
}
}
static void handleConfigChangeEvent(const LEAP_CONFIG_CHANGE_EVENT *config_change_event){
if(ConnectionCallbacks.on_config_change){
ConnectionCallbacks.on_config_change(config_change_event->requestID, config_change_event->status);
}
}
static void handleConfigResponseEvent(const LEAP_CONFIG_RESPONSE_EVENT *config_response_event){
if(ConnectionCallbacks.on_config_response){
ConnectionCallbacks.on_config_response(config_response_event->requestID, config_response_event->value);
}
}
static void handleImageEvent(const LEAP_IMAGE_EVENT *image_event) {
if(ConnectionCallbacks.on_image){
ConnectionCallbacks.on_image(image_event);
}
}
static void handlePointMappingChangeEvent(const LEAP_POINT_MAPPING_CHANGE_EVENT *point_mapping_change_event) {
if(ConnectionCallbacks.on_point_mapping_change){
ConnectionCallbacks.on_point_mapping_change(point_mapping_change_event);
}
}
static void handleHeadPoseEvent(const LEAP_HEAD_POSE_EVENT *head_pose_event) {
if(ConnectionCallbacks.on_head_pose){
ConnectionCallbacks.on_head_pose(head_pose_event);
}
}
#if defined(_MSC_VER)
static void serviceMessageLoop(void * unused){
#else
static void* serviceMessageLoop(void * unused){
#endif
eLeapRS result;
LEAP_CONNECTION_MESSAGE msg;
while(_isRunning){
unsigned int timeout = 1000;
result = LeapPollConnection(connectionHandle, timeout, &msg);
if(result != eLeapRS_Success){
printf("LeapC PollConnection call was %s.\n", ResultString(result));
continue;
}
switch (msg.type){
case eLeapEventType_Connection:
handleConnectionEvent(msg.connection_event);
break;
case eLeapEventType_ConnectionLost:
handleConnectionLostEvent(msg.connection_lost_event);
break;
case eLeapEventType_Device:
handleDeviceEvent(msg.device_event);
break;
case eLeapEventType_DeviceLost:
handleDeviceLostEvent(msg.device_event);
break;
case eLeapEventType_DeviceFailure:
handleDeviceFailureEvent(msg.device_failure_event);
break;
case eLeapEventType_Tracking:
handleTrackingEvent(msg.tracking_event);
break;
case eLeapEventType_ImageComplete:
break;
case eLeapEventType_ImageRequestError:
break;
case eLeapEventType_LogEvent:
handleLogEvent(msg.log_event);
break;
case eLeapEventType_Policy:
handlePolicyEvent(msg.policy_event);
break;
case eLeapEventType_ConfigChange:
handleConfigChangeEvent(msg.config_change_event);
break;
case eLeapEventType_ConfigResponse:
handleConfigResponseEvent(msg.config_response_event);
break;
case eLeapEventType_Image:
handleImageEvent(msg.image_event);
break;
case eLeapEventType_PointMappingChange:
handlePointMappingChangeEvent(msg.point_mapping_change_event);
break;
case eLeapEventType_LogEvents:
handleLogEvents(msg.log_events);
break;
case eLeapEventType_HeadPose:
handleHeadPoseEvent(msg.head_pose_event);
break;
default:
printf("Unhandled message type %i.\n", msg.type);
}
}
#if !defined(_MSC_VER)
return NULL;
#endif
}
void setFrame(const LEAP_TRACKING_EVENT *frame){
LockMutex(&dataLock);
if(!lastFrame) lastFrame = malloc(sizeof(*frame));
*lastFrame = *frame;
UnlockMutex(&dataLock);
}
LEAP_TRACKING_EVENT* GetFrame(){
LEAP_TRACKING_EVENT *currentFrame;
LockMutex(&dataLock);
currentFrame = lastFrame;
UnlockMutex(&dataLock);
return currentFrame;
}
static void setDevice(const LEAP_DEVICE_INFO *deviceProps){
LockMutex(&dataLock);
if(lastDevice){
free(lastDevice->serial);
} else {
lastDevice = malloc(sizeof(*deviceProps));
}
*lastDevice = *deviceProps;
lastDevice->serial = malloc(deviceProps->serial_length);
memcpy(lastDevice->serial, deviceProps->serial, deviceProps->serial_length);
UnlockMutex(&dataLock);
}
LEAP_DEVICE_INFO* GetDeviceProperties(){
LEAP_DEVICE_INFO *currentDevice;
LockMutex(&dataLock);
currentDevice = lastDevice;
UnlockMutex(&dataLock);
return currentDevice;
}
const char* ResultString(eLeapRS r) {
switch(r){
case eLeapRS_Success: return "eLeapRS_Success";
case eLeapRS_UnknownError: return "eLeapRS_UnknownError";
case eLeapRS_InvalidArgument: return "eLeapRS_InvalidArgument";
case eLeapRS_InsufficientResources: return "eLeapRS_InsufficientResources";
case eLeapRS_InsufficientBuffer: return "eLeapRS_InsufficientBuffer";
case eLeapRS_Timeout: return "eLeapRS_Timeout";
case eLeapRS_NotConnected: return "eLeapRS_NotConnected";
case eLeapRS_HandshakeIncomplete: return "eLeapRS_HandshakeIncomplete";
case eLeapRS_BufferSizeOverflow: return "eLeapRS_BufferSizeOverflow";
case eLeapRS_ProtocolError: return "eLeapRS_ProtocolError";
case eLeapRS_InvalidClientID: return "eLeapRS_InvalidClientID";
case eLeapRS_UnexpectedClosed: return "eLeapRS_UnexpectedClosed";
case eLeapRS_UnknownImageFrameRequest: return "eLeapRS_UnknownImageFrameRequest";
case eLeapRS_UnknownTrackingFrameID: return "eLeapRS_UnknownTrackingFrameID";
case eLeapRS_RoutineIsNotSeer: return "eLeapRS_RoutineIsNotSeer";
case eLeapRS_TimestampTooEarly: return "eLeapRS_TimestampTooEarly";
case eLeapRS_ConcurrentPoll: return "eLeapRS_ConcurrentPoll";
case eLeapRS_NotAvailable: return "eLeapRS_NotAvailable";
case eLeapRS_NotStreaming: return "eLeapRS_NotStreaming";
case eLeapRS_CannotOpenDevice: return "eLeapRS_CannotOpenDevice";
default: return "unknown result type.";
}
}
void millisleep(int milliseconds){
#ifdef _WIN32
Sleep(milliseconds);
#else
usleep(milliseconds*1000);
#endif
}
效果如下:
|