File: MjActuator.cs

package info (click to toggle)
mujoco 2.2.2-3.2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 39,796 kB
  • sloc: ansic: 28,947; cpp: 28,897; cs: 14,241; python: 10,465; xml: 5,104; sh: 93; makefile: 34
file content (394 lines) | stat: -rw-r--r-- 16,147 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using UnityEngine;

namespace Mujoco {
// Actuators provide means to set joints in motion.
public class MjActuator : MjComponent {

  public enum ActuatorType {
    General,
    Motor,
    Position,
    Velocity,
    Cylinder,
    Muscle
  }

  // This structure holds the parameters shared by all types of actuators.
  //
  // All constants found in this class are copied from the official documentation, and can be found
  // here: http://mujoco.org/book/XMLreference.html#actuator
  [Serializable]
  public class CommonParameters {

    // If true, the control input to this actuator is automatically clamped to ctrlrange at runtime.
    // If false, control input clamping is disabled.
    public bool CtrlLimited;

    // If true, the force output of this actuator is automatically clamped to forcerange at runtime.
    // If false, force output clamping is disabled.
    public bool ForceLimited;

    // Range for clamping the control input.
    public Vector2 CtrlRange;

    // Range for clamping the force output.
    public Vector2 ForceRange;

    // Range of feasible lengths of the actuator's transmission.
    public Vector2 LengthRange;

    // This attribute scales the length (and consequently moment arms, velocity and force) of the
    // actuator, for all transmission types. It is different from the gain in the force generation
    // mechanism, because the gain only scales the force output and does not affect the length,
    // moment arms and velocity.
    public List<float> Gear = new List<float>() { 1.0f };

    public void ToMjcf(XmlElement mjcf) {
      mjcf.SetAttribute("ctrllimited", $"{CtrlLimited}".ToLowerInvariant());
      mjcf.SetAttribute("forcelimited", $"{ForceLimited}".ToLowerInvariant());
      mjcf.SetAttribute(
          "ctrlrange",
          MjEngineTool.MakeLocaleInvariant($"{MjEngineTool.GetSorted(CtrlRange).x} {MjEngineTool.GetSorted(CtrlRange).y}"));
      mjcf.SetAttribute(
          "forcerange",
          MjEngineTool.MakeLocaleInvariant($"{MjEngineTool.GetSorted(ForceRange).x} {MjEngineTool.GetSorted(ForceRange).y}"));
      mjcf.SetAttribute(
          "lengthrange",
          MjEngineTool.MakeLocaleInvariant($"{MjEngineTool.GetSorted(LengthRange).x} {MjEngineTool.GetSorted(LengthRange).y}"));
      mjcf.SetAttribute("gear", MjEngineTool.ListToMjcf(Gear));
    }

    public void FromMjcf(XmlElement mjcf) {
      CtrlLimited = mjcf.GetBoolAttribute("ctrllimited", defaultValue: false);
      ForceLimited = mjcf.GetBoolAttribute("forcelimited", defaultValue: false);
      CtrlRange = mjcf.GetVector2Attribute("ctrlrange", defaultValue: Vector2.zero);
      ForceRange = mjcf.GetVector2Attribute("forcerange", defaultValue: Vector2.zero);
      LengthRange = mjcf.GetVector2Attribute("lengthrange", defaultValue: Vector2.zero);
      Gear = mjcf.GetFloatArrayAttribute("gear", defaultValue: new float[] { 1.0f }).ToList();
    }
  }

  // This structure holds all parameters unique to each type of the actuator.
  //
  // Because UnityEditor doesn't handle polymorphism well, I decided to put all parameters here
  // and then create a custom editor (MjActuatorEditor), that will display only the values
  // relevant to the selected articulation type. The choice will be made based on the value of
  // the 'Type' field.
  //
  // All constants found in this class are copied from the official documentation, and can be found
  // here: http://mujoco.org/book/XMLreference.html#actuator
  [Serializable]
  public class CustomParameters {

    //// General actuator parameters.

    // Activation dynamics type for the actuator.
    public MujocoLib.mjtDyn DynType;

    // The gain and bias together determine the output of the force generation mechanism, which is
    // currently assumed to be affine. As already explained in Actuation model, the general formula
    // is:
    //   scalar_force = gain_term * (act or ctrl) + bias_term.
    // The formula uses the activation state when present, and the control otherwise.
    public MujocoLib.mjtGain GainType;

