redid the global settings according to suggested guidelines

This commit is contained in:
Joan Llobera
2025-10-13 14:50:08 +02:00
parent cfd487c315
commit 655b961c89
+95 -53
View File
@@ -13,57 +13,59 @@
// limitations under the License. // limitations under the License.
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Xml; using System.Xml;
using UnityEngine; using UnityEngine;
using UnityEngine.Profiling;
namespace Mujoco { namespace Mujoco
{
// The MuJoCo parser is case-sensitive. The case format of the entries in the enums below is // The MuJoCo parser is case-sensitive. The case format of the entries in the enums below is
// exactly what the documentation specifies: http://mujoco.org/book/XMLreference.html#option . // exactly what the documentation specifies: http://mujoco.org/book/XMLreference.html#option .
public enum IntegratorType { public enum IntegratorType
{
Euler, Euler,
RK4, RK4,
@implicit, @implicit,
@implicitfast @implicitfast
} }
public enum FrictionConeType { public enum FrictionConeType
{
pyramidal, pyramidal,
elliptic elliptic
} }
public enum JacobianType { public enum JacobianType
{
dense, dense,
sparse, sparse,
auto auto
} }
public enum ConstraintSolverType { public enum ConstraintSolverType
{
PGS, PGS,
CG, CG,
Newton Newton
} }
public enum EnableDisableFlag { public enum EnableDisableFlag
{
enable, enable,
disable disable
} }
[Serializable] [Serializable]
public struct MjcfOptionFlag { public struct MjcfOptionFlag
{
public EnableDisableFlag Constraint; public EnableDisableFlag Constraint;
public EnableDisableFlag Equality; public EnableDisableFlag Equality;
public EnableDisableFlag FrictionLoss; public EnableDisableFlag FrictionLoss;
public EnableDisableFlag Limit; public EnableDisableFlag Limit;
public EnableDisableFlag Contact; public EnableDisableFlag Contact;
public EnableDisableFlag Passive; public EnableDisableFlag Spring;
public EnableDisableFlag Damper;
public EnableDisableFlag Gravity; public EnableDisableFlag Gravity;
public EnableDisableFlag ClampCtrl; public EnableDisableFlag ClampCtrl;
public EnableDisableFlag WarmStart; public EnableDisableFlag WarmStart;
@@ -74,13 +76,15 @@ public struct MjcfOptionFlag {
public EnableDisableFlag Energy; public EnableDisableFlag Energy;
public EnableDisableFlag FwdInv; public EnableDisableFlag FwdInv;
public EnableDisableFlag MultiCCD; public EnableDisableFlag MultiCCD;
public static MjcfOptionFlag Default = new MjcfOptionFlag() { public static MjcfOptionFlag Default = new MjcfOptionFlag()
{
Constraint = EnableDisableFlag.enable, Constraint = EnableDisableFlag.enable,
Equality = EnableDisableFlag.enable, Equality = EnableDisableFlag.enable,
FrictionLoss = EnableDisableFlag.enable, FrictionLoss = EnableDisableFlag.enable,
Limit = EnableDisableFlag.enable, Limit = EnableDisableFlag.enable,
Contact = EnableDisableFlag.enable, Contact = EnableDisableFlag.enable,
Passive = EnableDisableFlag.enable, Spring = EnableDisableFlag.enable,
Damper = EnableDisableFlag.enable,
Gravity = EnableDisableFlag.enable, Gravity = EnableDisableFlag.enable,
ClampCtrl = EnableDisableFlag.enable, ClampCtrl = EnableDisableFlag.enable,
WarmStart = EnableDisableFlag.enable, WarmStart = EnableDisableFlag.enable,
@@ -93,7 +97,8 @@ public struct MjcfOptionFlag {
MultiCCD = EnableDisableFlag.disable MultiCCD = EnableDisableFlag.disable
}; };
public void FromMjcf(XmlElement mjcf) { public void FromMjcf(XmlElement mjcf)
{
var localDefault = MjcfOptionFlag.Default; var localDefault = MjcfOptionFlag.Default;
Constraint = mjcf.GetEnumAttribute<EnableDisableFlag>("constraint", localDefault.Constraint); Constraint = mjcf.GetEnumAttribute<EnableDisableFlag>("constraint", localDefault.Constraint);
Equality = mjcf.GetEnumAttribute<EnableDisableFlag>("equality", localDefault.Equality); Equality = mjcf.GetEnumAttribute<EnableDisableFlag>("equality", localDefault.Equality);
@@ -101,7 +106,8 @@ public struct MjcfOptionFlag {
localDefault.FrictionLoss); localDefault.FrictionLoss);
Limit = mjcf.GetEnumAttribute<EnableDisableFlag>("limit", localDefault.Limit); Limit = mjcf.GetEnumAttribute<EnableDisableFlag>("limit", localDefault.Limit);
Contact = mjcf.GetEnumAttribute<EnableDisableFlag>("contact", localDefault.Contact); Contact = mjcf.GetEnumAttribute<EnableDisableFlag>("contact", localDefault.Contact);
Passive = mjcf.GetEnumAttribute<EnableDisableFlag>("passive", localDefault.Passive); Spring = mjcf.GetEnumAttribute<EnableDisableFlag>("spring", localDefault.Spring);
Damper = mjcf.GetEnumAttribute<EnableDisableFlag>("damper", localDefault.Damper);
Gravity = mjcf.GetEnumAttribute<EnableDisableFlag>("gravity", localDefault.Gravity); Gravity = mjcf.GetEnumAttribute<EnableDisableFlag>("gravity", localDefault.Gravity);
ClampCtrl = mjcf.GetEnumAttribute<EnableDisableFlag>("clampctrl", localDefault.ClampCtrl); ClampCtrl = mjcf.GetEnumAttribute<EnableDisableFlag>("clampctrl", localDefault.ClampCtrl);
WarmStart = mjcf.GetEnumAttribute<EnableDisableFlag>("warmstart", localDefault.WarmStart); WarmStart = mjcf.GetEnumAttribute<EnableDisableFlag>("warmstart", localDefault.WarmStart);
@@ -115,13 +121,15 @@ public struct MjcfOptionFlag {
MultiCCD = mjcf.GetEnumAttribute<EnableDisableFlag>("multiccd", localDefault.MultiCCD); MultiCCD = mjcf.GetEnumAttribute<EnableDisableFlag>("multiccd", localDefault.MultiCCD);
} }
public void ToMjcf(XmlElement mjcf) { public void ToMjcf(XmlElement mjcf)
{
mjcf.SetAttribute("constraint", Constraint.ToString()); mjcf.SetAttribute("constraint", Constraint.ToString());
mjcf.SetAttribute("equality", Equality.ToString()); mjcf.SetAttribute("equality", Equality.ToString());
mjcf.SetAttribute("frictionloss", FrictionLoss.ToString()); mjcf.SetAttribute("frictionloss", FrictionLoss.ToString());
mjcf.SetAttribute("limit", Limit.ToString()); mjcf.SetAttribute("limit", Limit.ToString());
mjcf.SetAttribute("contact", Contact.ToString()); mjcf.SetAttribute("contact", Contact.ToString());
// mjcf.SetAttribute("passive", Passive.ToString()); mjcf.SetAttribute("spring", Spring.ToString());
mjcf.SetAttribute("damper", Damper.ToString());
mjcf.SetAttribute("gravity", Gravity.ToString()); mjcf.SetAttribute("gravity", Gravity.ToString());
mjcf.SetAttribute("clampctrl", ClampCtrl.ToString()); mjcf.SetAttribute("clampctrl", ClampCtrl.ToString());
mjcf.SetAttribute("warmstart", WarmStart.ToString()); mjcf.SetAttribute("warmstart", WarmStart.ToString());
@@ -136,27 +144,31 @@ public struct MjcfOptionFlag {
} }
[Serializable] [Serializable]
public struct MjSizeStruct { public struct MjSizeStruct
{
public String Memory; public String Memory;
public static MjSizeStruct Default = new MjSizeStruct() { public static MjSizeStruct Default = new MjSizeStruct()
{
Memory = "-1" Memory = "-1"
}; };
public void ParseMjcf(XmlElement mjcf) { public void ParseMjcf(XmlElement mjcf)
{
Memory = mjcf.GetStringAttribute("memory", "-1"); Memory = mjcf.GetStringAttribute("memory", "-1");
} }
public XmlElement ToMjcf(XmlElement mjcf) { public XmlElement ToMjcf(XmlElement mjcf)
{
mjcf.SetAttribute("memory", $"{Memory}"); mjcf.SetAttribute("memory", $"{Memory}");
return mjcf; return mjcf;
} }
} }
[Serializable] [Serializable]
public struct MjOptionStruct { public struct MjOptionStruct
{
// "timestep" and "gravity" come from global settings. // "timestep" and "gravity" come from global settings.
// "apirate" is only relevant to HAPTIX.
[Tooltip("Ratio of frictional-to-normal constraint impedance.")] [Tooltip("Ratio of frictional-to-normal constraint impedance.")]
public float ImpRatio; public float ImpRatio;
[Tooltip("Global magnetic flux used by magnetometer sensors.")] [Tooltip("Global magnetic flux used by magnetometer sensors.")]
@@ -197,7 +209,8 @@ public struct MjOptionStruct {
public MjcfOptionFlag Flag; public MjcfOptionFlag Flag;
// Default values copied from the "XML reference" page in the MuJoCo documentation. // Default values copied from the "XML reference" page in the MuJoCo documentation.
public static MjOptionStruct Default = new MjOptionStruct() { public static MjOptionStruct Default = new MjOptionStruct()
{
ImpRatio = 1.0f, ImpRatio = 1.0f,
Magnetic = Vector3.zero, Magnetic = Vector3.zero,
Wind = new Vector3(0.0f, 0.0f, 0.0f), Wind = new Vector3(0.0f, 0.0f, 0.0f),
@@ -219,17 +232,21 @@ public struct MjOptionStruct {
Flag = MjcfOptionFlag.Default Flag = MjcfOptionFlag.Default
}; };
public void ParseMjcf(XmlElement mjcf) { public void ParseMjcf(XmlElement mjcf)
if (mjcf.HasAttribute("timestep")) { {
if (mjcf.HasAttribute("timestep"))
{
var mjTimestep = mjcf.GetFloatAttribute("timestep", Time.fixedDeltaTime); var mjTimestep = mjcf.GetFloatAttribute("timestep", Time.fixedDeltaTime);
if (mjTimestep != Time.fixedDeltaTime) { if (mjTimestep != Time.fixedDeltaTime)
{
Debug.unityLogger.LogWarning( Debug.unityLogger.LogWarning(
"MuJoCo", "MuJoCo",
$"MuJoCo's timestep ({mjTimestep}s) ignored, please set fixedDeltaTime manually.", $"MuJoCo's timestep ({mjTimestep}s) ignored, please set fixedDeltaTime manually.",
null); null);
} }
} }
if (mjcf.HasAttribute("gravity")) { if (mjcf.HasAttribute("gravity"))
{
var mjGravity = mjcf.GetVector3Attribute("gravity", Vector3.zero); var mjGravity = mjcf.GetVector3Attribute("gravity", Vector3.zero);
Debug.unityLogger.LogWarning( Debug.unityLogger.LogWarning(
"MuJoCo", "MuJoCo",
@@ -262,17 +279,22 @@ public struct MjOptionStruct {
CcdTolerance = mjcf.GetFloatAttribute("ccd_tolerance", localDefault.CcdTolerance); CcdTolerance = mjcf.GetFloatAttribute("ccd_tolerance", localDefault.CcdTolerance);
var flagElements = mjcf.GetElementsByTagName("flag"); var flagElements = mjcf.GetElementsByTagName("flag");
if (flagElements.Count == 1) { if (flagElements.Count == 1)
{
Flag.FromMjcf(flagElements[0] as XmlElement); Flag.FromMjcf(flagElements[0] as XmlElement);
} else if (flagElements.Count > 1) { }
else if (flagElements.Count > 1)
{
throw new ArgumentException("More than one <flag> node is not supported."); throw new ArgumentException("More than one <flag> node is not supported.");
} }
} }
public XmlElement ToMjcf(XmlElement mjcf) { public XmlElement ToMjcf(XmlElement mjcf)
{
mjcf.SetAttribute("impratio", MjEngineTool.MakeLocaleInvariant($"{ImpRatio}")); mjcf.SetAttribute("impratio", MjEngineTool.MakeLocaleInvariant($"{ImpRatio}"));
mjcf.SetAttribute("magnetic", MjEngineTool.MakeLocaleInvariant($"{Magnetic.x} {Magnetic.y} {Magnetic.z}")); mjcf.SetAttribute("magnetic",
MjEngineTool.MakeLocaleInvariant($"{Magnetic.x} {Magnetic.y} {Magnetic.z}"));
mjcf.SetAttribute("wind", MjEngineTool.MakeLocaleInvariant($"{Wind.x} {Wind.y} {Wind.z}")); mjcf.SetAttribute("wind", MjEngineTool.MakeLocaleInvariant($"{Wind.x} {Wind.y} {Wind.z}"));
mjcf.SetAttribute("density", MjEngineTool.MakeLocaleInvariant($"{Density}")); mjcf.SetAttribute("density", MjEngineTool.MakeLocaleInvariant($"{Density}"));
@@ -302,13 +324,15 @@ public struct MjOptionStruct {
} }
[Serializable] [Serializable]
public class NumericEntry { public class NumericEntry
{
public String Name; public String Name;
[Tooltip("Space-separated list of floats.")] [Tooltip("Space-separated list of floats.")]
public String Data; public String Data;
} }
public class MjGlobalSettings : MonoBehaviour { public class MjGlobalSettings : MonoBehaviour
{
[Tooltip("Filename for the generated scene XML.")] [Tooltip("Filename for the generated scene XML.")]
public string DebugFileName; public string DebugFileName;
@@ -325,14 +349,20 @@ public class MjGlobalSettings : MonoBehaviour {
public List<NumericEntry> CustomNumeric = new List<NumericEntry>() { }; public List<NumericEntry> CustomNumeric = new List<NumericEntry>() { };
public static MjGlobalSettings Instance { public static MjGlobalSettings Instance
get { {
if (_instance == null) { get
{
if (_instance == null)
{
var instances = FindObjectsOfType<MjGlobalSettings>(); var instances = FindObjectsOfType<MjGlobalSettings>();
if (instances.Length > 1) { if (instances.Length > 1)
{
throw new InvalidOperationException( throw new InvalidOperationException(
"Only one MjGlobalSettings instance is allowed - please resolve manually."); "Only one MjGlobalSettings instance is allowed - please resolve manually.");
} else if (instances.Length == 1) { }
else if (instances.Length == 1)
{
_instance = instances[0]; _instance = instances[0];
} }
} }
@@ -342,31 +372,41 @@ public class MjGlobalSettings : MonoBehaviour {
private static MjGlobalSettings _instance = null; private static MjGlobalSettings _instance = null;
public void Awake() { public void Awake()
if (_instance == null) { {
if (_instance == null)
{
_instance = this; _instance = this;
} else if (_instance != this) { }
else if (_instance != this)
{
throw new InvalidOperationException( throw new InvalidOperationException(
"At most one MjGlobalSettings should be present."); "At most one MjGlobalSettings should be present.");
} }
} }
public void ParseGlobalMjcfSections(XmlElement mujocoNode) { public void ParseGlobalMjcfSections(XmlElement mujocoNode)
{
var optionNode = mujocoNode.SelectSingleNode("option") as XmlElement; var optionNode = mujocoNode.SelectSingleNode("option") as XmlElement;
var sizeNode = mujocoNode.SelectSingleNode("size") as XmlElement; var sizeNode = mujocoNode.SelectSingleNode("size") as XmlElement;
var customNode = mujocoNode.SelectSingleNode("custom") as XmlElement; var customNode = mujocoNode.SelectSingleNode("custom") as XmlElement;
if (optionNode != null) { if (optionNode != null)
{
GlobalOptions.ParseMjcf(optionNode); GlobalOptions.ParseMjcf(optionNode);
} }
if (sizeNode != null) { if (sizeNode != null)
{
GlobalSizes.ParseMjcf(sizeNode); GlobalSizes.ParseMjcf(sizeNode);
} }
if (customNode != null) { if (customNode != null)
foreach (var childNode in customNode.ChildNodes) { {
foreach (var childNode in customNode.ChildNodes)
{
var child = childNode as XmlElement; var child = childNode as XmlElement;
if (child.Name == "numeric") { if (child.Name == "numeric")
{
var numeric = new NumericEntry(); var numeric = new NumericEntry();
numeric.Name = child.GetAttribute("name"); numeric.Name = child.GetAttribute("name");
numeric.Data = child.GetAttribute("data"); numeric.Data = child.GetAttribute("data");
@@ -376,14 +416,16 @@ public class MjGlobalSettings : MonoBehaviour {
} }
} }
public void GlobalsToMjcf(XmlElement mjcf) { public void GlobalsToMjcf(XmlElement mjcf)
{
var doc = mjcf.OwnerDocument; var doc = mjcf.OwnerDocument;
var optionMjcf = (XmlElement)mjcf.AppendChild(doc.CreateElement("option")); var optionMjcf = (XmlElement)mjcf.AppendChild(doc.CreateElement("option"));
GlobalOptions.ToMjcf(optionMjcf); GlobalOptions.ToMjcf(optionMjcf);
var sizeMjcf = (XmlElement)mjcf.AppendChild(doc.CreateElement("size")); var sizeMjcf = (XmlElement)mjcf.AppendChild(doc.CreateElement("size"));
GlobalSizes.ToMjcf(sizeMjcf); GlobalSizes.ToMjcf(sizeMjcf);
var customMjcf = (XmlElement)mjcf.AppendChild(doc.CreateElement("custom")); var customMjcf = (XmlElement)mjcf.AppendChild(doc.CreateElement("custom"));
foreach (var numeric in CustomNumeric) { foreach (var numeric in CustomNumeric)
{
var numericMjcf = (XmlElement)customMjcf.AppendChild(doc.CreateElement("numeric")); var numericMjcf = (XmlElement)customMjcf.AppendChild(doc.CreateElement("numeric"));
numericMjcf.SetAttribute("name", numeric.Name); numericMjcf.SetAttribute("name", numeric.Name);
// TODO: add validation that data is a space-separated list of floating numbers? // TODO: add validation that data is a space-separated list of floating numbers?