import math import time import serial from vector2 import Vector from decimal import * getcontext().prec = 8 XOFFSET = 200 YOFFSET = 200 L1 = 198 L2 = 180 ser = serial.Serial('/dev/ttyUSB0',9600,timeout=0,parity=serial.PARITY_NONE) #example: ser.write(serial.to_bytes((255,0,100))) where 255 is always 255, 0 is the servo number, and 100 is the servo position, scaled from 0-254 class linkage: def __init__(self,L1,L2,theta1=0,theta2=0): self.L1 = L1 #bicep length self.L2 = L2 #forearm length self.theta1 = theta1 #Shoulder self.theta2 = theta2 #Elbow self.x,self.y = self.forward() #hand position def degrees(self): '''return tuple of shoulder,elbow angles''' mlt = 180/math.pi return (mlt*self.theta1,mlt*self.theta2) def set_inverse(self,x,y): '''given x,y pair, figure out and set my angles, and new xy values''' self.theta1,self.theta2 = self.inverse(x,y) self.set_forward() def inverse(self,x,y): '''given x,y pair, figure out angles''' B = math.sqrt(x**2 + y**2) q1 = math.atan2(y,x) q2 = math.acos((self.L1**2 - self.L2**2 + B**2)/(2 * self.L1 * B)) theta1 = q1+q2 theta2 = math.pi - math.acos((self.L1**2 + self.L2**2 - B**2)/(2 * self.L1 * self.L2)) return (theta1,theta2) def set_forward(self): '''re-calculate and set my hand position x,y values''' self.x, self.y = self.forward() def forward(self): '''calculate and return my hand position x,y values''' y = math.sin(self.theta1)*self.L1 x = math.cos(self.theta1)*self.L1 y += math.sin(self.theta1 - self.theta2)*self.L2 x += math.cos(self.theta1 - self.theta2)*self.L2 return (Decimal(str(x)),Decimal(str(y))) def move(self,x,y,steps=1,stepdelay=1): '''splits a move up into intermediate points this results in a straighter line from the current point to x,y''' y += YOFFSET x += XOFFSET y = -y #get in the right plane steps = Decimal(steps) dx = (x - self.x)/steps dy = (y - self.y)/steps step = 1 while step <= steps: self.set_inverse(self.x + dx,self.y + dy) print 'moved to', self.truex(),self.truey(), 'angles are', self.degrees() self.apply_xy() #time.sleep(stepdelay) #stepdelay should probably end up being a function of dx and dy step += 1 def truex(self): return self.x - XOFFSET def truey(self): return self.y + YOFFSET def apply_xy(self): '''this invokes the serial communication to the servos which causes them to move to the position of this class model''' p1 = self.theta1 #p1 and p2 are the scaled values for servo position from 0-254 instead of -90 to 90 or whatever p2 = self.theta2 p1,p2 = translate(p1,-p2) ser.write(serial.to_bytes((255,0,p1))) #write x time.sleep(.1) ser.write(serial.to_bytes((255,1,p2))) #write y pass def apply_z(self): '''this talks over the serrial communication to set the z height''' p3 = self.z ser.write(serial.to_bytes((255,2,p3))) #write z def translate(theta1,theta2): mid = int(254/2) mult = 3 div = 5 #mapping: right90=70 zero=127 left90=180 #end mapping deg1 = theta1 *180/math.pi deg1 = 127 + 54*deg1/90 deg1 -= 3 deg2 = theta2 *180/math.pi deg2 = 127 + 54*deg2/90 deg2 += 12 return (int(deg1),int(deg2))