How to manually rotate and set keyframes on bones in Python

I’ve been trying several code snippets to rotate and set keyframes for the new position of bones using Python in Blender. All of these have created errors. For example, I attempted this code, but it told me bone objects have not such method as “rotation_euler”

{code}
bpy.ops.object.mode_set(mode=‘POSE’)
thebone=bpy.context.object.data.bones[‘B3’]
thebone.select = True
thebone.rotation_euler = [-30.0,0.0,0.0]
{/code}

type that into the console, then type thebone. followed by “ctrl + spacebar” and see all the listed props…you may also be able to do it using an operator…by making the bone you want selected and active, bpy.ops.tranform…etc etc. Not the most detailed of answers, but enough to get you googling.

That didn’t really help out. Basically all of my problems are caused because I do not know how to reference pose bones. Every time I try to access data frompose bones the blender console tells me the object type does not have that type of command.

Well, either you blender copy is mischievous and lying to you, or you are asking it the wrong thing…think of ‘ctrl’ + ‘spacebar’ as truth serum for mischievous lying Blender copies that need to be put into timeout. :evilgrin: Ok, truth time for me, I’ve never used python with an armature before but this is what is so great about autocomplete in the console (ctrl + spacebar is autocomplete)

I added an armature with one bone, I went to edit mode and extruded it several times so I had 4 bones. I didn’t know what extrude would do, but luckily and logically, hitting e caused a new bone to spring out of the previous one and each new bone became a child of the one before it. Then I went to pose mode.

in the console…without the lines starting with #. I typed.


#the armature object
my_armature = bpy.context.object
#the bone within the armature data
my_bone = my_armature.data.bones['Bone.001']

now…in the console, I type “my_bone.” and then ‘ctrl’ + ‘spacebar’ and see what it has


>>> my_bone.
            as_pointer(
            basename
            bbone_in
            bbone_out
            bbone_segments
            bbone_x
            bbone_z
            bl_rna
            callback_add(
            callback_remove(
            center
            children
            children_recursive
            children_recursive_basename
            driver_add(
            driver_remove(
            envelope_distance
            envelope_weight
            evaluate_envelope(
            get(
            head
            head_local
            head_radius
            hide
            hide_select
            id_data
            is_property_hidden(
            is_property_set(
            items(
            keyframe_delete(
            keyframe_insert(
            keys(
            layers
            length
            matrix
            matrix_local
            name
            parent
            parent_index(
            parent_recursive
            path_from_id(
            path_resolve(
            rna_type
            select
            select_head
            select_tail
            show_wire
            tail
            tail_local
            tail_radius
            translate(
            type_recast(
            use_connect
            use_cyclic_offset
            use_deform
            use_envelope_multiply
            use_inherit_rotation
            use_inherit_scale
            use_local_location
            values(
            vector
            x_axis
            y_axis
            z_axis

indeed, there is no “rotation_euler”…so that’s good, Blender didn’t lie to you, I owe it an apology. You will probably want to check out the “matrix” and “martix_local” properties if you want to set them by hand in this way. Eg


my_bone.matrix = my_calculated_matrix

when you do it this way, it doesnt have to be selected, you are manually setting the data to something. If however, you want to say rotate it by _____ from where it is, and calculating the matrix is a pain (which it would be for me because who paid attention in middle school?)


#deselect all the other ones if they are
bpy.ops.pose.select_all(action = 'DESELECT')

#make the bone I want selected
my_bone.select = True

#Rotate it....
bpy.ops.transform.rotate(

and now press ‘ctrl’ + ‘spacebar’ to learn about the rotate operator syntax which I will leave as an exercise for you. As a heads up, the rotate operator sytax is a little bit weird, just use all the commas that look like they shouldn’t be there and you will be fine :slight_smile: THe difference is that here, we are calling an operator to modify an objects data. It knows what to work on based on what is selected and/or active.

I’ve been doing a lot of research, but it’s not going well. The Blender Python API documentation is atrocious. There are very few examples and the info is spread out on multiple websites. There needs to be a comprehensive manual for this aspect of Blender.

Anyway, I’ve been attempting to keyframe rotations on a named Pose Bone. I’m able to find, select and set keyframes on the bone but there is no way to input the data into the keyframes. For example:

{code}

Get the bone name B3 and set two rotational keyframe for it

bpy.ops.object.mode_set(mode=‘POSE’)
thebone=bpy.context.object.pose.bones[‘B3’]
thebone.keyframe_insert(‘rotation_euler’, index=0,frame=0)
thebone.keyframe_insert(‘rotation_euler’, index=1,frame=10)
{/code}
this does indeed create keyframes for the selected bone but they are empty. There doesn’t seem to be a way to specify in the “keyframe_insert” command what rotational value you want the keyframe to have. I’ve tried using “action.fcurves[x].keyframe_points.insert(x,x)” but it’s not practical because the fcurves doesn’t reference the specific bone I’m trying to target. Also, if you try sending the rotational value that shows up in the number panel (example:x=-30), that value is way out of whack in the graph editor. instead of the bone rotating 30 degrees it rotates something like 3000 degrees.

Any ideas anyone?

Ok. I have now found a way to set keyframes on the pose bone I want. Now the issue is this. If I rotate the bone to (-30,0,0) and set a keyframe for it using python, Python creates a keyframe with a value of -1500!!!

Here is the code I am using


    action=bpy.data.actions['ArmatureAction']
    # KEYFRAME ON BONE
    bpy.ops.object.mode_set(mode='POSE')
    thebone=bpy.context.object.pose.bones['B3']
    thebone.rotation_euler=(-30.0,0.0,0.0)
    thebone.keyframe_insert(data_path='rotation_euler',frame=10)
    thebone.rotation_euler=(0.0,0.0,0.0)
    thebone.keyframe_insert(data_path='rotation_euler',frame=20)

use radians