Ejemplo n.º 1
0
        static void Main(string[] args)
        {
            uint hHD = HDAPI.hdInitDevice(null);

            HDAPI.hdEnable(HDEDParameters.HD_FORCE_OUTPUT);
            HDAPI.hdStartScheduler();

            HDErrorInfo error = HDAPI.hdGetError();

            if (error.CheckedError())
            {
                Console.WriteLine("Start Scheduler Failed.");
                Console.ReadKey();
                return;
            }

            ulong pHandler = HDAPI.hdScheduleAsynchronous(FrictionlessSphereCallback, IntPtr.Zero, HDSchedulerPriority.HD_DEFAULT_SCHEDULER_PRIORITY);

            while (true)
            {
                if (HDAPI.hdWaitForCompletion(pHandler, HDWaitCode.HD_WAIT_CHECK_STATUS) == 0x00)
                {
                    Console.WriteLine("主回调器退出。");
                    Console.ReadKey();
                    return;
                }
            }

            HDAPI.hdStopScheduler();
            HDAPI.hdUnschedule(pHandler);
            HDAPI.hdDisableDevice(hHD);
        }
Ejemplo n.º 2
0
        static HDCallbackCode GravityWellCallback(IntPtr pUserData)
        {
            const double kStiffness            = 0.175; //(N/mm)
            const double kGravityWellInfluence = 50;    //Box Size:50x50x50(mm)

            Vector3D position      = new Vector3D();
            Vector3D force         = new Vector3D();
            Vector3D positionTwell = new Vector3D();

            uint hHD = HDAPI.hdGetCurrentDevice();

            //触觉技术框架开始。(一般来说,所有与状态相关的触觉调用都应该在一个框架内进行。)
            HDAPI.hdBeginFrame(hHD);
            //获取设备的当前位置
            HDAPI.hdGetDoublev(HDGetParameters.HD_CURRENT_POSITION, ref position);
            //Console.WriteLine("Vector3D:{0}  {1}  {2}", position.X, position.Y, position.Z);
            force.ResetZero();

            // positionTwell = wellPos - position
            //创建一个从设备位置到重力井中心的矢量
            Vector3D.Subtrace(ref positionTwell, ref wellPos, ref position);

            //如果装置位置在重力井中心一定距离内,则向重力井中心施加弹簧力。
            //力的计算不同于传统的重力体,因为装置离中心越近,井所施加的力就越小;
            //该装置的行为就像弹簧连接在它自己和井的中心。
            if (InForce && Vector3D.Magnitude(ref positionTwell) < kGravityWellInfluence)
            {
                // F = k * x
                //F:力的单位为牛顿(N)
                //k: 井的刚度(N / mm)
                //x: 从设备端点位置到井中心的向量。
                Vector3D.Scale(ref force, ref positionTwell, kStiffness);
            }

            if (!InForce && Vector3D.Magnitude(ref positionTwell) >= kGravityWellInfluence)
            {
                Vector3D.Scale(ref force, ref positionTwell, kStiffness);
            }


            //把力传送到设备上
            HDAPI.hdSetDoublev(HDSetParameters.HD_CURRENT_FORCE, ref force);
            //End haptics frame.
            HDAPI.hdEndFrame(hHD);

            //check error
            HDErrorInfo error = HDAPI.hdGetError();

            if (error.CheckedError())
            {
                Console.WriteLine("渲染重力时检测到错误");
                if (error.IsSchedulerError())
                {
                    Console.WriteLine("调度器错误。");
                    return(HDCallbackCode.HD_CALLBACK_DONE);
                }
            }

            return(HDCallbackCode.HD_CALLBACK_CONTINUE);
        }
