When seeking a way to get rid of that pesky single actuator known as the ServoMotion actuator, I came across a 2.49 solution by cyboarg_ar.
His solution created a linear servo that was identacle to the servo motion actuator. I didn’t want all of it (ie reference objects), but wanted it as simple as possible, so I got rid of quite a bit. I also wanted a rotational servo, where you could set a torque and desired rotation speed.
Here are the two classes I ended up with, and they work pretty well.
class rotServo: '''Acts like a servo motion actuator, but rotationally'''
integral = mathutils.Vector([0,0,0])
prev_error = mathutils.Vector([0,0,0])
pid = [30.0, 0.5, 0]
def __init__(self, owner, torque_max = [0,0,0], torque_min = [0,0,0], rotV = [0,0,0], local=True):
'''Sets initial values for the servo'''
self.torque_max = mathutils.Vector(torque_max)
self.torque_min = mathutils.Vector(torque_min)
self.rotV = mathutils.Vector(rotV)
self.owner = owner
self.local = local
def update(self):
'''This function must be run each time you want the servo to update'''
cur_speed = mathutils.Vector(self.owner.getAngularVelocity(self.local))
error = self.rotV - cur_speed
self.integral += error
derivative = error - self.prev_error
self.prev_error = error
action = error * self.pid[0] + self.integral * self.pid[1] + derivative * self.pid[2]
for i in range(3):
if self.torque_min[i] != None and action[i] < self.torque_min[i]:
action[i] = self.torque_min[i]
if self.torque_max[i] != None and action[i] > self.torque_max[i]:
action[i] = self.torque_max[i]
self.owner.applyTorque(action, self.local)
class linServo:
'''Acts like a servo motion actuator'''
integral = mathutils.Vector([0,0,0])
prev_error = mathutils.Vector([0,0,0])
pid = [30.0, 0.5, 0]
def __init__(self, owner, force_max = [0,0,0], force_min = [0,0,0], linV = [0,0,0], local=True):
'''Sets initial values for the servo'''
self.force_max = mathutils.Vector(force_max)
self.force_min = mathutils.Vector(force_min)
self.linV = mathutils.Vector(linV)
self.owner = owner
self.local = local
def update(self):
'''This function must be run each time you want the servo to update'''
cur_speed = mathutils.Vector(self.owner.getLinearVelocity(self.local))
error = self.linV - cur_speed
self.integral += error
derivative = error - self.prev_error
self.prev_error = error
action = error * self.pid[0] + self.integral * self.pid[1] + derivative * self.pid[2]
for i in range(3):
if self.force_min[i] != None and action[i] < self.force_min[i]:
action[i] = self.force_min[i]
if self.force_max[i] != None and action[i] > self.force_max[i]:
action[i] = self.force_max[i]
self.owner.applyForce(action, self.local)
Instructions for use:
Create a servo by creating an instance of the class, and dump it somewhere:
cont.owner['rot_servo'] = rotServo(cont.owner, torque_max=[5,5,5], torque_min=[-5,-5,-5])
Give it a target velocity:
cont.owner['rot_servo'].rotV = [5,0,0]
And every frame you want it to take effect, update it:
cont.owner['rot_servo'].update()
The only difference between a rotational servo and a linear one is that:
- torque_max vs force_max
- torque_min vs force_min
- rotV vs linV
Hopefully someone else finds this useful, and if anyone sees any improvements, feel free to do so, and post back here.
<b>Bugs:</b>
- There seems to be a little drifting, but I'm not sure why.