    // Bias type.
    public MujocoLib.mjtBias BiasType;

    // Activation dynamics parameters. The built-in activation types (except for muscle) use only
    // the first parameter, but we provide additional parameters in case user callbacks implement a
    // more elaborate model. The length of this array is not enforced by the parser, so the user can
    // enter as many parameters as needed.
    public List<float> DynPrm = new List<float>() { 1.0f, 0.0f, 0.0f };

    // Gain parameters. The built-in gain types (except for muscle) use only the first parameter,
    // but we provide additional parameters in case user callbacks implement a more elaborate model.
    // The length of this array is not enforced by the parser, so the user can enter as many
    // parameters as needed.
    public List<float> GainPrm = new List<float>() { 1.0f, 0.0f, 0.0f };

    // Bias parameters. The affine bias type uses three parameters. The length of this array is not
    // enforced by the parser, so the user can enter as many parameters as needed.
    public List<float> BiasPrm = new List<float>() { 0.0f, 0.0f, 0.0f };

    public void GeneralToMjcf(XmlElement mjcf) {
      mjcf.SetAttribute("dyntype", $"{DynType}".Substring(6).ToLowerInvariant());
      mjcf.SetAttribute("gaintype", $"{GainType}".Substring(7).ToLowerInvariant());
      mjcf.SetAttribute("biastype", $"{BiasType}".Substring(7).ToLowerInvariant());
      mjcf.SetAttribute("dynprm", MjEngineTool.ListToMjcf(DynPrm));
      mjcf.SetAttribute("gainprm", MjEngineTool.ListToMjcf(GainPrm));
      mjcf.SetAttribute("biasprm", MjEngineTool.ListToMjcf(BiasPrm));
    }

    public void GeneralFromMjcf(XmlElement mjcf) {
      var dynTypeStr = mjcf.GetStringAttribute("dyntype", defaultValue: "none");
      var gainTypeStr = mjcf.GetStringAttribute("gaintype", defaultValue: "fixed");
      var biasTypeStr = mjcf.GetStringAttribute("biastype", defaultValue: "none");
      var ignoreCase = true;
      Enum.TryParse<MujocoLib.mjtDyn>($"mjdyn_{dynTypeStr}", ignoreCase, out DynType);
      Enum.TryParse<MujocoLib.mjtGain>($"mjgain_{gainTypeStr}", ignoreCase, out GainType);
      Enum.TryParse<MujocoLib.mjtBias>($"mjbias_{biasTypeStr}", ignoreCase, out BiasType);

      DynPrm = mjcf.GetFloatArrayAttribute(
        "dynprm", defaultValue: new float[] { 1.0f, 0.0f, 0.0f }).ToList();
      GainPrm = mjcf.GetFloatArrayAttribute(
        "gainprm", defaultValue: new float[] { 1.0f, 0.0f, 0.0f }).ToList();
      BiasPrm = mjcf.GetFloatArrayAttribute(
        "biasprm", defaultValue: new float[] { 0.0f, 0.0f, 0.0f }).ToList();
    }

    //// Position actuator parameters.

    // Position feedback gain.
    [AbsoluteValue]
    public float Kp = 1.0f;

    public void PositionToMjcf(XmlElement mjcf) {
      mjcf.SetAttribute("kp", MjEngineTool.MakeLocaleInvariant($"{Math.Abs(Kp)}"));
    }
    public void PositionFromMjcf(XmlElement mjcf) {
      Kp = mjcf.GetFloatAttribute("kp", defaultValue: 1.0f);
    }

    //// Velocity actuator parameters.

    // Velocity feedback gain.
    [AbsoluteValue]
    public float Kv = 1.0f;

    public void VelocityToMjcf(XmlElement mjcf) {
      mjcf.SetAttribute("kv", MjEngineTool.MakeLocaleInvariant($"{Math.Abs(Kv)}"));
    }
    public void VelocityFromMjcf(XmlElement mjcf) {
      Kv = mjcf.GetFloatAttribute("kv", defaultValue: 1.0f);
    }

    //// Cylinder actuator parameters.

    // Time constant of the activation dynamics.
    public float CylinderTimeConst = 1.0f;

    // Area of the cylinder. This is used internally as actuator gain.
    [AbsoluteValue]
    public float Area = 1.0f;

    // Instead of area the user can specify diameter. If both are specified, diameter has
    // precedence.
    [AbsoluteValue]
    public float Diameter = 0.0f;

