角色动画(Actors)
本教程介绍如何向世界(World)中添加 角色(actor),以及如何创建脚本化动画(scripted animation)。
可在 此处 查看本教程最终的仿真世界。
如果希望实体在仿真中沿预定路径运动而不受物理影响,动画就非常有用。这类实体不会因重力而掉落,也不会与其他对象碰撞,但仍然拥有 3D 可视化外观,能被 RGB 相机看到;也有 3D 网格(mesh),能被基于 GPU 的传感器检测到。本教程介绍如何创建与仿真其余部分互不交互的开环(open-loop)轨迹。
角色(Actor)
Section titled “角色(Actor)”在 Gazebo Sim 中,动画模型被称为 角色 (actor)。
动画分为两种类型,可以单独使用,也可以组合使用:
- 骨骼动画(skeleton animation),即模型内各链接之间的相对运动:

- 轨迹动画(trajectory animation),即让 actor 的所有链接作为一个整体沿一条轨迹在世界中运动:

- 组合使用,实现一个在世界中移动的骨骼动画:

Actor 具有以下属性:
- 它们不受任何力的作用,无论是重力、接触力还是其他任何力
- Actor 支持从 COLLADA (.dae) 和 BVH (.bvh) 文件导入的骨骼动画。
- Actor 可以在 SDF 中直接编写轨迹脚本。
可在 此处 查看 <actor> SDF 元素的完整规范。
骨骼(Skeleton)
Section titled “骨骼(Skeleton)”Gazebo Sim 支持两种骨骼动画文件格式:COLLADA (.dae) 和 Biovision Hierarchy (.bvh)。
打开任意世界,例如 empty.sdf 世界,并按如下方式添加一个名为 actor_walking 的 actor:
<actor name="actor_walking"> <skin> <filename>https://fuel.gazebosim.org/1.0/Mingfei/models/actor/tip/files/meshes/walk.dae</filename> <scale>1.0</scale> </skin> <animation name="walk"> <filename>https://fuel.gazebosim.org/1.0/Mingfei/models/actor/tip/files/meshes/walk.dae</filename> <interpolate_x>true</interpolate_x> </animation></actor>皮肤(Skin)
Section titled “皮肤(Skin)”<skin> 标签中加载的 COLLADA 文件 walk.dae 指定了 actor 的外观。COLLADA 文件用于 <skin> 标签时,其动画也会一并加载。<scale> 用于缩放皮肤尺寸。
动画(Animation)
Section titled “动画(Animation)”在 <animation> 标签中,通过 <filename> 标签指定 actor 的运动方式。<interpolate_x> 用于在沿轨迹运动时在路点(waypoint)之间插值动画。设为 true 可获得更真实、更平滑的动画。只要骨骼兼容,即可将不同的皮肤与不同的动画组合。运行世界后,应能看到模型在移动。

注意:可在 Gazebo Fuel 上找到许多 actor 和模型。
脚本化轨迹(Scripted trajectory)
Section titled “脚本化轨迹(Scripted trajectory)”这是 actor 的顶层动画,需要指定一系列在特定时间到达的位姿(pose)。Gazebo Sim 负责在路点之间插值运动,使动作流畅。
在 X 轴上有位移的动画(如 walk.dae)会在沿轨迹运动时播放骨骼动画;但对于没有位移的动画(如 talk_b.dae),即使存在轨迹,骨骼也不会移动。
可以让 actor 永远跟随指定轨迹,并在世界加载后立即开始播放,如下所示:
<script> <loop>true</loop> <delay_start>0.000000</delay_start> <auto_start>true</auto_start>脚本定义在 <actor> 和 </actor> 标签之间。
在 <script> 标签内可以使用以下参数:
-
loop:设为 true 使脚本循环重复。为获得流畅连续的运动,请确保最后一个路点与第一个路点匹配(下文示例即如此)。 -
delay_start:脚本开始前等待的时间(以秒为单位)。如果循环运行,每个周期开始前都会等待这段时间。 -
auto_start:如果动画应在仿真开始播放时立即启动,则设为 true。例如,如果动画只应在插件触发时才播放,设为 false 会很有用。
接下来将轨迹定义为一连串路点:
<trajectory id="0" type="walk" tension="0.6"> <waypoint> <time>0</time> <pose>0 0 1.0 0 0 0</pose> </waypoint> <waypoint> <time>2</time> <pose>2.0 0 1.0 0 0 0</pose> </waypoint> <waypoint> <time>2.5</time> <pose>2 0 1.0 0 0 1.57</pose> </waypoint> <waypoint> <time>4</time> <pose>2 2 1.0 0 0 1.57</pose> </waypoint> <waypoint> <time>4.5</time> <pose>2 2 1.0 0 0 3.142</pose> </waypoint> <waypoint> <time>6</time> <pose>0 2 1 0 0 3.142</pose> </waypoint> <waypoint> <time>6.5</time> <pose>0 2 1 0 0 -1.57</pose> </waypoint> <waypoint> <time>8</time> <pose>0 0 1.0 0 0 -1.57</pose> </waypoint> <waypoint> <time>8.5</time> <pose>0 0 1.0 0 0 0</pose> </waypoint> </trajectory> </script>在 <trajectory> 标签内,定义了一系列 actor 要跟随的路点。<trajectory> 有三个属性:id、type 和 tension。type 应与 <animation> 标签 name 属性指定的值同名,因此本例中设为 walk。tension(张力)参数控制轨迹贴合路点的程度。默认 tension 值为 0,等同于 Catmull-Rom 样条(Catmull-Rom spline),可能导致动画越过路点。tension 值为 1 时动画严格贴合路点。该值应在 0 到 1 之间。
在 trajectory 标签下定义以下内容:
waypoint:一条轨迹中可以有任意数量的路点。每个路点由一个时间和一个位姿组成:time:到达该位姿的时间(以秒为单位),从脚本开始时起算。pose:相对于 actor 初始位姿应到达的位姿。
运行世界后,应能看到 actor 沿路点绕方形移动。

注意:
- 路点的定义顺序不影响执行,它们按给定的时间依次运行。
- 轨迹会作为整体进行平滑处理,因此运动很流畅,但不一定会精确经过路点中指定的位姿。
不妨尝试不同的轨迹描述,看看效果。
本教程的视频演示可在 YouTube 频道上观看:Gazebo 教程:动画人类角色