简体   繁体   中英

Python - Extend Class Instance Method

I'm creating the "framework" to control a Hexapod. So (simplifying) I have a Servo class:

class Servo(object):
...
        def setAngle(self, angle):
                ##Executes order to move servo to specified angle
                ##Returns False if not possible or True if OK
                offsetAngle=self.offset+angle
                if not self.checkServoAngle(offsetAngle):
                        #Angle not within servo range
                        return=False
                else:
                        pwmvalue=self._convAngleToPWM(offsetAngle)
                        self._setPWM(pwmvalue)
                        self.angle=value
                        return=True
...

and a child HexBone class:

class HexBone(Servo):
    ## Servo.__init__ override:
    def __init__(self, I2C_ADDRESS, channel, length, startAngle, reversed=False, minAngle=NULL, maxAngle):       
        self = Servo(I2C_ADDRESS, channel, reversed, minAngle, maxAngle)

        #Setting bone length
        self.length=length
        #Positions bone in Starting Position 
        self.setAngle(startAngle)

and also a HexLimb class:

class HexLimb(object):
    def __init__(self, I2C_ADDRESS, femurLength, tibiaLength, femurInv, tibiaInv):
        #Setting precision of Limb Positioning
        self.precision=1

        #Setting i2c address and servo channels
        self.femur = HexBone(I2C_ADDRESS, 1, femurLength, 45, femurInv, 5, 190)
        self.tibia = HexBone(I2C_ADDRESS, 2, tibiaLength, 90, tibiaInv, 5, 190)

    def calcPosition(self):
        L1=self.femur.length
        L2=self.tibia.length
        try:
            a1=90-self.femur.angle#########!!!!!!
            a2=180-self.tibia.angle
            self.x=L1*math.cos(math.radians(a1))+L2*math.cos(math.radians(a1-a2))
            self.y=L1*math.sin(math.radians(a1))+L2*math.sin(math.radians(a1-a2))
        except:
            return False
        else:
            return True

In the HexLimb class whenever I do: self.femur.setAngle(30) I want to call self.calcPosition() to recalculate the limb's tip position.

I've been searching all over and couldn't found any answer...Am I doing it the wrong way?

(edited accordingly comments bellow)

Your HexLimb needs to know about the HexBones attached to it to calculate its position. But the HexBones , being Servo s, also need to know about the HexLimb they are attached to so that they can trigger a re-calculation of the limb's position.

One solution is to keep a back-reference on the HexBones to the HexLimb they're attached to.

In this example, I create a back-reference called limb in HexLimb.__init__() on both bones - you could also call it parent to be more generic about it.

from random import random

class Servo(object):
    """Servo controller"""
    def __init__(self):
        self.angle = 0

    def set_angle(self, angle):
        print "Setting angle to %s" % angle
        self.angle = angle
        # Let limb recalculate its position
        self.limb.calc_position()


class HexBone(Servo):
    """A bone that can be attached to a limb and moved."""
    def __init__(self, length):
        super(HexBone, self).__init__()
        self.length = length

        # Will be assigned later when attached to a limb
        self.limb = None


class HexLimb(object):
    """A limb consisting of several bones."""
    def __init__(self):
        self.femur = HexBone(42)
        self.femur.limb = self

        self.tibia = HexBone(30)
        self.tibia.limb = self

    def calc_position(self):
        print "Calculating position..."
        # Something that needs self.femur and self.tibia
        self.x = self.femur.length * random()
        self.y = self.tibia.length * random()

    def extend(self):
        self.tibia.set_angle(0)    # extend knee


left_leg = HexLimb()
left_leg.extend()

Taking what Lukas Graf suggested i've changed the code a little bit in order to maintain the Servo class more general. Basically Servo (and inherently its child class HexBone) take a callback function reference as an optional argument for init (which defaults to None). When calling Servo.setAngle in the end this will execute the callback function. Code is as follows:

from random import random


class Servo(object):
    """Servo controller"""
    def __init__(self, callback=None): #Servo takes a callback function as argument
        self.angle = 0
        self.callback=callback

    def set_angle(self, angle):
        print("Setting angle to %s" % angle)
        self.angle = angle
        # After angle set executes the callback function
        if self.callback is not None: self.callback()


class HexBone(Servo):
    """A bone that can be attached to a limb and moved."""
    def __init__(self, length, callback):
        super(HexBone, self).__init__(callback)
        self.length = length


class HexLimb(object):
    """A limb consisting of several bones."""
    def __init__(self):
        self.femur = HexBone(42, self.calc_position)
        self.femur.limb = self

        self.tibia = HexBone(30, self.calc_position)
        self.tibia.limb = self

    def calc_position(self):
        print("Calculating position...")
        # Something that needs self.femur and self.tibia
        self.x = self.femur.length * random()
        self.y = self.tibia.length * random()

    def extend(self):
        self.tibia.set_angle(0)    # extend knee


left_leg = HexLimb()
left_leg.extend()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM