|
本帖最后由 吹口琴的钢铁侠 于 2016-7-8 13:58 编辑
上位机
上回讲清楚了Arduino端的代码,提到了每次都是Arduino通过串口接受来自电脑端的指令,由于leap motion是实时获取手势信息,那么我们只要能够实时地计算出每个舵机的数据,然后把数据以一定的格式发送给Arduino就能实现控制了,而且在Arduino端我们使用了分割大距离为小距离来转动舵机的算法,实时的改变角度也就不会造成特别大的惯性和损伤。
Leapmotion
Leapmotion作为一个手势识别装置,我们究竟能从它身上获取到哪些信息呢?
方便起见,我在这里选择了它的python库(主要是因为当时还没开始学C++= =)。
https://developer.leapmotion.com/documentation/v2/python/devguide/Leap_Overview.html
可以看一下这个Leapmotion给出的API,总体而言,它本身会建立一个空间的直角坐标系,通过它发出的不可见光并接受反射(大概是这样,具体原理我也不清楚),我们就能得到从手臂的肘部一直到手指末端所有的位置和方向,同时它还可以识别手中的一些工具(比如笔),一些手势(包括画圈,点击,扫过)。
通过这些细致的数据,其实我们已经可以通过数学方法来完全并准确地描述使用者的手臂信息了,但是呢...在下数学欠佳,算法不勤,只能拙略的写出下面的算法,而且在上一篇中也提到过,我的这一个机械臂只是五自由度的,永远无法完整的把手臂给复制出来,在三个姿态量和三个位置量中只能取五个量。(python推荐使用pyCharm IDE)
[mw_shl_code=python,true]import Leap
import serial
import sys
def range_limit(data, minl, maxl):
if data < minl:
return minl
elif data > maxl:
return maxl
else:
return data
def map_transfer(data, fmin, fmax, tmin, tmax):
return (data - fmin) / (fmax - fmin) * (tmax - tmin) + tmin
def avg(data):
sum = 0
for i in range(0,4):
sum += data
return sum/4
class SampleListener(Leap.Listener):
data_1 = [1,2,3,4]
data_2 = [1,2,3,4]
data_3 = [1,2,3,4]
data_4 = [1,2,3,4]
data_5 = [1,2,3,4]
data_6 = [1,2,3,4]
def __init__(self):
super(SampleListener, self).__init__()
self.ser = serial.Serial('COM12', 9600)
print "Serial begin"
def on_init(self, controller):
print "Initialized"
def on_connect(self, controller):
print "Connected"
def on_disconnect(self, controller):
print "Disconnected"
def on_exit(self, controller):
print "Exited"
def on_frame(self, controller):
frame = controller.frame()
for hand in frame.hands:
palmangle = hand.palm_normal.roll * Leap.RAD_TO_DEG
del self.data_1[0]
self.data_1.append(palmangle)
palmangle = avg(self.data_1)
palmangle = range_limit(palmangle, -50, 50)
clawdata = map_transfer(palmangle, -50, 50, 2200, 800)
hand_angle = 90 - hand.direction.pitch * Leap.RAD_TO_DEG
del self.data_2[0]
self.data_2.append(hand_angle)
hand_angle = avg(self.data_2)
hand_angle = range_limit(hand_angle, 40, 140)
hand_angle_data = map_transfer(hand_angle, 40, 140, 900, 1400)
arm_height = hand.arm.elbow_position.y
arm_height = range_limit(arm_height, 50, 250)
del self.data_3[0]
self.data_3.append(arm_height)
arm_height = avg(self.data_3)
servo_5 = map_transfer(arm_height, 50, 250, 2000, 1400)
del self.data_4[0]
self.data_4.append(servo_5)
servo_5 = avg(self.data_4)
servo_4 = map_transfer(servo_5, 1400, 2200, 800, 1500)
arm_data = hand.arm.direction.yaw * Leap.RAD_TO_DEG
del self.data_5[0]
self.data_5.append(arm_data)
arm_data = avg(self.data_5)
arm_rotation = map_transfer(arm_data, 50, -50, 1000, 2000)
indexfinger_direction = hand.fingers[1].bone(2).direction
middlefinger_direction = hand.fingers[2].bone(2).direction
finger_data = indexfinger_direction.angle_to(middlefinger_direction) * Leap.RAD_TO_DEG
del self.data_6[0]
self.data_6.append(finger_data)
finger_data = avg(self.data_6)
finger_angle = map_transfer(finger_data, 40, -40, 1100, 2100)
print "%d,%d,%d,%d,%d,%d\n" % (finger_angle, clawdata, hand_angle_data, servo_4, servo_5, arm_rotation)
serial_data = "%d,%d,%d,%d,%d,%d\n" % (finger_angle, clawdata, hand_angle_data, servo_4, servo_5, arm_rotation)
self.ser.write(serial_data)
if not (frame.hands.is_empty and frame.gestures().is_empty):
print ""
def main():
listener = SampleListener()
controller = Leap.Controller()
controller.add_listener(listener)
print "Press Enter to quit..."
try:
sys.stdin.readline()
except KeyboardInterrupt:
pass
finally:
controller.remove_listener(listener)
if __name__ == "__main__":
main()
[/mw_shl_code]
|
|