Background: I am trying to do a animation of the deformation of a thin sheet, that has its motion at each point that is modeled as a sin wave (something like z = A*sin(freq*t + phi), where A and phi are the amplitude and phase offset of each point, and t is time. Much like water wave simulation, but I do need to be able to set each point amplitude and phase precisely. I modelled the surface as your standard grid, but with two planes so it is a sheet. I then added an armature with a bone for each point ( I tried shapekeys, but bones seemed to be easier), and also added a driver for each pose bone. I can access the drivers through Python with code like the following

obj = bpy.data.objects['Armature']   # the armature my model is 
drivers = obj.animation_data.drivers    
for d in drivers:
    d.driver.expression = "%f *sin(frame / %f + %f)" % (amp, frame_div, phi)

However, then problem I have no idea which driver applies to which pose bone. The driver data structure seems to give no indication which bone it is driving. I assumed the order in which I added the drivers is the same as the order of the bones, and this cam close but some seemed off.

So, the basic problem is, how do you know which driver applies to which pose bone, in Python?

Alternatively, is there a better way to do what I am trying to accomplish, without using bones/drivers?


2 Answers 2


You might try this:

import bpy

obj = bpy.data.objects['Armature']

#get pose_bone
pb = obj.pose.bones['Bone']
#add drivers
driver_loc = pb.driver_add('location')
driver_rot = pb.driver_add('rotation_quaternion')

#search for a driver
for d in obj.animation_data.drivers:
    if d.data_path.startswith('pose.bones'):
        id = d.data_path.split('"')[1]
        prop = d.data_path.rsplit('.', 1)[1]
        if id == pb.name and prop == 'location':
   d = None

if d:
    #... settings
    d.driver.expression = your_expr
  • $\begingroup$ Thanks! I will give this a try. I am also thinking about scripting the creation of the armature/bones as well. $\endgroup$ Jul 7, 2014 at 18:59

pink vertex has a solution. The core is that driver.data_path tells you what field is being modified. There's also an array_index which is needed for tuples like location, scale, and rotation_* .

I have an example at http://web.purplefrog.com/~thoth/blender/python-cookbook/driver-fin.html which creates several drivers to animate a waving fin.

I'll include part of it here:

def addDrivers(ao, nSegs, rotor):

    nRotors = len(rotor.pose.bones)-1
    for u in range(0, nSegs+1):
        for r in range(1,3):
            bn = "u=%d r=%d"%(u,r)
            dr = ao.driver_add("pose.bones[\"%s\"].rotation_euler"%bn, 0)
            dr.driver.type = 'AVERAGE'
            var = dr.driver.variables.new()
            var.type = 'TRANSFORMS'
            var.targets[0].id = rotor
            if (r==1):
                ridx = u%nRotors
                ridx = (u-2 + nRotors)%nRotors
            var.targets[0].bone_target = "rotor %d" % ridx
            var.targets[0].transform_type = 'LOC_Y'

If you're going to use expressions instead of targets (like world/local position/rotation) then your code will be simple like pink vertex wrote.

I used targets because I like to avoid having to enable python in my drivers when I know how to get around it (it's a mathematics machismo thing).


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .