liu
liu

Reputation: 73

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)

Upvotes: 0

Views: 1341

Answers (2)

Lukas Graf
Lukas Graf

Reputation: 32580

Your HexLimb needs to know about the HexBones attached to it to calculate its position. But the HexBones, being Servos, 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()

Upvotes: 1

liu
liu

Reputation: 73

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()

Upvotes: 0

Related Questions