Ejemplo n.º 1
0
class HandView(object):
    def __init__(self, handColor, objColor, grasps):
        self.setDefaults(handColor, objColor)
        self.setView()
        self.grasps = grasps

    def setDefaults(self, handColor, objColor):
        #handColor and objColor are colors from Colors.py
        #sets any start hardcoded values
        self.fingerOpeningDict = {1: False, 2: False, 3: False}
        self.handMovingForward = {"X": False, "Y": False, "Z": False}
        self.ignoreContact = {"1": True, "2": True, "3": True, "Palm": True}
        self.distJointAngles = {"min": 0, "max": .837}
        self.medJointAngles = {"min": 0, "max": 2.44}
        self.handColor = handColor
        self.objColor = objColor

    def addGroundPlane(self):
        #adds a ground plane to the scene
        self.ground = AddGroundPlane(self.vis)
        self.ground.createGroundPlane(.175)

    def setView(self):
        #creates a scene with a ground plane
        self.vis = Vis()
        self.vis.setCamera(60, 7 * np.pi / 8, 0)
        self.addGroundPlane()

    def addHand(self, grasp):
        #grasp is either "The Two-fer", "The Claw", "The Pinch", "The Cup"
        #adds the hand to the scene and sets the grasp and wrist rotation
        self.Hand = HandVis(self.vis)
        self.Hand.loadHand()
        self.Hand.changeColor(self.handColor)
        self.setGrasp(grasp)
        self.setWristRotation('Z', 0)

    def addObject(self, objParameters):
        #objParameters = {"shape":,"h":,"w":,"e":,"a":}
        #adds an object to the scene based on the object parameters
        #shifts the hand accordingly
        self.Obj = ObjectGenericVis(self.vis)
        self.setHandTranslation(
            'Z', -.075 - (float(objParameters["e"]) / 100) - .02)
        self.setObject(objParameters)
        self.Obj.changeColor(self.objColor)

    def setIgnoreAllContact(self, value):
        #value is either True or False
        #sets all fingers and palm to ignore or not ignore contact with the object
        for link in self.ignoreContact:
            self.ignoreContact[link] = value

    def setIgnoreFingerContact(self, value):
        #value is either True or False
        #sets all fingers to ignore or not ignore contact with the object
        for link in self.ignoreContact:
            if link != "Palm":
                self.ignoreContact[link] = value

    def totalNumberofTranslationIncrements(self, newOffset, increment):
        #newOffset is a float and increment is a float
        #returns the total number of iterations of the increment to reach the newOffset
        return int(math.ceil((newOffset + increment) / increment))

    def translateHand(self, dimension, amount):
        #direction should be either 'X', 'Y', or 'Z' ;;; amount is a float
        #shifts the hand in relation to the object in the direction of the dimension by the amount
        if dimension == 'X':
            self.Hand.localTranslation(np.array([amount, 0, 0]))
        elif dimension == 'Y':
            self.Hand.localTranslation(np.array([0, amount, 0]))
        elif dimension == 'Z':
            self.Hand.localTranslation(np.array([0, 0, amount]))

    def tryTranslateHandByOneIncrement(self, dimension, increment):
        #direction should be either 'X', 'Y', or 'Z' ;;; increment is a float
        #shifts the hand in the direction of dimension by the increment
        #if hand comes into contact with the object and contact is not ignored,
        #hand backs up to where it started and returns False, otherwise returns True
        #if contact is ignored, but the palm is not in contact, it no longer ignores contact
        self.translateHand(dimension, increment)
        pC = self.palmContact()
        if self.ignoreContact["Palm"]:
            self.ignoreContact["Palm"] = pC
            return True
        else:
            if pC:
                self.setHandTranslation(dimension, -increment)
                return False
            else:
                return True

    def setHandTranslation(self, dimension, newOffset):
        #shifts the hand in the direction of dimension by the newOffset
        #if shifting the hand causes a collision between the palm and object,
        #hand is shifted in the opposite direction by one increment so it is no longer touching
        #returns the amount by which the hand was shifted
        direction = newOffset / abs(newOffset)
        increment = .005 * direction
        for i in range(
                1,
                self.totalNumberofTranslationIncrements(newOffset, increment)):
            if not self.tryTranslateHandByOneIncrement(dimension, increment):
                return (i - 1) * increment
        return newOffset

    def setWristRotation(self, direction, rotation):
        #direction should be either 'X', 'Y', or 'Z' ;;; rotation is a float
        #rotates the hand's wrist in the direction specified
        #sets ignore contact for every finger/palm
        if direction == 'X':
            rot = matrixFromAxisAngle([rotation, 0, 0])
        elif direction == 'Y':
            rot = matrixFromAxisAngle([0, rotation, 0])
        elif direction == 'Z':
            rot = matrixFromAxisAngle([0, 0, rotation])
        self.Hand.localRotation(rot)
        self.setIgnoreAllContact(True)

    def setObjRotation(self, direction, rotation):
        #direction should be either 'X', 'Y', or 'Z' ;;; rotation is a float
        #rotates the object in the direction specified
        #sets ignore contact for every finger/palm
        if direction == 'X':
            rot = matrixFromAxisAngle([rotation, 0, 0])
        elif direction == 'Y':
            rot = matrixFromAxisAngle([0, rotation, 0])
        elif direction == 'Z':
            rot = matrixFromAxisAngle([0, 0, rotation])
        self.Obj.localRotation(rot)
        self.setIgnoreAllContact(True)

    def setObject(self, newObj):
        #newObj is a dict {"shape":, "h":, "w":, "e":, "a":}
        #assumes an object has already been added with addObject
        #sets ignore contact for every finger/palm
        if newObj["shape"] == 'cone':
            self.Obj.loadObject(newObj["shape"], int(newObj["h"]),
                                int(newObj["w"]), int(newObj["e"]),
                                int(newObj["a"]))
        else:
            self.Obj.loadObject(newObj["shape"], int(newObj["h"]),
                                int(newObj["w"]), int(newObj["e"]), None)
        self.Obj.changeColor(self.objColor)
        self.setIgnoreAllContact(True)

    def setGrasp(self, newGrasp):
        #newGrasp is one of the keys in self.grasps
        #sets the grasp so that it goes to a certain pregrasp
        #sets ignore contact for every finger/palm
        #returns the new grasp array so the finger sliders can be reset
        self.grasp = self.grasps[newGrasp]
        self.showGrasp()
        self.setIgnoreFingerContact(True)
        return self.grasp

    def getMedJointAngle(self, percentClosed):
        #percentClosed is a float 0<>100
        #returns the grasp array value for a med joint given the percent it is closed
        return ((self.medJointAngles["max"] - self.medJointAngles["min"]) *
                percentClosed) + self.medJointAngles["min"]

    def getDistJointAngle(self, percentClosed):
        #percentClosed is a float 0<>100
        #returns the grasp array value for a the dist joint given the percent it is closed
        return ((self.distJointAngles["max"] - self.distJointAngles["min"]) *
                percentClosed) + self.distJointAngles["min"]

    def fingerOpening(self, finger, percentClosed):
        #finger is either 1, 2, or 3
        #percentClosed is a float 0<>100
        #returns a bool
        if finger == 1:
            return self.getMedJointAngle(percentClosed) < self.grasp[3]
        elif finger == 2:
            return self.getMedJointAngle(percentClosed) < self.grasp[6]
        elif finger == 3:
            return self.getMedJointAngle(percentClosed) < self.grasp[8]

    def anyFingerContact(self):
        #returns whether any finger is in contact with the object
        for contact in self.Hand.getContact(self.Obj.boj).keys():
            if contact.find("finger_") != -1 and contact[-9:] != "prox_link":
                return True
        return False

    def fingerContact(self, finger):
        #finger should be either 1, 2, or 3
        #returns whether the provided finger is in contact with the object
        for contact in self.Hand.getContact(self.Obj.obj).keys():
            if contact.find("finger_" +
                            str(finger)) != -1 and contact[-9:] != "prox_link":
                return True
        return False

    def fullFingerContact(self, finger):
        #finger is either 1, 2, or 3
        #if the tip finger link is in contact, returns 't' (finger is fully in contact)
        #if only the lower finger link is in contact, returns 's' (only lower link in contact)
        #if there is no contact return 'f' (nothing is in contact)
        someContact = False
        for contact in self.Hand.getContact(self.Obj.obj).keys():
            if contact.find("finger_" +
                            str(finger)) != -1 and contact[-9:] == "dist_link":
                return 't'
            elif contact.find("finger_" + str(finger)
                              ) != -1 and contact[-8:] == "med_link":
                someContact = True
        if someContact:
            return 's'
        else:
            return 'f'

    def palmContact(self):
        #returns whether or not the palm is in contact with the object
        for contact in self.Hand.getContact(self.Obj.obj).keys():
            if contact[-9:] == "palm_link":
                return True
        return False

    def fingerChangingDirection(self, finger, percentClosed):
        #finger is either 1, 2, or 3
        #percentClosed is a float 0<>100
        #determines if the finger's motion has changed (was closing, now opening or was opening, now closing)
        return self.fingerOpening(
            finger, percentClosed) != self.fingerOpeningDict[finger]

    def fingerCanBeMovedThisWay(self, finger, percentClosed, contact):
        #finger is either 1, 2, or 3
        #percentClosed is a float 0<>100
        #contact is either 't', 'f', or 's'
        return self.ignoreContact[str(finger)] or self.fingerChangingDirection(
            finger, percentClosed) or contact != 't'

    def setFingerPosition(self, finger, percentClosed, contact):
        #finger is either 1, 2, or 3
        #percentClosed is a float 0<>100
        #contact is either 't'(rue), 'f'(alse), or 's'(some)
        #sets the new grasp values for the finger joints depending on which fingers have contact
        if finger == 1:
            if contact == 'f':
                self.grasp[3] = self.getMedJointAngle(percentClosed)
            self.grasp[4] = self.getDistJointAngle(percentClosed)
        elif finger == 2:
            if contact == 'f':
                self.grasp[6] = self.getMedJointAngle(percentClosed)
            self.grasp[7] = self.getDistJointAngle(percentClosed)
        elif finger == 3:
            if contact == 'f':
                self.grasp[8] = self.getMedJointAngle(percentClosed)
            self.grasp[9] = self.getDistJointAngle(percentClosed)
        self.showGrasp()
        print self.grasp

    def changeFingerPosition(self, finger, percentClosed):
        #finger is either 1, 2, or 3
        #percentClosed is a float 0<>100
        #changes the finger position to the new percentage if possible
        #checks the ignoreContact safeguard can be removed
        #returns whether or not the finger could be moved as suggested
        contact = self.fullFingerContact(finger)
        if self.fingerCanBeMovedThisWay(finger, percentClosed, contact):
            self.fingerOpeningDict[finger] = self.fingerOpening(
                finger, percentClosed)
            self.setFingerPosition(finger, percentClosed, contact)
            if self.ignoreContact[str(finger)]:
                self.ignoreContact[str(finger)] = self.fingerContact(finger)
            return True
        return False

    def getFingerPositionPercent(self, finger):
        #finger is either 1, 2, or 3
        #returns the percent of the finger closed
        if finger == 1:
            return (self.grasp[3] - self.medJointAngles["min"]) / (
                self.medJointAngles["max"] - self.medJointAngles["min"])
        elif finger == 2:
            return (self.grasp[6] - self.medJointAngles["min"]) / (
                self.medJointAngles["max"] - self.medJointAngles["min"])
        elif finger == 3:
            return (self.grasp[8] - self.medJointAngles["min"]) / (
                self.medJointAngles["max"] - self.medJointAngles["min"])

    def showGrasp(self):
        #sets the Hand to the new grasp
        self.Hand.setJointAngles(self.grasp)
Ejemplo n.º 2
0
class TrainingVideo(object):
	def __init__(self):
		self.vis = Vis()
		self.Hand = HandVis(self.vis)
		self.Hand.loadHand()
		self.Obj = ObjectGenericVis(self.vis)
		self.GP = AddGroundPlane(self.vis)
		self.demoObj = list()
		self.frameCount = 0
		self.start_offset = 0

	def recordFrame(self):
		fn = 'Image%04d.png' %self.frameCount
		self.vis.takeImage(fn, delay = False)
		self.frameCount += 1

	# Kadon Engle - last edited 07/14/17
	def fingerRecord(self, oldJA, newJA): # Records a frame for multiple join angles between the starting array (OldJA) amd the ending array (newJA)
		try:
			frame_rate = 20 # An arbitrary base line for the frames in each hand movement
			frames = int(max(abs(newJA - oldJA)) * frame_rate)
			Angles = []
			self.Hand.setJointAngles(oldJA)
			if len(self.Hand.getContactPoints()) > 0:
				self.Hand.setJointAngles(iP[-1])
			for i in range(frames):
				Angles.append(list())
			for i in range(len(oldJA)):
				current = np.linspace(oldJA[i], newJA[i], frames)
				for k in range(frames):
					Angles[k].append(current[k])
			for n, i in enumerate(Angles): #More work is necessary on detecting finger collision to stop the fingers
				self.Hand.setJointAngles(np.array(i))
				if len(self.Hand.getContactPoints()) > 0:
					self.Hand.setJointAngles(Angles[n-1])
					return Angles[n-1]
				self.recordFrame()
			return Angles[n-1]

		except:
			print "Invalid Joint Angle"

	# Kadon Engle - last edited 07/14/17
	def handRecord(self, x, y, z): # Records frames as hand moves in x, y, and/or z direction
		self.T_current = self.Hand.obj.GetTransform()
		T = copy.deepcopy(self.T_current)
		xyz = [x, y, z]
		frames = 20 # Arbitrary value, needs to be changed so that when x, y, or z moves shorter distances, it records less frames. Should be changed so that it records less frames for shorter movements and more frames for longer movements.
		for idx, i in enumerate(xyz):
			if abs(i - self.T_current[idx,3]) > 0.1e-5:
				V = np.linspace(self.T_current[idx,3], i, frames)
				for n in V:
					T[idx,3] = n
					self.Hand.obj.SetTransform(T)
					self.recordFrame()

	def stationaryRecord(self, frames):
		for i in range(int(frames)):
			self.recordFrame()

	def createVideo(self, fn): # creates a video from images recorded in previous section
		# there is a built in openrave function which would be much better, but doesn't work on all hardware
		
		# uses PIL and cv2. opencv is a pain to setup, so may not be worth the hassle
		try:
			if os.path.splitext(fn)[1] != '.avi':
				print("Did not save Video: Invalid File Name")
				return
			initImage = Image.open('Image0001.png')
			height, width, layers = np.array(initImage).shape
			fourcc = cv2.VideoWriter_fourcc(*'XVID')
			video = cv2.VideoWriter(fn, fourcc, 24, (width, height))
			Files = os.listdir(curdir)
			for file in np.sort(Files):
				if os.path.splitext(file)[1] == '.png':
					image = Image.open(file)
					video.write(cv2.cvtColor(numpy.array(image), cv2.COLOR_RGB2BGR))
			video.release()
		except:
			print 'Something went wrong. Maybe you didn\'t record any images'

		# native linux method -- most likely to work
		# subprocess.call(["avconv", "-f", "image2", "-i", "Image%04d.png", "-r", "5", "-s", "800x600", fn+".avi"])

	def removeImages(self): # remove image files that were created
		Files = os.listdir(curdir)
		for file in Files:
			if os.path.splitext(file)[1] == '.png':
				os.remove(file)

	def VLCPlay(self, fn):
		subprocess.call(["vlc", fn])

	def Video1(self): 
		# setup
		self.Obj.loadObject('cube',36,18,3,None)  # TODO: Object with larger extent!
		self.Obj.changeColor('purpleI')
		self.Hand.changeColor('mustard')
		self.GP.createGroundPlane(0.175)
		extent_offset = -3.0/100 # offset by thickness of object
		palm_offset = -0.075 #offset so palm is at 0,0,0
		clearance_offset = -1.0/100 # offset to have clearance between palm and object
		self.start_offset = extent_offset + palm_offset + clearance_offset
		self.Hand.localTranslation(np.array([0, 0, self.start_offset]))
		rot = matrixFromAxisAngle([0,0, np.pi/2])
		self.Hand.localRotation(rot) # rotate hand to put stationary finger on one side of object
		self.T_start = self.Hand.obj.GetTransform() # get starting transform so everything can be done relative to this
		oHand = np.array([0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) # position fingers such that hand can move in x, y, and z without hitting object
		cHand = np.array([0, 0, 0.0, 1.3, 0.4, 0.0, 1.3, 0.4, 1.3, 0.4]) # position fingers such that the hand will be closed around the object without hititng it
		self.Hand.setJointAngles(oHand)
		dist_range_min = -0.1
		dist_range_max = 0.1
		frame_rate = 20/0.1 # frames/cm
		# Different arbitrary camera angles for needed viewpoints
		# self.vis.setCamera(60,3*np.pi/4,-np.pi/4-0.1)
		# self.vis.setCamera(60, np.pi, -np.pi/2) # top view
		# self.vis.setCamera(60, -2.25, -np.pi/2.10)
		self.vis.setCamera(60, -2.25, -0.75) # Numbers are completely arbitrary, gives a good view of object and hand.