diff --git a/build.ps1 b/build.ps1 index aa68889..0cf4480 100644 --- a/build.ps1 +++ b/build.ps1 @@ -43,18 +43,17 @@ if($standalone) { & "$scriptPath\src\ros2cs\build.ps1" @options if($?) { - md -Force $scriptPath\install\asset | Out-Null - Copy-Item -Path $scriptPath\src\Ros2ForUnity -Destination $scriptPath\install\asset\ -Recurse -Force + md -Force $scriptPath\install\package | Out-Null + Copy-Item -Path $scriptPath\src\Ros2ForUnity -Destination $scriptPath\install\package\ -Recurse -Force - $plugin_path=Join-Path -Path $scriptPath -ChildPath "\install\asset\Ros2ForUnity\Plugins\" + $plugin_path=Join-Path -Path $scriptPath -ChildPath "\install\package\Ros2ForUnity\Runtime\Plugins\" Write-Host "Deploying build to $plugin_path" -ForegroundColor Green & "$scriptPath\deploy_unity_plugins.ps1" $plugin_path - Copy-Item -Path $scriptPath\src\Ros2ForUnity\metadata_ros2cs.xml -Destination $scriptPath\install\asset\Ros2ForUnity\Plugins\Windows\x86_64\ - Copy-Item -Path $scriptPath\src\Ros2ForUnity\metadata_ros2cs.xml -Destination $scriptPath\install\asset\Ros2ForUnity\Plugins\ + Copy-Item -Path $scriptPath\src\Ros2ForUnity\Runtime\metadata_ros2cs.xml -Destination $scriptPath\install\package\Ros2ForUnity\Runtime\Plugins\Windows\x86_64\ + Copy-Item -Path $scriptPath\src\Ros2ForUnity\Runtime\metadata_ros2cs.xml -Destination $scriptPath\install\package\Ros2ForUnity\Runtime\Plugins\ + Copy-Item -Path $scriptPath\README.md -Destination $scriptPath\install\package\Ros2ForUnity\ } else { Write-Host "Ros2cs build failed!" -ForegroundColor Red exit 1 } - - diff --git a/src/Ros2ForUnity/Runtime.meta b/src/Ros2ForUnity/Runtime.meta new file mode 100644 index 0000000..13c9309 --- /dev/null +++ b/src/Ros2ForUnity/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 13a1b243ce6b36e4196ef79619f7b40a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Ros2ForUnity/Plugins.meta b/src/Ros2ForUnity/Runtime/Plugins.meta similarity index 77% rename from src/Ros2ForUnity/Plugins.meta rename to src/Ros2ForUnity/Runtime/Plugins.meta index f77a550..aa81df9 100644 --- a/src/Ros2ForUnity/Plugins.meta +++ b/src/Ros2ForUnity/Runtime/Plugins.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 79b46a636d96b67468a29e597cb7b06a +guid: 131987f734e4d9f439acfef5ccb677c0 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/src/Ros2ForUnity/Plugins/.gitkeep b/src/Ros2ForUnity/Runtime/Plugins/.gitkeep similarity index 100% rename from src/Ros2ForUnity/Plugins/.gitkeep rename to src/Ros2ForUnity/Runtime/Plugins/.gitkeep diff --git a/src/Ros2ForUnity/Scripts.meta b/src/Ros2ForUnity/Runtime/Scripts.meta similarity index 77% rename from src/Ros2ForUnity/Scripts.meta rename to src/Ros2ForUnity/Runtime/Scripts.meta index fb3bbc9..fd068c8 100644 --- a/src/Ros2ForUnity/Scripts.meta +++ b/src/Ros2ForUnity/Runtime/Scripts.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: f750980d49c8bcf39830e89365689d16 +guid: e0bf4f692fdb2bb44aed07a15bc7b16c folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/src/Ros2ForUnity/Scripts/PostInstall.cs b/src/Ros2ForUnity/Runtime/Scripts/PostInstall.cs similarity index 69% rename from src/Ros2ForUnity/Scripts/PostInstall.cs rename to src/Ros2ForUnity/Runtime/Scripts/PostInstall.cs index 2f4dd03..55f0879 100644 --- a/src/Ros2ForUnity/Scripts/PostInstall.cs +++ b/src/Ros2ForUnity/Runtime/Scripts/PostInstall.cs @@ -33,20 +33,24 @@ public void OnPostprocessBuild(BuildReport report) var r2fuMetadataName = "metadata_ros2_for_unity.xml"; var r2csMetadataName = "metadata_ros2cs.xml"; - // FileUtil.CopyFileOrDirectory: All file separators should be forward ones "/". - var r2fuMeta = ROS2ForUnity.GetRos2ForUnityPath() + "/" + r2fuMetadataName; - var r2csMeta = ROS2ForUnity.GetPluginPath() + "/" + r2csMetadataName; - var outputDir = Directory.GetParent(report.summary.outputPath); + var r2fuMeta = Path.Combine(ROS2ForUnity.rootPath, r2fuMetadataName); + var r2csMeta = Path.Combine(ROS2ForUnity.pluginPath, r2csMetadataName); + + var outputDir = Directory.GetParent(report.summary.outputPath).ToString(); var execFilename = Path.GetFileNameWithoutExtension(report.summary.outputPath); + FileUtil.CopyFileOrDirectory( - r2fuMeta, outputDir + "/" + execFilename + "_Data/" + r2fuMetadataName); + r2fuMeta, Path.Combine(outputDir, execFilename + "_Data", r2fuMetadataName) + ); + + string r2csMetaTarget; if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneLinux64) { - FileUtil.CopyFileOrDirectory( - r2csMeta, outputDir + "/" + execFilename + "_Data/Plugins/" + r2csMetadataName); + r2csMetaTarget = Path.Combine(outputDir, execFilename + "_Data", "Plugins", r2csMetadataName); } else { - FileUtil.CopyFileOrDirectory( - r2csMeta, outputDir + "/" + execFilename + "_Data/Plugins/x86_64/" + r2csMetadataName); + r2csMetaTarget = Path.Combine(outputDir, execFilename + "_Data", "Plugins", "x86_64", r2csMetadataName); } + + FileUtil.CopyFileOrDirectory(r2csMeta, r2csMetaTarget); } } diff --git a/src/Ros2ForUnity/Runtime/Scripts/PostInstall.cs.meta b/src/Ros2ForUnity/Runtime/Scripts/PostInstall.cs.meta new file mode 100644 index 0000000..fc5a57f --- /dev/null +++ b/src/Ros2ForUnity/Runtime/Scripts/PostInstall.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 58c6e966dff4d9f49b70ece3620a65ab +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Ros2ForUnity/Scripts/ROS2ClientExample.cs b/src/Ros2ForUnity/Runtime/Scripts/ROS2ClientExample.cs similarity index 100% rename from src/Ros2ForUnity/Scripts/ROS2ClientExample.cs rename to src/Ros2ForUnity/Runtime/Scripts/ROS2ClientExample.cs diff --git a/src/Ros2ForUnity/Runtime/Scripts/ROS2ClientExample.cs.meta b/src/Ros2ForUnity/Runtime/Scripts/ROS2ClientExample.cs.meta new file mode 100644 index 0000000..365ebbf --- /dev/null +++ b/src/Ros2ForUnity/Runtime/Scripts/ROS2ClientExample.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bbecdb758cb91d74585785bc4ed52555 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Ros2ForUnity/Scripts/ROS2ForUnity.cs b/src/Ros2ForUnity/Runtime/Scripts/ROS2ForUnity.cs similarity index 84% rename from src/Ros2ForUnity/Scripts/ROS2ForUnity.cs rename to src/Ros2ForUnity/Runtime/Scripts/ROS2ForUnity.cs index 4ba7cfd..999356c 100644 --- a/src/Ros2ForUnity/Scripts/ROS2ForUnity.cs +++ b/src/Ros2ForUnity/Runtime/Scripts/ROS2ForUnity.cs @@ -1,372 +1,357 @@ -// Copyright 2019-2021 Robotec.ai. -// -// 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.IO; -using System.Collections.Generic; -using UnityEngine; -using UnityEditor; -using System.Xml; - -namespace ROS2 -{ - -/// -/// An internal class responsible for handling checking, proper initialization and shutdown of ROS2cs, -/// -internal class ROS2ForUnity -{ - private static bool isInitialized = false; - private static string ros2ForUnityAssetFolderName = "Ros2ForUnity"; - private XmlDocument ros2csMetadata = new XmlDocument(); - private XmlDocument ros2ForUnityMetadata = new XmlDocument(); - - public enum Platform - { - Windows, - Linux - } - - public static Platform GetOS() - { - if (Application.platform == RuntimePlatform.LinuxEditor || Application.platform == RuntimePlatform.LinuxPlayer) - { - return Platform.Linux; - } - else if (Application.platform == RuntimePlatform.WindowsEditor || Application.platform == RuntimePlatform.WindowsPlayer) - { - return Platform.Windows; - } - throw new System.NotSupportedException("Only Linux and Windows are supported"); - } - - private static bool InEditor() { - return Application.isEditor; - } - - private static string GetOSName() - { - switch (GetOS()) - { - case Platform.Linux: - return "Linux"; - case Platform.Windows: - return "Windows"; - default: - throw new System.NotSupportedException("Only Linux and Windows are supported"); - } - } - - private string GetEnvPathVariableName() - { - string envVariable = "LD_LIBRARY_PATH"; - if (GetOS() == Platform.Windows) - { - envVariable = "PATH"; - } - return envVariable; - } - - private string GetEnvPathVariableValue() - { - return Environment.GetEnvironmentVariable(GetEnvPathVariableName()); - } - - public static string GetRos2ForUnityPath() - { - char separator = Path.DirectorySeparatorChar; - string appDataPath = Application.dataPath; - string pluginPath = appDataPath; - - if (InEditor()) { - pluginPath += separator + ros2ForUnityAssetFolderName; - } - return pluginPath; - } - - public static string GetPluginPath() - { - char separator = Path.DirectorySeparatorChar; - string ros2ForUnityPath = GetRos2ForUnityPath(); - string pluginPath = ros2ForUnityPath; - - pluginPath += separator + "Plugins"; - - if (InEditor()) { - pluginPath += separator + GetOSName(); - } - - if (InEditor() || GetOS() == Platform.Windows) - { - pluginPath += separator + "x86_64"; - } - - if (GetOS() == Platform.Windows) - { - pluginPath = pluginPath.Replace("/", "\\"); - } - - return pluginPath; - } - - /// - /// Function responsible for setting up of environment paths for standalone builds - /// - /// - /// Note that on Linux, LD_LIBRARY_PATH as used for dlopen() is determined on process start and this change won't - /// affect it. Ros2 looks for rmw implementation based on this variable (independently) and the change - /// is effective for this process, however rmw implementation's dependencies itself are loaded by dynamic linker - /// anyway so setting it for Linux is pointless. - /// - private void SetEnvPathVariable() - { - string currentPath = GetEnvPathVariableValue(); - string pluginPath = GetPluginPath(); - - char envPathSep = ':'; - if (GetOS() == Platform.Windows) - { - envPathSep = ';'; - } - - Environment.SetEnvironmentVariable(GetEnvPathVariableName(), pluginPath + envPathSep + currentPath); - } - - public bool IsStandalone() { - return Convert.ToBoolean(Convert.ToInt16(GetMetadataValue(ros2csMetadata, "/ros2cs/standalone"))); - } - - public string GetROSVersion() - { - string ros2SourcedCodename = GetROSVersionSourced(); - string ros2FromRos4UMetadata = GetMetadataValue(ros2ForUnityMetadata, "/ros2_for_unity/ros2"); - - // Sourced ROS2 libs takes priority - if (string.IsNullOrEmpty(ros2SourcedCodename)) { - return ros2FromRos4UMetadata; - } - - return ros2SourcedCodename; - } - - /// - /// Checks if both ros2cs and ros2-for-unity were build for the same ros version as well as - /// the current sourced ros version matches ros2cs binaries. - /// - public void CheckIntegrity() - { - string ros2SourcedCodename = GetROSVersionSourced(); - string ros2FromRos2csMetadata = GetMetadataValue(ros2csMetadata, "/ros2cs/ros2"); - string ros2FromRos4UMetadata = GetMetadataValue(ros2ForUnityMetadata, "/ros2_for_unity/ros2"); - - if (ros2FromRos4UMetadata != ros2FromRos2csMetadata) { - Debug.LogError( - "ROS2 versions in 'ros2cs' and 'ros2-for-unity' metadata files are not the same. " + - "This is caused by mixing versions/builds. Plugin might not work correctly." - ); - } - - if(!IsStandalone() && ros2SourcedCodename != ros2FromRos2csMetadata) { - Debug.LogError( - "ROS2 version in 'ros2cs' metadata doesn't match currently sourced version. " + - "This is caused by mixing versions/builds. Plugin might not work correctly." - ); - } - - if (IsStandalone() && !string.IsNullOrEmpty(ros2SourcedCodename)) { - Debug.LogError( - "You should not source ROS2 in 'ros2-for-unity' standalone build. " + - "Plugin might not work correctly." - ); - } - } - - public string GetROSVersionSourced() - { - return Environment.GetEnvironmentVariable("ROS_DISTRO"); - } - - /// - /// Check if the ros version is supported, only applicable to non-standalone plugin versions - /// (i. e. without ros2 libraries included in the plugin). - /// - private void CheckROSSupport(string ros2Codename) - { - List supportedVersions = new List() { "foxy", "galactic", "humble", "rolling" }; - var supportedVersionsString = String.Join(", ", supportedVersions); - if (string.IsNullOrEmpty(ros2Codename)) - { - string errMessage = "No ROS environment sourced. You need to source your ROS2 " + supportedVersionsString - + " environment before launching Unity (ROS_DISTRO env variable not found)"; - Debug.LogError(errMessage); -#if UNITY_EDITOR - EditorApplication.isPlaying = false; - throw new System.InvalidOperationException(errMessage); -#else - const int ROS_NOT_SOURCED_ERROR_CODE = 33; - Application.Quit(ROS_NOT_SOURCED_ERROR_CODE); -#endif - } - - if (!supportedVersions.Contains(ros2Codename)) - { - string errMessage = "Currently sourced ROS version differs from supported one. Sourced: " + ros2Codename - + ", supported: " + supportedVersionsString + "."; - Debug.LogError(errMessage); -#if UNITY_EDITOR - EditorApplication.isPlaying = false; - throw new System.NotSupportedException(errMessage); -#else - const int ROS_BAD_VERSION_CODE = 34; - Application.Quit(ROS_BAD_VERSION_CODE); -#endif - } else if (ros2Codename.Equals("rolling") ) { - Debug.LogWarning("You are using ROS2 rolling version. Bleeding edge version might not work correctly."); - } - } - - private void RegisterCtrlCHandler() - { -#if ENABLE_MONO - // Il2CPP build does not support Console.CancelKeyPress currently - Console.CancelKeyPress += (sender, eventArgs) => { - eventArgs.Cancel = true; - DestroyROS2ForUnity(); - }; -#endif - } - - private void ConnectLoggers() - { - Ros2csLogger.setCallback(LogLevel.ERROR, Debug.LogError); - Ros2csLogger.setCallback(LogLevel.WARNING, Debug.LogWarning); - Ros2csLogger.setCallback(LogLevel.INFO, Debug.Log); - Ros2csLogger.setCallback(LogLevel.DEBUG, Debug.Log); - Ros2csLogger.LogLevel = LogLevel.WARNING; - } - - private string GetMetadataValue(XmlDocument doc, string valuePath) - { - return doc.DocumentElement.SelectSingleNode(valuePath).InnerText; - } - - private void LoadMetadata() - { - char separator = Path.DirectorySeparatorChar; - try - { - ros2csMetadata.Load(GetPluginPath() + separator + "metadata_ros2cs.xml"); - ros2ForUnityMetadata.Load(GetRos2ForUnityPath() + separator + "metadata_ros2_for_unity.xml"); - } - catch (System.IO.FileNotFoundException) - { -#if UNITY_EDITOR - var errMessage = "Could not find metadata files."; - EditorApplication.isPlaying = false; - throw new System.IO.FileNotFoundException(errMessage); -#else - const int NO_METADATA = 1; - Application.Quit(NO_METADATA); -#endif - } - } - - internal ROS2ForUnity() - { - // Load metadata - LoadMetadata(); - string currentRos2Version = GetROSVersion(); - string standalone = IsStandalone() ? "standalone" : "non-standalone"; - - // Self checks - CheckROSSupport(currentRos2Version); - CheckIntegrity(); - - // Library loading - if (GetOS() == Platform.Windows) { - // Windows version can run standalone, modifies PATH to ensure all plugins visibility - SetEnvPathVariable(); - } else { - // For foxy, it is necessary to use modified version of librcpputils to resolve custom msgs packages. - ROS2.GlobalVariables.absolutePath = GetPluginPath() + "/"; - if (currentRos2Version == "foxy") { - ROS2.GlobalVariables.preloadLibrary = true; - ROS2.GlobalVariables.preloadLibraryName = "librcpputils.so"; - } - } - - // Initialize - ConnectLoggers(); - Ros2cs.Init(); - RegisterCtrlCHandler(); - - string rmwImpl = Ros2cs.GetRMWImplementation(); - - Debug.Log("ROS2 version: " + currentRos2Version + ". Build type: " + standalone + ". RMW: " + rmwImpl); - -#if UNITY_EDITOR - EditorApplication.playModeStateChanged += this.EditorPlayStateChanged; - EditorApplication.quitting += this.DestroyROS2ForUnity; -#endif - isInitialized = true; - } - - private static void ThrowIfUninitialized(string callContext) - { - if (!isInitialized) - { - throw new InvalidOperationException("Ros2 For Unity is not initialized, can't " + callContext); - } - } - - /// - /// Check if ROS2 module is properly initialized and no shutdown was called yet - /// - /// The state of ROS2 module. Should be checked before attempting to create or use pubs/subs - public bool Ok() - { - if (!isInitialized) - { - return false; - } - return Ros2cs.Ok(); - } - - internal void DestroyROS2ForUnity() - { - if (isInitialized) - { - Debug.Log("Shutting down Ros2 For Unity"); - Ros2cs.Shutdown(); - isInitialized = false; - } - } - - ~ROS2ForUnity() - { - DestroyROS2ForUnity(); - } - -#if UNITY_EDITOR - void EditorPlayStateChanged(PlayModeStateChange change) - { - if (change == PlayModeStateChange.ExitingPlayMode) - { - DestroyROS2ForUnity(); - } - } -#endif -} - -} // namespace ROS2 +// Copyright 2019-2021 Robotec.ai. +// +// 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.IO; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; +using System.Xml; + +namespace ROS2 +{ + +/// +/// An internal class responsible for handling checking, proper initialization and shutdown of ROS2cs, +/// +internal class ROS2ForUnity +{ + private static bool isInitialized = false; + private static string ros2ForUnityAssetFolderName = "Ros2ForUnity"; + public readonly static string rootPath; // Full path to `Runtime/` + public readonly static string pluginPath; // Full path to `Runtime/Plugins/[Platform]/` + private XmlDocument ros2csMetadata = new XmlDocument(); + private XmlDocument ros2ForUnityMetadata = new XmlDocument(); + + public enum Platform + { + Windows, + Linux + } + + public static Platform GetOS() + { + if (Application.platform == RuntimePlatform.LinuxEditor || Application.platform == RuntimePlatform.LinuxPlayer) + { + return Platform.Linux; + } + else if (Application.platform == RuntimePlatform.WindowsEditor || Application.platform == RuntimePlatform.WindowsPlayer) + { + return Platform.Windows; + } + throw new System.NotSupportedException("Only Linux and Windows are supported"); + } + + private static bool InEditor() { + return Application.isEditor; + } + + private static string GetOSName() + { + switch (GetOS()) + { + case Platform.Linux: + return "Linux"; + case Platform.Windows: + return "Windows"; + default: + throw new System.NotSupportedException("Only Linux and Windows are supported"); + } + } + + private string GetEnvPathVariableName() + { + if (GetOS() == Platform.Windows) + { + return "PATH"; + } + + return "LD_LIBRARY_PATH"; + } + + private string GetEnvPathVariableValue() + { + return Environment.GetEnvironmentVariable(GetEnvPathVariableName()); + } + + /// + /// Function responsible for setting up of environment paths for standalone builds + /// + /// + /// Note that on Linux, LD_LIBRARY_PATH as used for dlopen() is determined on process start and this change won't + /// affect it. Ros2 looks for rmw implementation based on this variable (independently) and the change + /// is effective for this process, however rmw implementation's dependencies itself are loaded by dynamic linker + /// anyway so setting it for Linux is pointless. + /// + private void SetEnvPathVariable() + { + string currentPath = GetEnvPathVariableValue(); + + char envPathSep = (GetOS() == Platform.Windows) ? ';' : ':'; + + Environment.SetEnvironmentVariable(GetEnvPathVariableName(), pluginPath + envPathSep + currentPath); + } + + public bool IsStandalone() { + return Convert.ToBoolean(Convert.ToInt16(GetMetadataValue(ros2csMetadata, "/ros2cs/standalone"))); + } + + public string GetROSVersion() + { + string ros2SourcedCodename = GetROSVersionSourced(); + string ros2FromRos4UMetadata = GetMetadataValue(ros2ForUnityMetadata, "/ros2_for_unity/ros2"); + + // Sourced ROS2 libs takes priority + if (string.IsNullOrEmpty(ros2SourcedCodename)) { + return ros2FromRos4UMetadata; + } + + return ros2SourcedCodename; + } + + /// + /// Checks if both ros2cs and ros2-for-unity were build for the same ros version as well as + /// the current sourced ros version matches ros2cs binaries. + /// + public void CheckIntegrity() + { + string ros2SourcedCodename = GetROSVersionSourced(); + string ros2FromRos2csMetadata = GetMetadataValue(ros2csMetadata, "/ros2cs/ros2"); + string ros2FromRos4UMetadata = GetMetadataValue(ros2ForUnityMetadata, "/ros2_for_unity/ros2"); + + if (ros2FromRos4UMetadata != ros2FromRos2csMetadata) { + Debug.LogError( + "ROS2 versions in 'ros2cs' and 'ros2-for-unity' metadata files are not the same. " + + "This is caused by mixing versions/builds. Plugin might not work correctly." + ); + } + + if(!IsStandalone() && ros2SourcedCodename != ros2FromRos2csMetadata) { + Debug.LogError( + "ROS2 version in 'ros2cs' metadata doesn't match currently sourced version. " + + "This is caused by mixing versions/builds. Plugin might not work correctly." + ); + } + + if (IsStandalone() && !string.IsNullOrEmpty(ros2SourcedCodename)) { + Debug.LogError( + "You should not source ROS2 in 'ros2-for-unity' standalone build. " + + "Plugin might not work correctly." + ); + } + } + + public string GetROSVersionSourced() + { + return Environment.GetEnvironmentVariable("ROS_DISTRO"); + } + + /// + /// Check if the ros version is supported, only applicable to non-standalone plugin versions + /// (i. e. without ros2 libraries included in the plugin). + /// + private void CheckROSSupport(string ros2Codename) + { + List supportedVersions = new List() { "foxy", "galactic", "humble", "rolling" }; + var supportedVersionsString = String.Join(", ", supportedVersions); + if (string.IsNullOrEmpty(ros2Codename)) + { + string errMessage = "No ROS environment sourced. You need to source your ROS2 " + supportedVersionsString + + " environment before launching Unity (ROS_DISTRO env variable not found)"; + Debug.LogError(errMessage); +#if UNITY_EDITOR + EditorApplication.isPlaying = false; + throw new System.InvalidOperationException(errMessage); +#else + const int ROS_NOT_SOURCED_ERROR_CODE = 33; + Application.Quit(ROS_NOT_SOURCED_ERROR_CODE); +#endif + } + + if (!supportedVersions.Contains(ros2Codename)) + { + string errMessage = "Currently sourced ROS version differs from supported one. Sourced: " + ros2Codename + + ", supported: " + supportedVersionsString + "."; + Debug.LogError(errMessage); +#if UNITY_EDITOR + EditorApplication.isPlaying = false; + throw new System.NotSupportedException(errMessage); +#else + const int ROS_BAD_VERSION_CODE = 34; + Application.Quit(ROS_BAD_VERSION_CODE); +#endif + } else if (ros2Codename.Equals("rolling") ) { + Debug.LogWarning("You are using ROS2 rolling version. Bleeding edge version might not work correctly."); + } + } + + private void RegisterCtrlCHandler() + { +#if ENABLE_MONO + // Il2CPP build does not support Console.CancelKeyPress currently + Console.CancelKeyPress += (sender, eventArgs) => { + eventArgs.Cancel = true; + DestroyROS2ForUnity(); + }; +#endif + } + + private void ConnectLoggers() + { + Ros2csLogger.setCallback(LogLevel.ERROR, Debug.LogError); + Ros2csLogger.setCallback(LogLevel.WARNING, Debug.LogWarning); + Ros2csLogger.setCallback(LogLevel.INFO, Debug.Log); + Ros2csLogger.setCallback(LogLevel.DEBUG, Debug.Log); + Ros2csLogger.LogLevel = LogLevel.WARNING; + } + + private string GetMetadataValue(XmlDocument doc, string valuePath) + { + return doc.DocumentElement.SelectSingleNode(valuePath).InnerText; + } + + private void LoadMetadata() + { + try + { + ros2csMetadata.Load( + Path.Combine(pluginPath, "metadata_ros2cs.xml") + ); + ros2ForUnityMetadata.Load( + Path.Combine(rootPath, "metadata_ros2_for_unity.xml") + ); + } + catch (System.IO.FileNotFoundException) + { +#if UNITY_EDITOR + var errMessage = "Could not find metadata files."; + EditorApplication.isPlaying = false; + throw new System.IO.FileNotFoundException(errMessage); +#else + const int NO_METADATA = 1; + Application.Quit(NO_METADATA); +#endif + } + } + + /// + /// Static constructor (mostly for paths) + /// + static ROS2ForUnity() + { + // Make paths: + + rootPath = Path.GetFullPath("Packages/com.robotecai.ros2-for-unity/Runtime"); + + pluginPath = Path.Combine(rootPath, "Plugins"); + + if (InEditor()) + { + pluginPath = Path.Combine(pluginPath, GetOSName()); + } + + if (InEditor() || GetOS() == Platform.Windows) + { + pluginPath = Path.Combine(pluginPath, "x86_64"); + } + } + + internal ROS2ForUnity() + { + // Load metadata + LoadMetadata(); + string currentRos2Version = GetROSVersion(); + string standalone = IsStandalone() ? "standalone" : "non-standalone"; + + // Self checks + CheckROSSupport(currentRos2Version); + CheckIntegrity(); + + // Library loading + if (GetOS() == Platform.Windows) { + // Windows version can run standalone, modifies PATH to ensure all plugins visibility + SetEnvPathVariable(); + } else { + // For foxy, it is necessary to use modified version of librcpputils to resolve custom msgs packages. + ROS2.GlobalVariables.absolutePath = pluginPath + Path.PathSeparator; + if (currentRos2Version == "foxy") { + ROS2.GlobalVariables.preloadLibrary = true; + ROS2.GlobalVariables.preloadLibraryName = "librcpputils.so"; + } + } + + // Initialize + ConnectLoggers(); + Ros2cs.Init(); + RegisterCtrlCHandler(); + + string rmwImpl = Ros2cs.GetRMWImplementation(); + + Debug.Log("ROS2 version: " + currentRos2Version + ". Build type: " + standalone + ". RMW: " + rmwImpl); + +#if UNITY_EDITOR + EditorApplication.playModeStateChanged += this.EditorPlayStateChanged; + EditorApplication.quitting += this.DestroyROS2ForUnity; +#endif + isInitialized = true; + } + + private static void ThrowIfUninitialized(string callContext) + { + if (!isInitialized) + { + throw new InvalidOperationException("Ros2 For Unity is not initialized, can't " + callContext); + } + } + + /// + /// Check if ROS2 module is properly initialized and no shutdown was called yet + /// + /// The state of ROS2 module. Should be checked before attempting to create or use pubs/subs + public bool Ok() + { + if (!isInitialized) + { + return false; + } + return Ros2cs.Ok(); + } + + internal void DestroyROS2ForUnity() + { + if (isInitialized) + { + Debug.Log("Shutting down Ros2 For Unity"); + Ros2cs.Shutdown(); + isInitialized = false; + } + } + + ~ROS2ForUnity() + { + DestroyROS2ForUnity(); + } + +#if UNITY_EDITOR + void EditorPlayStateChanged(PlayModeStateChange change) + { + if (change == PlayModeStateChange.ExitingPlayMode) + { + DestroyROS2ForUnity(); + } + } +#endif +} + +} // namespace ROS2 diff --git a/src/Ros2ForUnity/Scripts/ROS2ForUnity.cs.meta b/src/Ros2ForUnity/Runtime/Scripts/ROS2ForUnity.cs.meta similarity index 100% rename from src/Ros2ForUnity/Scripts/ROS2ForUnity.cs.meta rename to src/Ros2ForUnity/Runtime/Scripts/ROS2ForUnity.cs.meta diff --git a/src/Ros2ForUnity/Scripts/ROS2ListenerExample.cs b/src/Ros2ForUnity/Runtime/Scripts/ROS2ListenerExample.cs similarity index 96% rename from src/Ros2ForUnity/Scripts/ROS2ListenerExample.cs rename to src/Ros2ForUnity/Runtime/Scripts/ROS2ListenerExample.cs index d145359..7433221 100644 --- a/src/Ros2ForUnity/Scripts/ROS2ListenerExample.cs +++ b/src/Ros2ForUnity/Runtime/Scripts/ROS2ListenerExample.cs @@ -1,46 +1,46 @@ -// Copyright 2019-2021 Robotec.ai. -// -// 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 UnityEngine; - -namespace ROS2 -{ - -/// -/// An example class provided for testing of basic ROS2 communication -/// -public class ROS2ListenerExample : MonoBehaviour -{ - private ROS2UnityComponent ros2Unity; - private ROS2Node ros2Node; - private ISubscription chatter_sub; - - void Start() - { - ros2Unity = GetComponent(); - } - - void Update() - { - if (ros2Node == null && ros2Unity.Ok()) - { - ros2Node = ros2Unity.CreateNode("ROS2UnityListenerNode"); - chatter_sub = ros2Node.CreateSubscription( - "chatter", msg => Debug.Log("Unity listener heard: [" + msg.Data + "]")); - } - } -} - -} // namespace ROS2 +// Copyright 2019-2021 Robotec.ai. +// +// 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 UnityEngine; + +namespace ROS2 +{ + +/// +/// An example class provided for testing of basic ROS2 communication +/// +public class ROS2ListenerExample : MonoBehaviour +{ + private ROS2UnityComponent ros2Unity; + private ROS2Node ros2Node; + private ISubscription chatter_sub; + + void Start() + { + ros2Unity = GetComponent(); + } + + void Update() + { + if (ros2Node == null && ros2Unity.Ok()) + { + ros2Node = ros2Unity.CreateNode("ROS2UnityListenerNode"); + chatter_sub = ros2Node.CreateSubscription( + "chatter", msg => Debug.Log("Unity listener heard: [" + msg.Data + "]")); + } + } +} + +} // namespace ROS2 diff --git a/src/Ros2ForUnity/Scripts/ROS2ListenerExample.cs.meta b/src/Ros2ForUnity/Runtime/Scripts/ROS2ListenerExample.cs.meta similarity index 100% rename from src/Ros2ForUnity/Scripts/ROS2ListenerExample.cs.meta rename to src/Ros2ForUnity/Runtime/Scripts/ROS2ListenerExample.cs.meta diff --git a/src/Ros2ForUnity/Scripts/ROS2Node.cs b/src/Ros2ForUnity/Runtime/Scripts/ROS2Node.cs similarity index 97% rename from src/Ros2ForUnity/Scripts/ROS2Node.cs rename to src/Ros2ForUnity/Runtime/Scripts/ROS2Node.cs index ad74fca..e007a0e 100644 --- a/src/Ros2ForUnity/Scripts/ROS2Node.cs +++ b/src/Ros2ForUnity/Runtime/Scripts/ROS2Node.cs @@ -1,151 +1,151 @@ -// Copyright 2019-2021 Robotec.ai. -// -// 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 UnityEngine; -using UnityEditor; - -namespace ROS2 -{ - -/// -/// A class representing a ros2 node. Multiple nodes can be used. Node can be removed by GC when not used anymore, -/// but will also be removed properly with Ros2cs Shutdown, which ROS2 for Unity performs on application quit -/// The node should be constructed through ROS2UnityComponent class, which also handles spinning -/// -public class ROS2Node -{ - internal INode node; - public ROS2Clock clock; - public string name; - - // Use ROS2UnityComponent to create a node - internal ROS2Node(string unityROS2NodeName = "unity_ros2_node") - { - name = unityROS2NodeName; - node = Ros2cs.CreateNode(name); - clock = new ROS2Clock(); - } - - ~ROS2Node() - { - Ros2cs.RemoveNode(node); - } - - private static void ThrowIfUninitialized(string callContext) - { - if (!Ros2cs.Ok()) - { - throw new InvalidOperationException("Ros2 For Unity is not initialized, can't " + callContext); - } - } - - /// - /// Create a publisher with QoS suitable for sensor data - /// - /// The publisher - /// topic that will be used for publishing - public Publisher CreateSensorPublisher(string topicName) where T : Message, new() - { - QualityOfServiceProfile sensorProfile = new QualityOfServiceProfile(QosPresetProfile.SENSOR_DATA); - return CreatePublisher(topicName, sensorProfile); - } - - /// - /// Create a publisher with indicated QoS. - /// - /// The publisher - /// topic that will be used for publishing - /// QoS for publishing. If no QoS is selected, it will default to reliable, keep 10 last - public Publisher CreatePublisher(string topicName, QualityOfServiceProfile qos = null) where T : Message, new() - { - ThrowIfUninitialized("create publisher"); - return node.CreatePublisher(topicName, qos); - } - - /// - /// Create a subscription - /// - /// The subscription - /// topic to subscribe to - /// QoS for subscription. If no QoS is selected, it will default to reliable, keep 10 last - public Subscription CreateSubscription(string topicName, Action callback, - QualityOfServiceProfile qos = null) where T : Message, new() - { - if (qos == null) - { - qos = new QualityOfServiceProfile(QosPresetProfile.DEFAULT); - } - ThrowIfUninitialized("create subscription"); - return node.CreateSubscription(topicName, callback, qos); - } - - - /// - /// Remove existing subscription (returned earlier with CreateSubscription) - /// - /// The whether subscription was found (e. g. false if removed earlier elsewhere) - /// subscrition to remove, returned from CreateSubscription - public bool RemoveSubscription(ISubscriptionBase subscription) - { - ThrowIfUninitialized("remove subscription"); - return node.RemoveSubscription(subscription); - } - - /// - /// Remove existing publisher - /// - /// The whether publisher was found (e. g. false if removed earlier elsewhere) - /// publisher to remove, returned from CreatePublisher or CreateSensorPublisher - public bool RemovePublisher(IPublisherBase publisher) - { - ThrowIfUninitialized("remove publisher"); - return node.RemovePublisher(publisher); - } - - /// - public Service CreateService(string topic, Func callback, QualityOfServiceProfile qos = null) - where I : Message, new() - where O : Message, new() - { - ThrowIfUninitialized("create service"); - return node.CreateService(topic, callback, qos); - } - - /// - public bool RemoveService(IServiceBase service) - { - ThrowIfUninitialized("remove service"); - return node.RemoveService(service); - } - - /// - public Client CreateClient(string topic, QualityOfServiceProfile qos = null) - where I : Message, new() - where O : Message, new() - { - ThrowIfUninitialized(callContext: "create client"); - return node.CreateClient(topic, qos); - } - - /// - public bool RemoveClient(IClientBase client) - { - ThrowIfUninitialized(callContext: "remove client"); - return node.RemoveClient(client); - } -} - -} // namespace ROS2 +// Copyright 2019-2021 Robotec.ai. +// +// 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 UnityEngine; +using UnityEditor; + +namespace ROS2 +{ + +/// +/// A class representing a ros2 node. Multiple nodes can be used. Node can be removed by GC when not used anymore, +/// but will also be removed properly with Ros2cs Shutdown, which ROS2 for Unity performs on application quit +/// The node should be constructed through ROS2UnityComponent class, which also handles spinning +/// +public class ROS2Node +{ + internal INode node; + public ROS2Clock clock; + public string name; + + // Use ROS2UnityComponent to create a node + internal ROS2Node(string unityROS2NodeName = "unity_ros2_node") + { + name = unityROS2NodeName; + node = Ros2cs.CreateNode(name); + clock = new ROS2Clock(); + } + + ~ROS2Node() + { + Ros2cs.RemoveNode(node); + } + + private static void ThrowIfUninitialized(string callContext) + { + if (!Ros2cs.Ok()) + { + throw new InvalidOperationException("Ros2 For Unity is not initialized, can't " + callContext); + } + } + + /// + /// Create a publisher with QoS suitable for sensor data + /// + /// The publisher + /// topic that will be used for publishing + public Publisher CreateSensorPublisher(string topicName) where T : Message, new() + { + QualityOfServiceProfile sensorProfile = new QualityOfServiceProfile(QosPresetProfile.SENSOR_DATA); + return CreatePublisher(topicName, sensorProfile); + } + + /// + /// Create a publisher with indicated QoS. + /// + /// The publisher + /// topic that will be used for publishing + /// QoS for publishing. If no QoS is selected, it will default to reliable, keep 10 last + public Publisher CreatePublisher(string topicName, QualityOfServiceProfile qos = null) where T : Message, new() + { + ThrowIfUninitialized("create publisher"); + return node.CreatePublisher(topicName, qos); + } + + /// + /// Create a subscription + /// + /// The subscription + /// topic to subscribe to + /// QoS for subscription. If no QoS is selected, it will default to reliable, keep 10 last + public Subscription CreateSubscription(string topicName, Action callback, + QualityOfServiceProfile qos = null) where T : Message, new() + { + if (qos == null) + { + qos = new QualityOfServiceProfile(QosPresetProfile.DEFAULT); + } + ThrowIfUninitialized("create subscription"); + return node.CreateSubscription(topicName, callback, qos); + } + + + /// + /// Remove existing subscription (returned earlier with CreateSubscription) + /// + /// The whether subscription was found (e. g. false if removed earlier elsewhere) + /// subscrition to remove, returned from CreateSubscription + public bool RemoveSubscription(ISubscriptionBase subscription) + { + ThrowIfUninitialized("remove subscription"); + return node.RemoveSubscription(subscription); + } + + /// + /// Remove existing publisher + /// + /// The whether publisher was found (e. g. false if removed earlier elsewhere) + /// publisher to remove, returned from CreatePublisher or CreateSensorPublisher + public bool RemovePublisher(IPublisherBase publisher) + { + ThrowIfUninitialized("remove publisher"); + return node.RemovePublisher(publisher); + } + + /// + public Service CreateService(string topic, Func callback, QualityOfServiceProfile qos = null) + where I : Message, new() + where O : Message, new() + { + ThrowIfUninitialized("create service"); + return node.CreateService(topic, callback, qos); + } + + /// + public bool RemoveService(IServiceBase service) + { + ThrowIfUninitialized("remove service"); + return node.RemoveService(service); + } + + /// + public Client CreateClient(string topic, QualityOfServiceProfile qos = null) + where I : Message, new() + where O : Message, new() + { + ThrowIfUninitialized(callContext: "create client"); + return node.CreateClient(topic, qos); + } + + /// + public bool RemoveClient(IClientBase client) + { + ThrowIfUninitialized(callContext: "remove client"); + return node.RemoveClient(client); + } +} + +} // namespace ROS2 diff --git a/src/Ros2ForUnity/Scripts/ROS2Node.cs.meta b/src/Ros2ForUnity/Runtime/Scripts/ROS2Node.cs.meta similarity index 100% rename from src/Ros2ForUnity/Scripts/ROS2Node.cs.meta rename to src/Ros2ForUnity/Runtime/Scripts/ROS2Node.cs.meta diff --git a/src/Ros2ForUnity/Scripts/ROS2PerformanceTest.cs b/src/Ros2ForUnity/Runtime/Scripts/ROS2PerformanceTest.cs similarity index 96% rename from src/Ros2ForUnity/Scripts/ROS2PerformanceTest.cs rename to src/Ros2ForUnity/Runtime/Scripts/ROS2PerformanceTest.cs index 3b70f3b..84b7e74 100644 --- a/src/Ros2ForUnity/Scripts/ROS2PerformanceTest.cs +++ b/src/Ros2ForUnity/Runtime/Scripts/ROS2PerformanceTest.cs @@ -1,137 +1,137 @@ -// Copyright 2019-2021 Robotec.ai. -// -// 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 UnityEngine; -using System.Threading; - -namespace ROS2 -{ - -/// -/// An example class provided for performance testing of ROS2 communication -/// -public class ROS2PerformanceTest : MonoBehaviour -{ - public int messageSize = 10000; - public int rate = 10; - private int interval_ms = 100; - private ROS2UnityComponent ros2Unity; - private ROS2Node ros2Node; - private IPublisher perf_pub; - sensor_msgs.msg.PointCloud2 msg; - private bool initialized = false; - - void Start() - { - ros2Unity = GetComponent(); - PrepMessage(); - } - - void OnValidate() - { - if (rate < 1) - { - interval_ms = 0; - } - else - { - interval_ms = 1000 / rate; - } - PrepMessage(); - } - - private void Publish() - { - while(true) - { - if (ros2Unity.Ok()) - { - if (ros2Node == null) - { - ros2Node = ros2Unity.CreateNode("ros2_unity_performance_test_node"); - perf_pub = ros2Node.CreateSensorPublisher("perf_chatter"); - } - - var msgWithHeader = msg as MessageWithHeader; - ros2Node.clock.UpdateROSTimestamp(ref msgWithHeader); - perf_pub.Publish(msg); - if (interval_ms > 0) - { - Thread.Sleep(interval_ms); - } - } - } - } - - void FixedUpdate() - { - if (!initialized) - { - Thread publishThread = new Thread(() => Publish()); - publishThread.Start(); - initialized = true; - } - } - - private void AssignField(ref sensor_msgs.msg.PointField pf, string n, uint off, byte dt, uint count) - { - pf.Name = n; - pf.Offset = off; - pf.Datatype = dt; - pf.Count = count; - } - - private void PrepMessage() - { - uint count = (uint)messageSize; //point per message - uint fieldsSize = 16; - uint rowSize = count * fieldsSize; - msg = new sensor_msgs.msg.PointCloud2() - { - Height = 1, - Width = count, - Is_bigendian = false, - Is_dense = true, - Point_step = fieldsSize, - Row_step = rowSize, - Data = new byte[rowSize * 1] - }; - uint pointFieldCount = 4; - msg.Fields = new sensor_msgs.msg.PointField[pointFieldCount]; - for (int i = 0; i < pointFieldCount; ++i) - { - msg.Fields[i] = new sensor_msgs.msg.PointField(); - } - - AssignField(ref msg.Fields[0], "x", 0, 7, 1); - AssignField(ref msg.Fields[1], "y", 4, 7, 1); - AssignField(ref msg.Fields[2], "z", 8, 7, 1); - AssignField(ref msg.Fields[3], "intensity", 12, 7, 1); - float[] pointsArray = new float[count * msg.Fields.Length]; - - var floatIndex = 0; - for (int i = 0; i < count; ++i) - { - float intensity = 100; - pointsArray[floatIndex++] = 1; - pointsArray[floatIndex++] = 2; - pointsArray[floatIndex++] = 3; - pointsArray[floatIndex++] = intensity; - } - System.Buffer.BlockCopy(pointsArray, 0, msg.Data, 0, msg.Data.Length); - msg.SetHeaderFrame("pc"); - } -} - -} // namespace ROS2 +// Copyright 2019-2021 Robotec.ai. +// +// 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 UnityEngine; +using System.Threading; + +namespace ROS2 +{ + +/// +/// An example class provided for performance testing of ROS2 communication +/// +public class ROS2PerformanceTest : MonoBehaviour +{ + public int messageSize = 10000; + public int rate = 10; + private int interval_ms = 100; + private ROS2UnityComponent ros2Unity; + private ROS2Node ros2Node; + private IPublisher perf_pub; + sensor_msgs.msg.PointCloud2 msg; + private bool initialized = false; + + void Start() + { + ros2Unity = GetComponent(); + PrepMessage(); + } + + void OnValidate() + { + if (rate < 1) + { + interval_ms = 0; + } + else + { + interval_ms = 1000 / rate; + } + PrepMessage(); + } + + private void Publish() + { + while(true) + { + if (ros2Unity.Ok()) + { + if (ros2Node == null) + { + ros2Node = ros2Unity.CreateNode("ros2_unity_performance_test_node"); + perf_pub = ros2Node.CreateSensorPublisher("perf_chatter"); + } + + var msgWithHeader = msg as MessageWithHeader; + ros2Node.clock.UpdateROSTimestamp(ref msgWithHeader); + perf_pub.Publish(msg); + if (interval_ms > 0) + { + Thread.Sleep(interval_ms); + } + } + } + } + + void FixedUpdate() + { + if (!initialized) + { + Thread publishThread = new Thread(() => Publish()); + publishThread.Start(); + initialized = true; + } + } + + private void AssignField(ref sensor_msgs.msg.PointField pf, string n, uint off, byte dt, uint count) + { + pf.Name = n; + pf.Offset = off; + pf.Datatype = dt; + pf.Count = count; + } + + private void PrepMessage() + { + uint count = (uint)messageSize; //point per message + uint fieldsSize = 16; + uint rowSize = count * fieldsSize; + msg = new sensor_msgs.msg.PointCloud2() + { + Height = 1, + Width = count, + Is_bigendian = false, + Is_dense = true, + Point_step = fieldsSize, + Row_step = rowSize, + Data = new byte[rowSize * 1] + }; + uint pointFieldCount = 4; + msg.Fields = new sensor_msgs.msg.PointField[pointFieldCount]; + for (int i = 0; i < pointFieldCount; ++i) + { + msg.Fields[i] = new sensor_msgs.msg.PointField(); + } + + AssignField(ref msg.Fields[0], "x", 0, 7, 1); + AssignField(ref msg.Fields[1], "y", 4, 7, 1); + AssignField(ref msg.Fields[2], "z", 8, 7, 1); + AssignField(ref msg.Fields[3], "intensity", 12, 7, 1); + float[] pointsArray = new float[count * msg.Fields.Length]; + + var floatIndex = 0; + for (int i = 0; i < count; ++i) + { + float intensity = 100; + pointsArray[floatIndex++] = 1; + pointsArray[floatIndex++] = 2; + pointsArray[floatIndex++] = 3; + pointsArray[floatIndex++] = intensity; + } + System.Buffer.BlockCopy(pointsArray, 0, msg.Data, 0, msg.Data.Length); + msg.SetHeaderFrame("pc"); + } +} + +} // namespace ROS2 diff --git a/src/Ros2ForUnity/Scripts/ROS2PerformanceTest.cs.meta b/src/Ros2ForUnity/Runtime/Scripts/ROS2PerformanceTest.cs.meta similarity index 100% rename from src/Ros2ForUnity/Scripts/ROS2PerformanceTest.cs.meta rename to src/Ros2ForUnity/Runtime/Scripts/ROS2PerformanceTest.cs.meta diff --git a/src/Ros2ForUnity/Scripts/ROS2ServiceExample.cs b/src/Ros2ForUnity/Runtime/Scripts/ROS2ServiceExample.cs similarity index 100% rename from src/Ros2ForUnity/Scripts/ROS2ServiceExample.cs rename to src/Ros2ForUnity/Runtime/Scripts/ROS2ServiceExample.cs diff --git a/src/Ros2ForUnity/Runtime/Scripts/ROS2ServiceExample.cs.meta b/src/Ros2ForUnity/Runtime/Scripts/ROS2ServiceExample.cs.meta new file mode 100644 index 0000000..8d21546 --- /dev/null +++ b/src/Ros2ForUnity/Runtime/Scripts/ROS2ServiceExample.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 77ca4f3ef22cdb943ba7dc008cebddbd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Ros2ForUnity/Scripts/ROS2TalkerExample.cs b/src/Ros2ForUnity/Runtime/Scripts/ROS2TalkerExample.cs similarity index 96% rename from src/Ros2ForUnity/Scripts/ROS2TalkerExample.cs rename to src/Ros2ForUnity/Runtime/Scripts/ROS2TalkerExample.cs index 705ea0d..c56d1a2 100644 --- a/src/Ros2ForUnity/Scripts/ROS2TalkerExample.cs +++ b/src/Ros2ForUnity/Runtime/Scripts/ROS2TalkerExample.cs @@ -1,54 +1,54 @@ -// Copyright 2019-2021 Robotec.ai. -// -// 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 UnityEngine; - -namespace ROS2 -{ - -/// -/// An example class provided for testing of basic ROS2 communication -/// -public class ROS2TalkerExample : MonoBehaviour -{ - // Start is called before the first frame update - private ROS2UnityComponent ros2Unity; - private ROS2Node ros2Node; - private IPublisher chatter_pub; - private int i; - - void Start() - { - ros2Unity = GetComponent(); - } - - void Update() - { - if (ros2Unity.Ok()) - { - if (ros2Node == null) - { - ros2Node = ros2Unity.CreateNode("ROS2UnityTalkerNode"); - chatter_pub = ros2Node.CreatePublisher("chatter"); - } - - i++; - std_msgs.msg.String msg = new std_msgs.msg.String(); - msg.Data = "Unity ROS2 sending: hello " + i; - chatter_pub.Publish(msg); - } - } -} - -} // namespace ROS2 +// Copyright 2019-2021 Robotec.ai. +// +// 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 UnityEngine; + +namespace ROS2 +{ + +/// +/// An example class provided for testing of basic ROS2 communication +/// +public class ROS2TalkerExample : MonoBehaviour +{ + // Start is called before the first frame update + private ROS2UnityComponent ros2Unity; + private ROS2Node ros2Node; + private IPublisher chatter_pub; + private int i; + + void Start() + { + ros2Unity = GetComponent(); + } + + void Update() + { + if (ros2Unity.Ok()) + { + if (ros2Node == null) + { + ros2Node = ros2Unity.CreateNode("ROS2UnityTalkerNode"); + chatter_pub = ros2Node.CreatePublisher("chatter"); + } + + i++; + std_msgs.msg.String msg = new std_msgs.msg.String(); + msg.Data = "Unity ROS2 sending: hello " + i; + chatter_pub.Publish(msg); + } + } +} + +} // namespace ROS2 diff --git a/src/Ros2ForUnity/Scripts/ROS2TalkerExample.cs.meta b/src/Ros2ForUnity/Runtime/Scripts/ROS2TalkerExample.cs.meta similarity index 100% rename from src/Ros2ForUnity/Scripts/ROS2TalkerExample.cs.meta rename to src/Ros2ForUnity/Runtime/Scripts/ROS2TalkerExample.cs.meta diff --git a/src/Ros2ForUnity/Scripts/ROS2UnityComponent.cs b/src/Ros2ForUnity/Runtime/Scripts/ROS2UnityComponent.cs similarity index 96% rename from src/Ros2ForUnity/Scripts/ROS2UnityComponent.cs rename to src/Ros2ForUnity/Runtime/Scripts/ROS2UnityComponent.cs index 24018c8..7c916e2 100644 --- a/src/Ros2ForUnity/Scripts/ROS2UnityComponent.cs +++ b/src/Ros2ForUnity/Runtime/Scripts/ROS2UnityComponent.cs @@ -1,164 +1,164 @@ -// Copyright 2019-2021 Robotec.ai. -// -// 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 UnityEngine; -using System; -using System.Collections.Generic; -using System.Threading; -using ROS2; - -namespace ROS2 -{ - -/// -/// The principal MonoBehaviour class for handling ros2 nodes and executables. -/// Use this to create ros2 node, check ros2 status. -/// Spins and executes actions (e. g. clock, sensor publish triggers) in a dedicated thread -/// TODO: this is meant to be used as a one-of (a singleton). Enforce. However, things should work -/// anyway with more than one since the underlying library can handle multiple init and shutdown calls, -/// and does node name uniqueness check independently. -/// -public class ROS2UnityComponent : MonoBehaviour -{ - private ROS2ForUnity ros2forUnity; - private List nodes; - private List ros2csNodes; // For performance in spinning - private List executableActions; - private bool initialized = false; - private bool quitting = false; - private int interval = 2; // Spinning / executor interval in ms - private object mutex = new object(); - private double spinTimeout = 0.0001; - - public bool Ok() - { - lock (mutex) - { - if (ros2forUnity == null) - LazyConstruct(); - return (nodes != null && ros2forUnity.Ok()); - } - } - - private void LazyConstruct() - { - lock (mutex) - { - if (ros2forUnity != null) - return; - - ros2forUnity = new ROS2ForUnity(); - nodes = new List(); - ros2csNodes = new List(); - executableActions = new List(); - } - } - - void Start() - { - LazyConstruct(); - } - - public ROS2Node CreateNode(string name) - { - LazyConstruct(); - - lock (mutex) - { - foreach (ROS2Node n in nodes) - { // Assumed to be a rare operation on rather small (<1k) list - if (n.name == name) - { - throw new InvalidOperationException("Cannot create node " + name + ". A node with this name already exists!"); - } - } - ROS2Node node = new ROS2Node(name); - nodes.Add(node); - ros2csNodes.Add(node.node); - return node; - } - } - - public void RemoveNode(ROS2Node node) - { - lock (mutex) - { - ros2csNodes.Remove(node.node); - nodes.Remove(node); //Node will be later deleted if unused, by GC - } - } - - /// - /// Works as a simple executor registration analogue. These functions will be called with each Tick() - /// Actions need to take care of correct call resolution by checking in their body (TODO) - /// Make sure actions are lightweight (TODO - separate out threads for spinning and executables?) - /// - public void RegisterExecutable(Action executable) - { - LazyConstruct(); - - lock (mutex) - { - executableActions.Add(executable); - } - } - - public void UnregisterExecutable(Action executable) - { - lock (mutex) - { - executableActions.Remove(executable); - } - } - - /// - /// "Executor" thread will tick all clocks and spin the node - /// - private void Tick() - { - while (!quitting) - { - if (Ok()) - { - lock (mutex) - { - foreach (Action action in executableActions) - { - action(); - } - Ros2cs.SpinOnce(ros2csNodes, spinTimeout); - } - } - Thread.Sleep(interval); - } - } - - void FixedUpdate() - { - if (!initialized) - { - Thread publishThread = new Thread(() => Tick()); - publishThread.Start(); - initialized = true; - } - } - - void OnApplicationQuit() - { - quitting = true; - ros2forUnity.DestroyROS2ForUnity(); - } -} - -} // namespace ROS2 +// Copyright 2019-2021 Robotec.ai. +// +// 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 UnityEngine; +using System; +using System.Collections.Generic; +using System.Threading; +using ROS2; + +namespace ROS2 +{ + +/// +/// The principal MonoBehaviour class for handling ros2 nodes and executables. +/// Use this to create ros2 node, check ros2 status. +/// Spins and executes actions (e. g. clock, sensor publish triggers) in a dedicated thread +/// TODO: this is meant to be used as a one-of (a singleton). Enforce. However, things should work +/// anyway with more than one since the underlying library can handle multiple init and shutdown calls, +/// and does node name uniqueness check independently. +/// +public class ROS2UnityComponent : MonoBehaviour +{ + private ROS2ForUnity ros2forUnity; + private List nodes; + private List ros2csNodes; // For performance in spinning + private List executableActions; + private bool initialized = false; + private bool quitting = false; + private int interval = 2; // Spinning / executor interval in ms + private object mutex = new object(); + private double spinTimeout = 0.0001; + + public bool Ok() + { + lock (mutex) + { + if (ros2forUnity == null) + LazyConstruct(); + return (nodes != null && ros2forUnity.Ok()); + } + } + + private void LazyConstruct() + { + lock (mutex) + { + if (ros2forUnity != null) + return; + + ros2forUnity = new ROS2ForUnity(); + nodes = new List(); + ros2csNodes = new List(); + executableActions = new List(); + } + } + + void Start() + { + LazyConstruct(); + } + + public ROS2Node CreateNode(string name) + { + LazyConstruct(); + + lock (mutex) + { + foreach (ROS2Node n in nodes) + { // Assumed to be a rare operation on rather small (<1k) list + if (n.name == name) + { + throw new InvalidOperationException("Cannot create node " + name + ". A node with this name already exists!"); + } + } + ROS2Node node = new ROS2Node(name); + nodes.Add(node); + ros2csNodes.Add(node.node); + return node; + } + } + + public void RemoveNode(ROS2Node node) + { + lock (mutex) + { + ros2csNodes.Remove(node.node); + nodes.Remove(node); //Node will be later deleted if unused, by GC + } + } + + /// + /// Works as a simple executor registration analogue. These functions will be called with each Tick() + /// Actions need to take care of correct call resolution by checking in their body (TODO) + /// Make sure actions are lightweight (TODO - separate out threads for spinning and executables?) + /// + public void RegisterExecutable(Action executable) + { + LazyConstruct(); + + lock (mutex) + { + executableActions.Add(executable); + } + } + + public void UnregisterExecutable(Action executable) + { + lock (mutex) + { + executableActions.Remove(executable); + } + } + + /// + /// "Executor" thread will tick all clocks and spin the node + /// + private void Tick() + { + while (!quitting) + { + if (Ok()) + { + lock (mutex) + { + foreach (Action action in executableActions) + { + action(); + } + Ros2cs.SpinOnce(ros2csNodes, spinTimeout); + } + } + Thread.Sleep(interval); + } + } + + void FixedUpdate() + { + if (!initialized) + { + Thread publishThread = new Thread(() => Tick()); + publishThread.Start(); + initialized = true; + } + } + + void OnApplicationQuit() + { + quitting = true; + ros2forUnity.DestroyROS2ForUnity(); + } +} + +} // namespace ROS2 diff --git a/src/Ros2ForUnity/Scripts/ROS2UnityComponent.cs.meta b/src/Ros2ForUnity/Runtime/Scripts/ROS2UnityComponent.cs.meta similarity index 100% rename from src/Ros2ForUnity/Scripts/ROS2UnityComponent.cs.meta rename to src/Ros2ForUnity/Runtime/Scripts/ROS2UnityComponent.cs.meta diff --git a/src/Ros2ForUnity/Scripts/ROS2UnityCore.cs b/src/Ros2ForUnity/Runtime/Scripts/ROS2UnityCore.cs similarity index 100% rename from src/Ros2ForUnity/Scripts/ROS2UnityCore.cs rename to src/Ros2ForUnity/Runtime/Scripts/ROS2UnityCore.cs diff --git a/src/Ros2ForUnity/Scripts/ROS2UnityCore.cs.meta b/src/Ros2ForUnity/Runtime/Scripts/ROS2UnityCore.cs.meta similarity index 100% rename from src/Ros2ForUnity/Scripts/ROS2UnityCore.cs.meta rename to src/Ros2ForUnity/Runtime/Scripts/ROS2UnityCore.cs.meta diff --git a/src/Ros2ForUnity/Scripts/Sensor.cs b/src/Ros2ForUnity/Runtime/Scripts/Sensor.cs old mode 100755 new mode 100644 similarity index 100% rename from src/Ros2ForUnity/Scripts/Sensor.cs rename to src/Ros2ForUnity/Runtime/Scripts/Sensor.cs diff --git a/src/Ros2ForUnity/Scripts/Sensor.cs.meta b/src/Ros2ForUnity/Runtime/Scripts/Sensor.cs.meta similarity index 100% rename from src/Ros2ForUnity/Scripts/Sensor.cs.meta rename to src/Ros2ForUnity/Runtime/Scripts/Sensor.cs.meta diff --git a/src/Ros2ForUnity/Runtime/Scripts/Time.meta b/src/Ros2ForUnity/Runtime/Scripts/Time.meta new file mode 100644 index 0000000..20aa921 --- /dev/null +++ b/src/Ros2ForUnity/Runtime/Scripts/Time.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7733f1d2b41af9b4085ad9a8315c3ead +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Ros2ForUnity/Scripts/Time/DotnetTimeSource.cs b/src/Ros2ForUnity/Runtime/Scripts/Time/DotnetTimeSource.cs similarity index 100% rename from src/Ros2ForUnity/Scripts/Time/DotnetTimeSource.cs rename to src/Ros2ForUnity/Runtime/Scripts/Time/DotnetTimeSource.cs diff --git a/src/Ros2ForUnity/Runtime/Scripts/Time/DotnetTimeSource.cs.meta b/src/Ros2ForUnity/Runtime/Scripts/Time/DotnetTimeSource.cs.meta new file mode 100644 index 0000000..e400099 --- /dev/null +++ b/src/Ros2ForUnity/Runtime/Scripts/Time/DotnetTimeSource.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dbe7b625291ce71418e89f80c5846349 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Ros2ForUnity/Scripts/Time/ITimeSource.cs b/src/Ros2ForUnity/Runtime/Scripts/Time/ITimeSource.cs similarity index 100% rename from src/Ros2ForUnity/Scripts/Time/ITimeSource.cs rename to src/Ros2ForUnity/Runtime/Scripts/Time/ITimeSource.cs diff --git a/src/Ros2ForUnity/Runtime/Scripts/Time/ITimeSource.cs.meta b/src/Ros2ForUnity/Runtime/Scripts/Time/ITimeSource.cs.meta new file mode 100644 index 0000000..09413e0 --- /dev/null +++ b/src/Ros2ForUnity/Runtime/Scripts/Time/ITimeSource.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8a6b77a55c98705439d95de6bebe5fa7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Ros2ForUnity/Scripts/Time/ROS2Clock.cs b/src/Ros2ForUnity/Runtime/Scripts/Time/ROS2Clock.cs similarity index 100% rename from src/Ros2ForUnity/Scripts/Time/ROS2Clock.cs rename to src/Ros2ForUnity/Runtime/Scripts/Time/ROS2Clock.cs diff --git a/src/Ros2ForUnity/Scripts/Time/ROS2Clock.cs.meta b/src/Ros2ForUnity/Runtime/Scripts/Time/ROS2Clock.cs.meta similarity index 100% rename from src/Ros2ForUnity/Scripts/Time/ROS2Clock.cs.meta rename to src/Ros2ForUnity/Runtime/Scripts/Time/ROS2Clock.cs.meta diff --git a/src/Ros2ForUnity/Scripts/Time/ROS2TimeSource.cs b/src/Ros2ForUnity/Runtime/Scripts/Time/ROS2TimeSource.cs similarity index 100% rename from src/Ros2ForUnity/Scripts/Time/ROS2TimeSource.cs rename to src/Ros2ForUnity/Runtime/Scripts/Time/ROS2TimeSource.cs diff --git a/src/Ros2ForUnity/Runtime/Scripts/Time/ROS2TimeSource.cs.meta b/src/Ros2ForUnity/Runtime/Scripts/Time/ROS2TimeSource.cs.meta new file mode 100644 index 0000000..d259279 --- /dev/null +++ b/src/Ros2ForUnity/Runtime/Scripts/Time/ROS2TimeSource.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2bbfe7ca89c391244af9c394486efcb0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Ros2ForUnity/Scripts/Time/TimeUtils.cs b/src/Ros2ForUnity/Runtime/Scripts/Time/TimeUtils.cs similarity index 100% rename from src/Ros2ForUnity/Scripts/Time/TimeUtils.cs rename to src/Ros2ForUnity/Runtime/Scripts/Time/TimeUtils.cs diff --git a/src/Ros2ForUnity/Runtime/Scripts/Time/TimeUtils.cs.meta b/src/Ros2ForUnity/Runtime/Scripts/Time/TimeUtils.cs.meta new file mode 100644 index 0000000..32a55a9 --- /dev/null +++ b/src/Ros2ForUnity/Runtime/Scripts/Time/TimeUtils.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ae7c5c02efdefa94daaf1550b254a8e0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Ros2ForUnity/Scripts/Time/UnityTimeSource.cs b/src/Ros2ForUnity/Runtime/Scripts/Time/UnityTimeSource.cs similarity index 100% rename from src/Ros2ForUnity/Scripts/Time/UnityTimeSource.cs rename to src/Ros2ForUnity/Runtime/Scripts/Time/UnityTimeSource.cs diff --git a/src/Ros2ForUnity/Runtime/Scripts/Time/UnityTimeSource.cs.meta b/src/Ros2ForUnity/Runtime/Scripts/Time/UnityTimeSource.cs.meta new file mode 100644 index 0000000..eb532bb --- /dev/null +++ b/src/Ros2ForUnity/Runtime/Scripts/Time/UnityTimeSource.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4d78097250d392444a5902b58762d38d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Ros2ForUnity/Scripts/Transformations.cs b/src/Ros2ForUnity/Runtime/Scripts/Transformations.cs similarity index 100% rename from src/Ros2ForUnity/Scripts/Transformations.cs rename to src/Ros2ForUnity/Runtime/Scripts/Transformations.cs diff --git a/src/Ros2ForUnity/Scripts/Transformations.cs.meta b/src/Ros2ForUnity/Runtime/Scripts/Transformations.cs.meta similarity index 100% rename from src/Ros2ForUnity/Scripts/Transformations.cs.meta rename to src/Ros2ForUnity/Runtime/Scripts/Transformations.cs.meta diff --git a/src/Ros2ForUnity/Runtime/metadata_ros2_for_unity.xml.meta b/src/Ros2ForUnity/Runtime/metadata_ros2_for_unity.xml.meta new file mode 100644 index 0000000..5a05eb3 --- /dev/null +++ b/src/Ros2ForUnity/Runtime/metadata_ros2_for_unity.xml.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 239875d8263fd93429bd313e9767cb11 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Ros2ForUnity/Runtime/metadata_ros2cs.xml.meta b/src/Ros2ForUnity/Runtime/metadata_ros2cs.xml.meta new file mode 100644 index 0000000..b06fb61 --- /dev/null +++ b/src/Ros2ForUnity/Runtime/metadata_ros2cs.xml.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 459adb1c8300ac047b95fa3ea165bf89 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Ros2ForUnity/Runtime/robotecai.ros2-for-unity.asmdef b/src/Ros2ForUnity/Runtime/robotecai.ros2-for-unity.asmdef new file mode 100644 index 0000000..feb534d --- /dev/null +++ b/src/Ros2ForUnity/Runtime/robotecai.ros2-for-unity.asmdef @@ -0,0 +1,14 @@ +{ + "name": "RobotecAI.ROS2-for-Unity", + "rootNamespace": "", + "references": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} diff --git a/src/Ros2ForUnity/Runtime/robotecai.ros2-for-unity.asmdef.meta b/src/Ros2ForUnity/Runtime/robotecai.ros2-for-unity.asmdef.meta new file mode 100644 index 0000000..36ac666 --- /dev/null +++ b/src/Ros2ForUnity/Runtime/robotecai.ros2-for-unity.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ac79f61176286e84f93be5f4e048d950 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Ros2ForUnity/package.json b/src/Ros2ForUnity/package.json new file mode 100644 index 0000000..21cb40e --- /dev/null +++ b/src/Ros2ForUnity/package.json @@ -0,0 +1,15 @@ +{ + "name": "com.robotecai.ros2-for-unity", + "version": "1.3.0", + "displayName": "ROS2 For Unity", + "description": "Integration of ROS2 with Unity", + "unity": "2022.3", + "unityRelease": "5f1", + "documentationUrl": "https://github.com/RobotecAI/ros2-for-unity/", + "licensesUrl": "https://github.com/RobotecAI/ros2-for-unity/blob/develop/LICENSE.AL2", + "author": { + "name": "RobotecAI", + "email": "office@robotec.ai", + "url": "http://www.robotec.ai/" + } +} diff --git a/src/Ros2ForUnity/package.json.meta b/src/Ros2ForUnity/package.json.meta new file mode 100644 index 0000000..118a183 --- /dev/null +++ b/src/Ros2ForUnity/package.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 86a52626cb10818438fb3dc6c2a23337 +PackageManifestImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/scripts/metadata_generator.py b/src/scripts/metadata_generator.py index 25f6c40..a41180e 100644 --- a/src/scripts/metadata_generator.py +++ b/src/scripts/metadata_generator.py @@ -39,7 +39,7 @@ def get_ros2_for_unity_root_path() -> pathlib.Path: return pathlib.Path(__file__).parents[2] def get_ros2_for_unity_path() -> pathlib.Path: - return pathlib.Path(__file__).parents[1].joinpath("Ros2ForUnity") + return pathlib.Path(__file__).parents[1].joinpath("Ros2ForUnity").joinpath("Runtime") def get_ros2cs_path() -> pathlib.Path: return pathlib.Path(__file__).parents[1].joinpath("ros2cs")