    // Bias parameters, copied internally into biasprm.
    public float[] Bias = new float[] { 0.0f, 0.0f, 0.0f };

    public void CylinderToMjcf(XmlElement mjcf) {
      mjcf.SetAttribute("timeconst", MjEngineTool.MakeLocaleInvariant($"{CylinderTimeConst}"));
      mjcf.SetAttribute("area", MjEngineTool.MakeLocaleInvariant($"{Math.Abs(Area)}"));
      mjcf.SetAttribute("diameter", MjEngineTool.MakeLocaleInvariant($"{Math.Abs(Diameter)}"));
      mjcf.SetAttribute("bias", MjEngineTool.ArrayToMjcf(Bias));
    }

    public void CylinderFromMjcf(XmlElement mjcf) {
      CylinderTimeConst = mjcf.GetFloatAttribute("timeconst", defaultValue: 1.0f);
      Area = mjcf.GetFloatAttribute("area", defaultValue: 1.0f);
      Diameter = mjcf.GetFloatAttribute("diameter", defaultValue: 0.0f);
      Bias = mjcf.GetFloatArrayAttribute("bias", defaultValue: new float[] { 0.0f, 0.0f, 0.0f });
    }

    //// Muscle actuator parameters.

    // Time constants for activation and de-activation dynamics.
    public Vector2 MuscleTimeConst = new Vector2(0.01f, 0.04f);

    // Operating length range of the muscle, in units of L0.
    public Vector2 Range = new Vector2(0.75f, 1.05f);

    // Peak active force at rest. If this value is negative, the peak force is determined
    // automatically using the scale attribute below.
    public float Force = -1.0f;

    // If the force attribute is negative, the peak active force for the muscle is set to this value
    // divided by mjModel.actuator_acc0. The latter is the norm of the joint-space acceleration
    // vector caused by unit force on the actuator's transmission in qpos0. In other words, scaling
    // produces higher peak forces for muscles that pull more weight.
    public float Scale = 200.0f;

    // Lower position range of the normalized FLV curve, in units of L0.
    public float LMin = 0.5f;

    // Upper position range of the normalized FLV curve, in units of L0.
    public float LMax = 1.6f;

    // Shortening velocity at which muscle force drops to zero, in units of L0 per second.
    public float VMax = 1.5f;

    // Passive force generated at lmax, relative to the peak rest force.
    public float FpMax = 1.3f;

    // Active force generated at saturating lengthening velocity, relative to the peak rest force.
    public float FvMax = 1.2f;

    public void MuscleToMjcf(XmlElement mjcf) {
      mjcf.SetAttribute("timeconst", MjEngineTool.MakeLocaleInvariant($"{MuscleTimeConst[0]} {MuscleTimeConst[1]}"));
      mjcf.SetAttribute(
        "range", MjEngineTool.MakeLocaleInvariant($"{MjEngineTool.GetSorted(Range).x} {MjEngineTool.GetSorted(Range).y}"));
      mjcf.SetAttribute("force", MjEngineTool.MakeLocaleInvariant($"{Force}"));
      mjcf.SetAttribute("scale", MjEngineTool.MakeLocaleInvariant($"{Scale}"));
      mjcf.SetAttribute("lmin", MjEngineTool.MakeLocaleInvariant($"{LMin}"));
      mjcf.SetAttribute("lmax", MjEngineTool.MakeLocaleInvariant($"{LMax}"));
      mjcf.SetAttribute("vmax", MjEngineTool.MakeLocaleInvariant($"{VMax}"));
      mjcf.SetAttribute("fpmax", MjEngineTool.MakeLocaleInvariant($"{FpMax}"));
      mjcf.SetAttribute("fvmax", MjEngineTool.MakeLocaleInvariant($"{FvMax}"));
    }

    public void MuscleFromMjcf(XmlElement mjcf) {
      MuscleTimeConst = mjcf.GetVector2Attribute(
          "timeconst", defaultValue: new Vector2(0.01f, 0.04f));
      Range = mjcf.GetVector2Attribute("range", defaultValue: new Vector2(0.75f, 1.05f));
      Force = mjcf.GetFloatAttribute("force", defaultValue: -1.0f);
      Scale = mjcf.GetFloatAttribute("scale", defaultValue: 200.0f);
      LMin = mjcf.GetFloatAttribute("lmin", defaultValue: 0.5f);
      LMax = mjcf.GetFloatAttribute("lmax", defaultValue: 1.6f);
      VMax = mjcf.GetFloatAttribute("vmax", defaultValue: 1.5f);
      FpMax = mjcf.GetFloatAttribute("fpmax", defaultValue: 1.3f);
      FvMax = mjcf.GetFloatAttribute("fvmax", defaultValue: 1.2f);
    }
  }