Ejemplo n.º 3
0
        static void Main(string[] args)
        {
            uint hHD = HDAPI.hdInitDevice(null);

            Console.WriteLine(HLAPI.hlGetString(HLGetStringParameters.HL_VENDOR));

            HDAPI.hdMakeCurrentDevice(hHD);

            IntPtr hHLRC = HLAPI.hlCreateContext(hHD);

            HLAPI.hlMakeCurrent(hHLRC);
            //禁用GL
            HLAPI.hlDisable(HLCapabilityParameters.HL_USE_GL_MODELVIEW);

            uint spring = HLAPI.hlGenEffects(1);

            Console.WriteLine("spring:{0}", spring);
            //添加回调处理按扭按下
            HLAPI.hlAddEventCallback(HLCallbackEvents.HL_EVENT_1BUTTONDOWN, HLAPI.HL_OBJECT_ANY, HLCallbackThreads.HL_CLIENT_THREAD, ButtonCB, new IntPtr(spring));
            HLAPI.hlAddEventCallback(HLCallbackEvents.HL_EVENT_1BUTTONUP, HLAPI.HL_OBJECT_ANY, HLCallbackThreads.HL_CLIENT_THREAD, ButtonCB, new IntPtr(spring));
            HLAPI.hlAddEventCallback(HLCallbackEvents.HL_EVENT_2BUTTONDOWN, HLAPI.HL_OBJECT_ANY, HLCallbackThreads.HL_CLIENT_THREAD, ButtonCB, new IntPtr(0));

            uint friction = HLAPI.hlGenEffects(1);

            HLAPI.hlBeginFrame();
            HLAPI.hlEffectd(HLEffectParams.HL_EFFECT_PROPERTY_GAIN, 0.2);
            HLAPI.hlEffectd(HLEffectParams.HL_EFFECT_PROPERTY_MAGNITUDE, 0.5);
            HLAPI.hlStartEffect(HLStartEffectTypes.HL_EFFECT_FRICTION, friction);
            HLAPI.hlEndFrame();

            HLError error;

            while (true)
            {
                HLAPI.hlBeginFrame();
                //轮询事件。请注意,客户端线程事件回调是从这里的一个框架内分派的,因此我们可以安全地直接启动/停止事件回调的效果
                HLAPI.hlCheckEvents();
                HLAPI.hlEndFrame();

                error = HLAPI.hlGetError();
                if (error.CheckedError())
                {
                    Console.WriteLine("HL Error:{0}", error.GetErrorCodeString());
                }
            }

            //Stop the friction effect.
            HLAPI.hlBeginFrame();
            HLAPI.hlStopEffect(friction);
            HLAPI.hlEndFrame();

            HLAPI.hlDeleteEffects(friction, 1);
            HLAPI.hlDeleteEffects(spring, 1);

            HLAPI.hlDeleteContext(hHLRC);
            HDAPI.hdDisableDevice(hHD);

            Console.ReadKey();
        }
Ejemplo n.º 4
0
        static HDCallbackCode GetSyncPos(IntPtr pUserData)
        {
            Vector3D v3 = HDDLLUtils.IntPtrToStruct <Vector3D>(pUserData);

            HDAPI.hdBeginFrame(v3.HHD);
            //将获取的坐标位置放入结构数据前三个double字节中
            HDAPI.hdGetDoublev(HDGetParameters.HD_CURRENT_POSITION, pUserData);
            HDAPI.hdEndFrame(v3.HHD);

            return(HDCallbackCode.HD_CALLBACK_DONE);
        }
Ejemplo n.º 5
0
        static void Main(string[] args)
        {
            uint hHD = HDAPI.hdInitDevice("Default Device");

            error = HDAPI.hdGetError();
            if (error.CheckedError())
            {
                Console.WriteLine("Device Initialize Failed..");
                Console.ReadKey();
                return;
            }

            //HDSchedulerCallback pCallback = GravityWellCallback;
            ulong gravityWell = HDAPI.hdScheduleAsynchronous(GravityWellCallback, IntPtr.Zero, HDSchedulerPriority.HD_MAX_SCHEDULER_PRIORITY);

            HDAPI.hdEnable(HDEDParameters.HD_FORCE_OUTPUT);
            HDAPI.hdStartScheduler();

            error = HDAPI.hdGetError();
            if (error.CheckedError())
            {
                Console.WriteLine("Start Scheduler Failed..");
                Console.ReadKey();
                return;
            }

            while (true)
            {
                ConsoleKeyInfo key = Console.ReadKey();
                if (key.Key == ConsoleKey.DownArrow)
                {
                    InForce = true;
                    Console.WriteLine("In Force:{0}", true);
                }
                else if (key.Key == ConsoleKey.UpArrow)
                {
                    InForce = false;
                    Console.WriteLine("Out Force:{0}", false);
                }

                if (HDAPI.hdWaitForCompletion(gravityWell, HDWaitCode.HD_WAIT_CHECK_STATUS) == 0x00)
                {
                    Console.WriteLine("Ready quit..");
                    Console.ReadKey();
                    break;
                }
            }

            HDAPI.hdStopScheduler();
            HDAPI.hdUnschedule(gravityWell);
            HDAPI.hdDisableDevice(hHD);
        }
