A script to create an armature, create and place each bone at the objects and child objects positions. Then it makes each object parented to the respective bones (bone parenting).

Note that the script will loose the previous parenting hierarchy as an object can only have one parent.
From that if you want rigged objects, not just bone parents, simply select them all and parent to the armature.
Script principles:
- Create an armature at the parent object location with same transformations
- Parse the object hierarchy and create an edit bone for each object, recursively
- Parse again in object mode to make the parenting to each object
Nearly each line is commented below. But if questions, please ask.
import bpy
from mathutils import Vector, Matrix
#Create the armature
def create_armature(object, collection):
armature_data = bpy.data.armatures.new(object.name)
armature = bpy.data.objects.new(object.name, armature_data)
armature.matrix_basis = object.matrix_basis
collection.objects.link(armature)
return armature
#Create the bones
def bone_from_hierarchy(object, armature, parent_bone = None):
#Create a bone parented and disconnect to its parent
bone = armature.data.edit_bones.new(object.name)
bone.parent = parent_bone
bone.use_connect = False
#Get its transformation matrix inside the armature from the object matrix
matrix = armature.matrix_world.inverted() @ object.matrix_world
#Place head and tail
bone.head = matrix @ Vector()
bone.tail = matrix @ Vector((0.0, 0.0, 1.0))
#Recurse through the children objects
for child in object.children:
bone_from_hierarchy(child, armature, bone)
#Parent the objects to the armarture
def parent_from_hierarchy(object, armature):
name = object.name
#Get the pose bone
bone = armature.pose.bones[name]
#Keep the object position
matrix_world = object.matrix_world.copy()
#Parent it
object.parent = armature
object.parent_type = 'BONE'
object.parent_bone = name
#Make so we can unparent and keep object's position
bone_matrix = Matrix.Translation(bone.tail - bone.head) @ bone.matrix
object.matrix_parent_inverse = (armature.matrix_world @ bone_matrix).inverted()
#Assigns its position
object.matrix_world = matrix_world
#Recurse through the children
for child in object.children:
parent_from_hierarchy(child, armature)
def make_bone_hierarchy(object):
if object:
armature = create_armature(object, object.users_collection[0])
#Enter edit mode for the armature in order to create edit bones
bpy.context.view_layer.objects.active = armature
bpy.ops.object.mode_set(mode='EDIT')
bone_from_hierarchy(object, armature)
#Back to object mode
bpy.ops.object.mode_set(mode='OBJECT')
#bpy.context.view_layer.objects.active = object
#Parent the objects to the armature
parent_from_hierarchy(object, armature)
root = bpy.context.view_layer.objects.active
make_bone_hierarchy(root)