Moving two objects together as one

I’m looking for a way to attach two nodes in a scene together to move as if they were one. Based on my understanding of scene graphs, I would expect this to be possible by reparenting one node to another, so that I could move the parent (with e.g. setPos or applying a force with Bullet) and the child would inherit its movement and move along with it. This remark on Panda’s description of its scene graph seems to support that understanding:

Positions of objects are specified relative to their parent in the tree. For example, if you have a 3D model of a hat, you might want to specify that it always stays five units above a 3D model of a certain person’s head. Insert the hat as a child of the head, and set the position of the hat to (0,0,5).

But that’s not the behavior I’m finding. If I move the parent node, the child stays put when I view the scene (though oddly its global coordinates according to getPos() seem to move with the parent’s). Is there a way to get the effect I’m looking for, through reparenting or other means? In addition to setPos(), I’ve tried Bullet’s applyCentralForce() method to move the parent node, and this doesn’t move the child either.

Here’s the relevant portion of the code I’ve been using to test this with:

# PARENT
self.model = loader.loadModel('model.gltf')
self.parent_model = self.model.find('Parent')
self.parent_body = BulletCylinderShape(4.5, 20, YUp)
node = BulletRigidBodyNode('parent')
node.setMass(1)
node.addShape(self.parent_body)
self.parent = self.render.attachNewNode(node)
self.parent.setPos(0, 0, 0)
self.world.attachRigidBody(node)
self.parent_model.reparentTo(self.parent)
self.parent.node().setDeactivationEnabled(False)

# CHILD
self.child_model = self.model.find('Child')
self.child_body = BulletCylinderShape(1.75, 2, YUp)
node = BulletRigidBodyNode('child')
node.setMass(1)
node.addShape(self.child_body)
self.child = self.render.attachNewNode(node)
self.child.setPos(20, 0, 0)
self.world.attachRigidBody(node)
self.child_model.reparentTo(self.child)
self.child.node().setDeactivationEnabled(False)
self.child.reparentTo(self.parent)  # Reparent

# MOVE PARENT
self.parent.setPos(0,0,10)

print('parent',self.parent.getPos(self.render))  # Prints (0, 0, 10)
print('child',self.child.getPos(self.render))  # Prints (20, 0, 10), but child appears at (20, 0, 0)

# These lines don't move the child either:
# v = LVector3(200, 0, 0)
# self.parent.node().applyCentralForce(v)

What you want is strange from the point of view of logic, the Panda3D node system is not designed for a bullet. You need to create a bullet body with two geometric shapes(composite).

node.addShape(body0)
node.addShape(body1)

https://docs.panda3d.org/1.10/python/programming/physics/bullet/collision-shapes#compound-shape

Thanks for your help! That works nicely.