Ejemplo n.º 6
0
        static HDCallbackCode AnchoredSpringForceHandler(IntPtr pUserData)
        {
            uint hHD = (uint)pUserData;

            double[] force = new double[3] {
                0.0, 0.0, 0.0
            };

            HDAPI.hdBeginFrame(hHD);

            double[] position = new double[3];
            HDAPI.hdGetDoublev(HDGetParameters.HD_CURRENT_POSITION, position);

            int currButtons = 0;
            int lastButtons = 0;

            HDAPI.hdGetIntegerv(HDGetParameters.HD_LAST_BUTTONS, ref lastButtons);
            HDAPI.hdGetIntegerv(HDGetParameters.HD_CURRENT_BUTTONS, ref currButtons);

            //按下 Button 1
            if ((currButtons & (int)HDButtonMasks.HD_DEVICE_BUTTON_1) != 0 &&
                (lastButtons & (int)HDButtonMasks.HD_DEVICE_BUTTON_1) == 0)
            {
                anchor      = position;
                renderForce = true;

                Console.WriteLine("gSpringStiffness:{0}", gSpringStiffness);
                //Console.WriteLine("Button Down:{0}  {1}  {2}", position[0], position[1], position[2]);
            }
            else if ((currButtons & (int)HDButtonMasks.HD_DEVICE_BUTTON_1) == 0 &&
                     (lastButtons & (int)HDButtonMasks.HD_DEVICE_BUTTON_1) != 0)
            {
                renderForce = false;
                //向设备发送零力,否则它将继续呈现最后发送的力
                HDAPI.hdSetDoublev(HDSetParameters.HD_CURRENT_FORCE, force);
            }

            if (renderForce)
            {
                //计算弹簧力为 F = k * (anchor - position),这将吸引设备位置朝向锚点位置
                Vector3D.Subtrace(ref force, anchor, position);
                Vector3D.ScaleInPlace(ref force, gSpringStiffness);

                HDAPI.hdSetDoublev(HDSetParameters.HD_CURRENT_FORCE, force);
            }

            HDAPI.hdEndFrame(hHD);

            return(HDCallbackCode.HD_CALLBACK_CONTINUE);
        }
Ejemplo n.º 7
0
        static HDCallbackCode FrictionlessSphereCallback(IntPtr pUserData)
        {
            uint hHD = HDAPI.hdGetCurrentDevice();

            HDAPI.hdBeginFrame(hHD);

            //获取坐标位置
            Vector3D position = new Vector3D();

            HDAPI.hdGetDoublev(HDGetParameters.HD_CURRENT_POSITION, ref position);
            //Console.WriteLine("{0}  {1}  {2}", position.X, position.Y, position.Z);

            //计算设备和球体中心之间的距离。
            Vector3D res      = position - spherePosition;
            double   distance = Vector3D.Magnitude(ref res);

            //如果用户在球体内,即用户到球体中心的距离小于球体半径,
            //则用户正在穿透球体,应命令一个力将用户推向表面。
            if (distance < radius)
            {
                //计算穿透距离。
                double penetrationDistance = radius - distance;

                //在力的方向上创建一个单位矢量,它总是从球体的中心通过用户的位置向外。
                Vector3D forceDirection = (position - spherePosition) / distance;

                //使用 F = k * x 创建一个远离中心的力向量
                //球体与穿透距离成正比,并受物体刚度的制约。
                double   k = stiffness;
                Vector3D x = penetrationDistance * forceDirection;
                Vector3D f = k * x;

                HDAPI.hdSetDoublev(HDSetParameters.HD_CURRENT_FORCE, ref f);
            }

            HDAPI.hdEndFrame(hHD);
            HDErrorInfo error = HDAPI.hdGetError();

            if (error.CheckedError())
            {
                Console.WriteLine("主调度程序回调期间出错.");
                if (error.IsSchedulerError())
                {
                    return(HDCallbackCode.HD_CALLBACK_DONE);
                }
            }

            return(HDCallbackCode.HD_CALLBACK_CONTINUE);
        }