  public ActuatorType Type;

  [Tooltip("Joint actuation target. Mutually exclusive with tendon target.")]
  public MjBaseJoint Joint;

  [Tooltip("Tendon actuation target. Mutually exclusive with joint target.")]
  public MjBaseTendon Tendon;

  [Tooltip("Parameters specific to each actuator type.")]
  [HideInInspector]
  public CustomParameters CustomParams = new CustomParameters();

  [Tooltip("Parameters shared by all types of actuators.")]
  public CommonParameters CommonParams = new CommonParameters();

  [Tooltip("Actuator control.")]
  public float Control;

  // Actuator length.
  public float Length { get; private set; }

  // Actuator velocity.
  public float Velocity { get; private set; }

  // Actuator force.
  public float Force { get; private set; }

  public override MujocoLib.mjtObj ObjectType => MujocoLib.mjtObj.mjOBJ_ACTUATOR;

  // Parse the component settings from an external Mjcf.
  protected override void OnParseMjcf(XmlElement mjcf) {
    if (!Enum.TryParse(mjcf.Name, ignoreCase: true, result: out Type)) {
      throw new ArgumentException($"Unknown actuator type {mjcf.Name}.");
    }
    CommonParams.FromMjcf(mjcf);
    switch (Type) {
      case MjActuator.ActuatorType.General: {
        CustomParams.GeneralFromMjcf(mjcf);
        break;
      }
      case MjActuator.ActuatorType.Position: {
        CustomParams.PositionFromMjcf(mjcf);
        break;
      }
      case MjActuator.ActuatorType.Velocity: {
        CustomParams.VelocityFromMjcf(mjcf);
        break;
      }
      case MjActuator.ActuatorType.Cylinder: {
        CustomParams.CylinderFromMjcf(mjcf);
        break;
      }
      case MjActuator.ActuatorType.Muscle: {
        CustomParams.MuscleFromMjcf(mjcf);
        break;
      }
    }
    Joint = mjcf.GetObjectReferenceAttribute<MjBaseJoint>("joint");
    Tendon = mjcf.GetObjectReferenceAttribute<MjBaseTendon>("tendon");
  }

  // Generate implementation specific XML element.
  protected override XmlElement OnGenerateMjcf(XmlDocument doc) {
    if (Joint == null && Tendon == null) {
      throw new InvalidOperationException($"Actuator {name} is not assigned a joint nor tendon.");
    }
    if (Joint != null && Tendon != null) {
      throw new InvalidOperationException(
        $"Actuator {name} can't have both a tendon and a joint target.");
    }

    var mjcf = doc.CreateElement(Type.ToString().ToLowerInvariant());
    if (Joint != null) {
      mjcf.SetAttribute("joint", Joint.MujocoName);
    } else {
      mjcf.SetAttribute("tendon", Tendon.MujocoName);
    }
    CommonParams.ToMjcf(mjcf);

    switch (Type) {
      case MjActuator.ActuatorType.General: {
        CustomParams.GeneralToMjcf(mjcf);
        break;
      }
      case MjActuator.ActuatorType.Position: {
        CustomParams.PositionToMjcf(mjcf);
        break;
      }
      case MjActuator.ActuatorType.Velocity: {
        CustomParams.VelocityToMjcf(mjcf);
        break;
      }
      case MjActuator.ActuatorType.Cylinder: {
        CustomParams.CylinderToMjcf(mjcf);
        break;
      }
      case MjActuator.ActuatorType.Muscle: {
        CustomParams.MuscleToMjcf(mjcf);
        break;
      }
    }
    return mjcf;
  }

  // Synchronize the state of the component.
  public override unsafe void OnSyncState(MujocoLib.mjData_* data) {
    data->ctrl[MujocoId] = Control;
    Length = (float)data->actuator_length[MujocoId];
    Velocity = (float)data->actuator_velocity[MujocoId];
    Force = (float)data->actuator_force[MujocoId];
  }

  public void OnValidate() {
    if (Joint != null && Tendon != null) {
      Debug.LogError(
          $"Actuator {name} can't have both a tendon and a joint target.", this);
    }
  }
}
}