Ejemplo n.º 8
0
        static void Main(string[] args)
        {
            uint        hHD   = HDAPI.hdInitDevice(null);
            HDErrorInfo error = HDAPI.hdGetError();

            if (error.CheckedError())
            {
                Console.WriteLine("Initialize Device Failed.");
                Console.ReadKey();
                return;
            }

            HDAPI.hdMakeCurrentDevice(hHD);
            IntPtr hHLRC = HLAPI.hlCreateContext(hHD);

            HLAPI.hlMakeCurrent(hHLRC);

            HLAPI.hlDisable(HLCapabilityParameters.HL_USE_GL_MODELVIEW);
            uint   spring = HLAPI.hlGenEffects(1);
            IntPtr ptr    = new IntPtr(spring);

            HLAPI.hlAddEventCallback(HLCallbackEvents.HL_EVENT_1BUTTONDOWN, HLAPI.HL_OBJECT_ANY, HLCallbackThreads.HL_CLIENT_THREAD, ButtonCB, ptr);
            HLAPI.hlAddEventCallback(HLCallbackEvents.HL_EVENT_1BUTTONUP, HLAPI.HL_OBJECT_ANY, HLCallbackThreads.HL_CLIENT_THREAD, ButtonCB, ptr);

            while (true)
            {
                HLAPI.hlBeginFrame();
                //轮询事件。请注意,客户端线程事件回调是从这里的一个框架内分派的,因此我们可以安全地直接启动/停止事件回调的效果。
                HLAPI.hlCheckEvents();
                HLAPI.hlEndFrame();
            }

            HLAPI.hlDeleteEffects(spring, 1);
            HLAPI.hlDeleteContext(hHLRC);
            HDAPI.hdDisableDevice(hHD);
        }
Ejemplo n.º 9
0
        static void Main(string[] args)
        {
            uint hHD = HDAPI.hdInitDevice(HDAPI.HD_DEFAULT_DEVICE);

            error = HDAPI.hdGetError();
            if (error.CheckedError())
            {
                Console.WriteLine("Device Initialize Failed..");
                return;
            }

            //更新校准
            //HDAPI.hdUpdateCalibration(HDCalibrationStyles.HD_CALIBRATION_INKWELL);

            HDSchedulerCallback pCallback = AnchoredSpringForceHandler;

            IntPtr deviceHHD = new IntPtr(hHD);
            ulong  pHandler  = HDAPI.hdScheduleAsynchronous(pCallback, deviceHHD, HDSchedulerPriority.HD_MAX_SCHEDULER_PRIORITY);

            //启用力输出功能
            HDAPI.hdEnable(HDEDParameters.HD_FORCE_OUTPUT);
            double maxStiffness = 0;

            //查询设备能够处理的最大闭环控制刚度。使用超过这个限制的值可能会导致设备嗡嗡作响。
            HDAPI.hdGetDoublev(HDGetParameters.HD_NOMINAL_MAX_STIFFNESS, ref maxStiffness);

            HDAPI.hdStartScheduler();
            error = HDAPI.hdGetError();
            if (error.CheckedError())
            {
                Console.WriteLine("启动调度程序失败.");
                Console.ReadKey();
                return;
            }

            Console.WriteLine("按下 Button 1 开始,按上下键设置 force 值");
            while (true)
            {
                ConsoleKeyInfo key = Console.ReadKey(true);
                if (key.Key == ConsoleKey.DownArrow)
                {
                    gSpringStiffness -= 0.05;
                    if (gSpringStiffness <= 0)
                    {
                        gSpringStiffness = 0.00;
                    }

                    Console.WriteLine("gSpringStiffness:{0}", gSpringStiffness);
                }
                else if (key.Key == ConsoleKey.UpArrow)
                {
                    gSpringStiffness += 0.05;
                    if (gSpringStiffness >= maxStiffness)
                    {
                        gSpringStiffness = maxStiffness;
                    }

                    Console.WriteLine("gSpringStiffness:{0}", gSpringStiffness);
                }
            }

            HDAPI.hdStopScheduler();
            HDAPI.hdUnschedule(pHandler);
            HDAPI.hdDisableDevice(hHD);
        }
Ejemplo n.º 10
0
        static void Main(string[] args)
        {
            hHD   = HDAPI.hdInitDevice(null);
            error = HDAPI.hdGetError();

            if (error.CheckedError())
            {
                Console.WriteLine("Init Error.");
                Console.ReadKey();
                return;
            }

            //获取支持的校准样式,因为一些设备可能支持多种类型的校准
            HDAPI.hdGetIntegerv(HDGetParameters.HD_CALIBRATION_STYLE, ref supportedCalibrationStyles);
            Console.WriteLine("supportedCalibrationStyles:{0} {1}", supportedCalibrationStyles,
                              Enum.GetName(typeof(HDCalibrationStyles), supportedCalibrationStyles));

            //使用墨水池校准
            HDAPI.hdUpdateCalibration(HDCalibrationStyles.HD_CALIBRATION_INKWELL);
            //启动 Servo Loop
            HDAPI.hdStartScheduler();

#if 直接获取坐标位置输出
            double[] pPosition = new double[3];
            int      buttons   = 0;
            while (true)
            {
                if (HDAPI.hdCheckCalibration() == HDCalibrationCodes.HD_CALIBRATION_NEEDS_UPDATE)
                {
                    HDAPI.hdUpdateCalibration(HDCalibrationStyles.HD_CALIBRATION_INKWELL);
                }

                HDAPI.hdBeginFrame(hHD);
                HDAPI.hdGetDoublev(HDGetParameters.HD_CURRENT_POSITION, pPosition);
                HDAPI.hdGetIntegerv(HDGetParameters.HD_CURRENT_BUTTONS, ref buttons);
                HDAPI.hdEndFrame(hHD);

                Console.WriteLine("Button Status:Btn1:{0}  Btn2:{1}  Btn3:{2}  Btn4:{3}",
                                  buttons & (int)HDButtonMasks.HD_DEVICE_BUTTON_1,
                                  buttons & (int)HDButtonMasks.HD_DEVICE_BUTTON_2,
                                  buttons & (int)HDButtonMasks.HD_DEVICE_BUTTON_3,
                                  buttons & (int)HDButtonMasks.HD_DEVICE_BUTTON_4);
                Console.WriteLine("Position: X:{0}  Y:{1}   Z:{2}", pPosition[0], pPosition[1], pPosition[2]);

                Thread.Sleep(100);
            }
#endif

#if 使用调度器同步输出位置
            PositionSynchronous = GetSyncPos;
            Vector3D v3 = new Vector3D();
            v3.HHD = hHD;

            IntPtr pPosition = OHUtils.StructToIntPtr(v3);
            while (true)
            {
                HDAPI.hdScheduleSynchronous(PositionSynchronous, pPosition, HDSchedulerPriority.HD_DEFAULT_SCHEDULER_PRIORITY);
                v3 = OHUtils.IntPtrToStruct <Vector3D>(pPosition);
                Console.WriteLine("Position: X:{0}  Y:{1}   Z:{2}", v3.X, v3.Y, v3.Z);

                //Sleep一下,不然打印的数据太多,看不清,实际项目是不需要的
                //Thread.Sleep(100);
            }
#endif
            //停止 Servo Loop
            HDAPI.hdStopScheduler();
            //禁用设备
            HDAPI.hdDisableDevice(hHD);
            Console.ReadKey();
            return;
        }