diff --git a/.gitignore b/.gitignore
index 0653b96a..7733d871 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,12 @@
.DS_Store
-.swp
+*.swp
.idea
.vscode/
+
+# Generated by local utr runs
+.Editor
+.download
+.bin
+test-results
+
tutorials/pick_and_place/PickAndPlaceProject/Packages/packages-lock.json
diff --git a/.yamato/PickAndPlaceTests/IntegrationTestSettings.asset b/.yamato/PickAndPlaceTests/IntegrationTestSettings.asset
new file mode 100644
index 00000000..df0c5bd8
--- /dev/null
+++ b/.yamato/PickAndPlaceTests/IntegrationTestSettings.asset
@@ -0,0 +1,673 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!129 &1
+PlayerSettings:
+ m_ObjectHideFlags: 0
+ serializedVersion: 21
+ productGUID: 653f7f2858f49284bbf5f6d04c027b96
+ AndroidProfiler: 0
+ AndroidFilterTouchesWhenObscured: 0
+ AndroidEnableSustainedPerformanceMode: 0
+ defaultScreenOrientation: 4
+ targetDevice: 2
+ useOnDemandResources: 0
+ accelerometerFrequency: 60
+ companyName: UnityRobotics
+ productName: PickAndPlace
+ defaultCursor: {fileID: 0}
+ cursorHotspot: {x: 0, y: 0}
+ m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1}
+ m_ShowUnitySplashScreen: 1
+ m_ShowUnitySplashLogo: 1
+ m_SplashScreenOverlayOpacity: 1
+ m_SplashScreenAnimation: 1
+ m_SplashScreenLogoStyle: 1
+ m_SplashScreenDrawMode: 0
+ m_SplashScreenBackgroundAnimationZoom: 1
+ m_SplashScreenLogoAnimationZoom: 1
+ m_SplashScreenBackgroundLandscapeAspect: 1
+ m_SplashScreenBackgroundPortraitAspect: 1
+ m_SplashScreenBackgroundLandscapeUvs:
+ serializedVersion: 2
+ x: 0
+ y: 0
+ width: 1
+ height: 1
+ m_SplashScreenBackgroundPortraitUvs:
+ serializedVersion: 2
+ x: 0
+ y: 0
+ width: 1
+ height: 1
+ m_SplashScreenLogos: []
+ m_VirtualRealitySplashScreen: {fileID: 0}
+ m_HolographicTrackingLossScreen: {fileID: 0}
+ defaultScreenWidth: 1024
+ defaultScreenHeight: 768
+ defaultScreenWidthWeb: 960
+ defaultScreenHeightWeb: 600
+ m_StereoRenderingPath: 0
+ m_ActiveColorSpace: 0
+ m_MTRendering: 1
+ mipStripping: 0
+ numberOfMipsStripped: 0
+ m_StackTraceTypes: 010000000100000001000000010000000100000001000000
+ iosShowActivityIndicatorOnLoading: -1
+ androidShowActivityIndicatorOnLoading: -1
+ iosUseCustomAppBackgroundBehavior: 0
+ iosAllowHTTPDownload: 1
+ allowedAutorotateToPortrait: 1
+ allowedAutorotateToPortraitUpsideDown: 1
+ allowedAutorotateToLandscapeRight: 1
+ allowedAutorotateToLandscapeLeft: 1
+ useOSAutorotation: 1
+ use32BitDisplayBuffer: 1
+ preserveFramebufferAlpha: 0
+ disableDepthAndStencilBuffers: 0
+ androidStartInFullscreen: 1
+ androidRenderOutsideSafeArea: 1
+ androidUseSwappy: 1
+ androidBlitType: 0
+ defaultIsNativeResolution: 1
+ macRetinaSupport: 1
+ runInBackground: 1
+ captureSingleScreen: 0
+ muteOtherAudioSources: 0
+ Prepare IOS For Recording: 0
+ Force IOS Speakers When Recording: 0
+ deferSystemGesturesMode: 0
+ hideHomeButton: 0
+ submitAnalytics: 1
+ usePlayerLog: 1
+ bakeCollisionMeshes: 0
+ forceSingleInstance: 0
+ useFlipModelSwapchain: 1
+ resizableWindow: 0
+ useMacAppStoreValidation: 0
+ macAppStoreCategory: public.app-category.games
+ gpuSkinning: 1
+ xboxPIXTextureCapture: 0
+ xboxEnableAvatar: 0
+ xboxEnableKinect: 0
+ xboxEnableKinectAutoTracking: 0
+ xboxEnableFitness: 0
+ visibleInBackground: 1
+ allowFullscreenSwitch: 1
+ fullscreenMode: 1
+ xboxSpeechDB: 0
+ xboxEnableHeadOrientation: 0
+ xboxEnableGuest: 0
+ xboxEnablePIXSampling: 0
+ metalFramebufferOnly: 0
+ xboxOneResolution: 0
+ xboxOneSResolution: 0
+ xboxOneXResolution: 3
+ xboxOneMonoLoggingLevel: 0
+ xboxOneLoggingLevel: 1
+ xboxOneDisableEsram: 0
+ xboxOneEnableTypeOptimization: 0
+ xboxOnePresentImmediateThreshold: 0
+ switchQueueCommandMemory: 0
+ switchQueueControlMemory: 16384
+ switchQueueComputeMemory: 262144
+ switchNVNShaderPoolsGranularity: 33554432
+ switchNVNDefaultPoolsGranularity: 16777216
+ switchNVNOtherPoolsGranularity: 16777216
+ switchNVNMaxPublicTextureIDCount: 0
+ switchNVNMaxPublicSamplerIDCount: 0
+ stadiaPresentMode: 0
+ stadiaTargetFramerate: 0
+ vulkanNumSwapchainBuffers: 3
+ vulkanEnableSetSRGBWrite: 0
+ vulkanEnablePreTransform: 0
+ vulkanEnableLateAcquireNextImage: 0
+ m_SupportedAspectRatios:
+ 4:3: 1
+ 5:4: 1
+ 16:10: 1
+ 16:9: 1
+ Others: 1
+ bundleVersion: 0.1
+ preloadedAssets: []
+ metroInputSource: 0
+ wsaTransparentSwapchain: 0
+ m_HolographicPauseOnTrackingLoss: 1
+ xboxOneDisableKinectGpuReservation: 1
+ xboxOneEnable7thCore: 1
+ vrSettings:
+ enable360StereoCapture: 0
+ isWsaHolographicRemotingEnabled: 0
+ enableFrameTimingStats: 0
+ useHDRDisplay: 0
+ D3DHDRBitDepth: 0
+ m_ColorGamuts: 00000000
+ targetPixelDensity: 30
+ resolutionScalingMode: 0
+ androidSupportedAspectRatio: 1
+ androidMaxAspectRatio: 2.1
+ applicationIdentifier:
+ Standalone: com.UnityRobotics.PickAndPlace
+ buildNumber:
+ Standalone: 0
+ iPhone: 0
+ tvOS: 0
+ overrideDefaultApplicationIdentifier: 0
+ AndroidBundleVersionCode: 1
+ AndroidMinSdkVersion: 19
+ AndroidTargetSdkVersion: 0
+ AndroidPreferredInstallLocation: 1
+ aotOptions:
+ stripEngineCode: 1
+ iPhoneStrippingLevel: 0
+ iPhoneScriptCallOptimization: 0
+ ForceInternetPermission: 0
+ ForceSDCardPermission: 0
+ CreateWallpaper: 0
+ APKExpansionFiles: 0
+ keepLoadedShadersAlive: 0
+ StripUnusedMeshComponents: 1
+ VertexChannelCompressionMask: 4054
+ iPhoneSdkVersion: 988
+ iOSTargetOSVersionString: 11.0
+ tvOSSdkVersion: 0
+ tvOSRequireExtendedGameController: 0
+ tvOSTargetOSVersionString: 11.0
+ uIPrerenderedIcon: 0
+ uIRequiresPersistentWiFi: 0
+ uIRequiresFullScreen: 1
+ uIStatusBarHidden: 1
+ uIExitOnSuspend: 0
+ uIStatusBarStyle: 0
+ appleTVSplashScreen: {fileID: 0}
+ appleTVSplashScreen2x: {fileID: 0}
+ tvOSSmallIconLayers: []
+ tvOSSmallIconLayers2x: []
+ tvOSLargeIconLayers: []
+ tvOSLargeIconLayers2x: []
+ tvOSTopShelfImageLayers: []
+ tvOSTopShelfImageLayers2x: []
+ tvOSTopShelfImageWideLayers: []
+ tvOSTopShelfImageWideLayers2x: []
+ iOSLaunchScreenType: 0
+ iOSLaunchScreenPortrait: {fileID: 0}
+ iOSLaunchScreenLandscape: {fileID: 0}
+ iOSLaunchScreenBackgroundColor:
+ serializedVersion: 2
+ rgba: 0
+ iOSLaunchScreenFillPct: 100
+ iOSLaunchScreenSize: 100
+ iOSLaunchScreenCustomXibPath:
+ iOSLaunchScreeniPadType: 0
+ iOSLaunchScreeniPadImage: {fileID: 0}
+ iOSLaunchScreeniPadBackgroundColor:
+ serializedVersion: 2
+ rgba: 0
+ iOSLaunchScreeniPadFillPct: 100
+ iOSLaunchScreeniPadSize: 100
+ iOSLaunchScreeniPadCustomXibPath:
+ iOSLaunchScreenCustomStoryboardPath:
+ iOSLaunchScreeniPadCustomStoryboardPath:
+ iOSDeviceRequirements: []
+ iOSURLSchemes: []
+ iOSBackgroundModes: 0
+ iOSMetalForceHardShadows: 0
+ metalEditorSupport: 1
+ metalAPIValidation: 1
+ iOSRenderExtraFrameOnPause: 0
+ iosCopyPluginsCodeInsteadOfSymlink: 0
+ appleDeveloperTeamID:
+ iOSManualSigningProvisioningProfileID:
+ tvOSManualSigningProvisioningProfileID:
+ iOSManualSigningProvisioningProfileType: 0
+ tvOSManualSigningProvisioningProfileType: 0
+ appleEnableAutomaticSigning: 0
+ iOSRequireARKit: 0
+ iOSAutomaticallyDetectAndAddCapabilities: 1
+ appleEnableProMotion: 0
+ shaderPrecisionModel: 0
+ clonedFromGUID: c0afd0d1d80e3634a9dac47e8a0426ea
+ templatePackageId: com.unity.template.3d@5.0.4
+ templateDefaultScene: Assets/Scenes/SampleScene.unity
+ useCustomMainManifest: 0
+ useCustomLauncherManifest: 0
+ useCustomMainGradleTemplate: 0
+ useCustomLauncherGradleManifest: 0
+ useCustomBaseGradleTemplate: 0
+ useCustomGradlePropertiesTemplate: 0
+ useCustomProguardFile: 0
+ AndroidTargetArchitectures: 1
+ AndroidSplashScreenScale: 0
+ androidSplashScreen: {fileID: 0}
+ AndroidKeystoreName:
+ AndroidKeyaliasName:
+ AndroidBuildApkPerCpuArchitecture: 0
+ AndroidTVCompatibility: 0
+ AndroidIsGame: 1
+ AndroidEnableTango: 0
+ androidEnableBanner: 1
+ androidUseLowAccuracyLocation: 0
+ androidUseCustomKeystore: 0
+ m_AndroidBanners:
+ - width: 320
+ height: 180
+ banner: {fileID: 0}
+ androidGamepadSupportLevel: 0
+ AndroidMinifyWithR8: 0
+ AndroidMinifyRelease: 0
+ AndroidMinifyDebug: 0
+ AndroidValidateAppBundleSize: 1
+ AndroidAppBundleSizeToValidate: 150
+ m_BuildTargetIcons: []
+ m_BuildTargetPlatformIcons: []
+ m_BuildTargetBatching:
+ - m_BuildTarget: Standalone
+ m_StaticBatching: 1
+ m_DynamicBatching: 0
+ - m_BuildTarget: tvOS
+ m_StaticBatching: 1
+ m_DynamicBatching: 0
+ - m_BuildTarget: Android
+ m_StaticBatching: 1
+ m_DynamicBatching: 0
+ - m_BuildTarget: iPhone
+ m_StaticBatching: 1
+ m_DynamicBatching: 0
+ - m_BuildTarget: WebGL
+ m_StaticBatching: 0
+ m_DynamicBatching: 0
+ m_BuildTargetGraphicsJobs:
+ - m_BuildTarget: MacStandaloneSupport
+ m_GraphicsJobs: 0
+ - m_BuildTarget: Switch
+ m_GraphicsJobs: 1
+ - m_BuildTarget: MetroSupport
+ m_GraphicsJobs: 1
+ - m_BuildTarget: AppleTVSupport
+ m_GraphicsJobs: 0
+ - m_BuildTarget: BJMSupport
+ m_GraphicsJobs: 1
+ - m_BuildTarget: LinuxStandaloneSupport
+ m_GraphicsJobs: 1
+ - m_BuildTarget: PS4Player
+ m_GraphicsJobs: 1
+ - m_BuildTarget: iOSSupport
+ m_GraphicsJobs: 0
+ - m_BuildTarget: WindowsStandaloneSupport
+ m_GraphicsJobs: 1
+ - m_BuildTarget: XboxOnePlayer
+ m_GraphicsJobs: 1
+ - m_BuildTarget: LuminSupport
+ m_GraphicsJobs: 0
+ - m_BuildTarget: AndroidPlayer
+ m_GraphicsJobs: 0
+ - m_BuildTarget: WebGLSupport
+ m_GraphicsJobs: 0
+ m_BuildTargetGraphicsJobMode:
+ - m_BuildTarget: PS4Player
+ m_GraphicsJobMode: 0
+ - m_BuildTarget: XboxOnePlayer
+ m_GraphicsJobMode: 0
+ m_BuildTargetGraphicsAPIs:
+ - m_BuildTarget: AndroidPlayer
+ m_APIs: 150000000b000000
+ m_Automatic: 0
+ - m_BuildTarget: iOSSupport
+ m_APIs: 10000000
+ m_Automatic: 1
+ - m_BuildTarget: AppleTVSupport
+ m_APIs: 10000000
+ m_Automatic: 1
+ - m_BuildTarget: WebGLSupport
+ m_APIs: 0b000000
+ m_Automatic: 1
+ m_BuildTargetVRSettings:
+ - m_BuildTarget: Standalone
+ m_Enabled: 0
+ m_Devices:
+ - Oculus
+ - OpenVR
+ openGLRequireES31: 0
+ openGLRequireES31AEP: 0
+ openGLRequireES32: 0
+ m_TemplateCustomTags: {}
+ mobileMTRendering:
+ Android: 1
+ iPhone: 1
+ tvOS: 1
+ m_BuildTargetGroupLightmapEncodingQuality: []
+ m_BuildTargetGroupLightmapSettings: []
+ m_BuildTargetNormalMapEncoding: []
+ playModeTestRunnerEnabled: 0
+ runPlayModeTestAsEditModeTest: 0
+ actionOnDotNetUnhandledException: 1
+ enableInternalProfiler: 0
+ logObjCUncaughtExceptions: 1
+ enableCrashReportAPI: 0
+ cameraUsageDescription:
+ locationUsageDescription:
+ microphoneUsageDescription:
+ switchNMETAOverride:
+ switchNetLibKey:
+ switchSocketMemoryPoolSize: 6144
+ switchSocketAllocatorPoolSize: 128
+ switchSocketConcurrencyLimit: 14
+ switchScreenResolutionBehavior: 2
+ switchUseCPUProfiler: 0
+ switchUseGOLDLinker: 0
+ switchApplicationID: 0x01004b9000490000
+ switchNSODependencies:
+ switchTitleNames_0:
+ switchTitleNames_1:
+ switchTitleNames_2:
+ switchTitleNames_3:
+ switchTitleNames_4:
+ switchTitleNames_5:
+ switchTitleNames_6:
+ switchTitleNames_7:
+ switchTitleNames_8:
+ switchTitleNames_9:
+ switchTitleNames_10:
+ switchTitleNames_11:
+ switchTitleNames_12:
+ switchTitleNames_13:
+ switchTitleNames_14:
+ switchPublisherNames_0:
+ switchPublisherNames_1:
+ switchPublisherNames_2:
+ switchPublisherNames_3:
+ switchPublisherNames_4:
+ switchPublisherNames_5:
+ switchPublisherNames_6:
+ switchPublisherNames_7:
+ switchPublisherNames_8:
+ switchPublisherNames_9:
+ switchPublisherNames_10:
+ switchPublisherNames_11:
+ switchPublisherNames_12:
+ switchPublisherNames_13:
+ switchPublisherNames_14:
+ switchIcons_0: {fileID: 0}
+ switchIcons_1: {fileID: 0}
+ switchIcons_2: {fileID: 0}
+ switchIcons_3: {fileID: 0}
+ switchIcons_4: {fileID: 0}
+ switchIcons_5: {fileID: 0}
+ switchIcons_6: {fileID: 0}
+ switchIcons_7: {fileID: 0}
+ switchIcons_8: {fileID: 0}
+ switchIcons_9: {fileID: 0}
+ switchIcons_10: {fileID: 0}
+ switchIcons_11: {fileID: 0}
+ switchIcons_12: {fileID: 0}
+ switchIcons_13: {fileID: 0}
+ switchIcons_14: {fileID: 0}
+ switchSmallIcons_0: {fileID: 0}
+ switchSmallIcons_1: {fileID: 0}
+ switchSmallIcons_2: {fileID: 0}
+ switchSmallIcons_3: {fileID: 0}
+ switchSmallIcons_4: {fileID: 0}
+ switchSmallIcons_5: {fileID: 0}
+ switchSmallIcons_6: {fileID: 0}
+ switchSmallIcons_7: {fileID: 0}
+ switchSmallIcons_8: {fileID: 0}
+ switchSmallIcons_9: {fileID: 0}
+ switchSmallIcons_10: {fileID: 0}
+ switchSmallIcons_11: {fileID: 0}
+ switchSmallIcons_12: {fileID: 0}
+ switchSmallIcons_13: {fileID: 0}
+ switchSmallIcons_14: {fileID: 0}
+ switchManualHTML:
+ switchAccessibleURLs:
+ switchLegalInformation:
+ switchMainThreadStackSize: 1048576
+ switchPresenceGroupId:
+ switchLogoHandling: 0
+ switchReleaseVersion: 0
+ switchDisplayVersion: 1.0.0
+ switchStartupUserAccount: 0
+ switchTouchScreenUsage: 0
+ switchSupportedLanguagesMask: 0
+ switchLogoType: 0
+ switchApplicationErrorCodeCategory:
+ switchUserAccountSaveDataSize: 0
+ switchUserAccountSaveDataJournalSize: 0
+ switchApplicationAttribute: 0
+ switchCardSpecSize: -1
+ switchCardSpecClock: -1
+ switchRatingsMask: 0
+ switchRatingsInt_0: 0
+ switchRatingsInt_1: 0
+ switchRatingsInt_2: 0
+ switchRatingsInt_3: 0
+ switchRatingsInt_4: 0
+ switchRatingsInt_5: 0
+ switchRatingsInt_6: 0
+ switchRatingsInt_7: 0
+ switchRatingsInt_8: 0
+ switchRatingsInt_9: 0
+ switchRatingsInt_10: 0
+ switchRatingsInt_11: 0
+ switchRatingsInt_12: 0
+ switchLocalCommunicationIds_0:
+ switchLocalCommunicationIds_1:
+ switchLocalCommunicationIds_2:
+ switchLocalCommunicationIds_3:
+ switchLocalCommunicationIds_4:
+ switchLocalCommunicationIds_5:
+ switchLocalCommunicationIds_6:
+ switchLocalCommunicationIds_7:
+ switchParentalControl: 0
+ switchAllowsScreenshot: 1
+ switchAllowsVideoCapturing: 1
+ switchAllowsRuntimeAddOnContentInstall: 0
+ switchDataLossConfirmation: 0
+ switchUserAccountLockEnabled: 0
+ switchSystemResourceMemory: 16777216
+ switchSupportedNpadStyles: 22
+ switchNativeFsCacheSize: 32
+ switchIsHoldTypeHorizontal: 0
+ switchSupportedNpadCount: 8
+ switchSocketConfigEnabled: 0
+ switchTcpInitialSendBufferSize: 32
+ switchTcpInitialReceiveBufferSize: 64
+ switchTcpAutoSendBufferSizeMax: 256
+ switchTcpAutoReceiveBufferSizeMax: 256
+ switchUdpSendBufferSize: 9
+ switchUdpReceiveBufferSize: 42
+ switchSocketBufferEfficiency: 4
+ switchSocketInitializeEnabled: 1
+ switchNetworkInterfaceManagerInitializeEnabled: 1
+ switchPlayerConnectionEnabled: 1
+ switchUseNewStyleFilepaths: 0
+ ps4NPAgeRating: 12
+ ps4NPTitleSecret:
+ ps4NPTrophyPackPath:
+ ps4ParentalLevel: 11
+ ps4ContentID: ED1633-NPXX51362_00-0000000000000000
+ ps4Category: 0
+ ps4MasterVersion: 01.00
+ ps4AppVersion: 01.00
+ ps4AppType: 0
+ ps4ParamSfxPath:
+ ps4VideoOutPixelFormat: 0
+ ps4VideoOutInitialWidth: 1920
+ ps4VideoOutBaseModeInitialWidth: 1920
+ ps4VideoOutReprojectionRate: 60
+ ps4PronunciationXMLPath:
+ ps4PronunciationSIGPath:
+ ps4BackgroundImagePath:
+ ps4StartupImagePath:
+ ps4StartupImagesFolder:
+ ps4IconImagesFolder:
+ ps4SaveDataImagePath:
+ ps4SdkOverride:
+ ps4BGMPath:
+ ps4ShareFilePath:
+ ps4ShareOverlayImagePath:
+ ps4PrivacyGuardImagePath:
+ ps4ExtraSceSysFile:
+ ps4NPtitleDatPath:
+ ps4RemotePlayKeyAssignment: -1
+ ps4RemotePlayKeyMappingDir:
+ ps4PlayTogetherPlayerCount: 0
+ ps4EnterButtonAssignment: 1
+ ps4ApplicationParam1: 0
+ ps4ApplicationParam2: 0
+ ps4ApplicationParam3: 0
+ ps4ApplicationParam4: 0
+ ps4DownloadDataSize: 0
+ ps4GarlicHeapSize: 2048
+ ps4ProGarlicHeapSize: 2560
+ playerPrefsMaxSize: 32768
+ ps4Passcode: frAQBc8Wsa1xVPfvJcrgRYwTiizs2trQ
+ ps4pnSessions: 1
+ ps4pnPresence: 1
+ ps4pnFriends: 1
+ ps4pnGameCustomData: 1
+ playerPrefsSupport: 0
+ enableApplicationExit: 0
+ resetTempFolder: 1
+ restrictedAudioUsageRights: 0
+ ps4UseResolutionFallback: 0
+ ps4ReprojectionSupport: 0
+ ps4UseAudio3dBackend: 0
+ ps4UseLowGarlicFragmentationMode: 1
+ ps4SocialScreenEnabled: 0
+ ps4ScriptOptimizationLevel: 0
+ ps4Audio3dVirtualSpeakerCount: 14
+ ps4attribCpuUsage: 0
+ ps4PatchPkgPath:
+ ps4PatchLatestPkgPath:
+ ps4PatchChangeinfoPath:
+ ps4PatchDayOne: 0
+ ps4attribUserManagement: 0
+ ps4attribMoveSupport: 0
+ ps4attrib3DSupport: 0
+ ps4attribShareSupport: 0
+ ps4attribExclusiveVR: 0
+ ps4disableAutoHideSplash: 0
+ ps4videoRecordingFeaturesUsed: 0
+ ps4contentSearchFeaturesUsed: 0
+ ps4CompatibilityPS5: 0
+ ps4GPU800MHz: 1
+ ps4attribEyeToEyeDistanceSettingVR: 0
+ ps4IncludedModules: []
+ ps4attribVROutputEnabled: 0
+ monoEnv:
+ splashScreenBackgroundSourceLandscape: {fileID: 0}
+ splashScreenBackgroundSourcePortrait: {fileID: 0}
+ blurSplashScreenBackground: 1
+ spritePackerPolicy:
+ webGLMemorySize: 16
+ webGLExceptionSupport: 1
+ webGLNameFilesAsHashes: 0
+ webGLDataCaching: 1
+ webGLDebugSymbols: 0
+ webGLEmscriptenArgs:
+ webGLModulesDirectory:
+ webGLTemplate: APPLICATION:Default
+ webGLAnalyzeBuildSize: 0
+ webGLUseEmbeddedResources: 0
+ webGLCompressionFormat: 1
+ webGLWasmArithmeticExceptions: 0
+ webGLLinkerTarget: 1
+ webGLThreadsSupport: 0
+ webGLDecompressionFallback: 0
+ scriptingDefineSymbols:
+ 1: INTEGRATION_TEST
+ additionalCompilerArguments:
+ 1: []
+ platformArchitecture: {}
+ scriptingBackend: {}
+ il2cppCompilerConfiguration: {}
+ managedStrippingLevel: {}
+ incrementalIl2cppBuild: {}
+ suppressCommonWarnings: 1
+ allowUnsafeCode: 0
+ useDeterministicCompilation: 1
+ useReferenceAssemblies: 1
+ enableRoslynAnalyzers: 1
+ additionalIl2CppArgs:
+ scriptingRuntimeVersion: 1
+ gcIncremental: 1
+ gcWBarrierValidation: 0
+ apiCompatibilityLevelPerPlatform:
+ Standalone: 3
+ m_RenderingPath: 1
+ m_MobileRenderingPath: 1
+ metroPackageName: Template_3D
+ metroPackageVersion:
+ metroCertificatePath:
+ metroCertificatePassword:
+ metroCertificateSubject:
+ metroCertificateIssuer:
+ metroCertificateNotAfter: 0000000000000000
+ metroApplicationDescription: Template_3D
+ wsaImages: {}
+ metroTileShortName:
+ metroTileShowName: 0
+ metroMediumTileShowName: 0
+ metroLargeTileShowName: 0
+ metroWideTileShowName: 0
+ metroSupportStreamingInstall: 0
+ metroLastRequiredScene: 0
+ metroDefaultTileSize: 1
+ metroTileForegroundText: 2
+ metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 0}
+ metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628, a: 1}
+ metroSplashScreenUseBackgroundColor: 0
+ platformCapabilities: {}
+ metroTargetDeviceFamilies: {}
+ metroFTAName:
+ metroFTAFileTypes: []
+ metroProtocolName:
+ XboxOneProductId:
+ XboxOneUpdateKey:
+ XboxOneSandboxId:
+ XboxOneContentId:
+ XboxOneTitleId:
+ XboxOneSCId:
+ XboxOneGameOsOverridePath:
+ XboxOnePackagingOverridePath:
+ XboxOneAppManifestOverridePath:
+ XboxOneVersion: 1.0.0.0
+ XboxOnePackageEncryption: 0
+ XboxOnePackageUpdateGranularity: 2
+ XboxOneDescription:
+ XboxOneLanguage:
+ - enus
+ XboxOneCapability: []
+ XboxOneGameRating: {}
+ XboxOneIsContentPackage: 0
+ XboxOneEnableGPUVariability: 1
+ XboxOneSockets: {}
+ XboxOneSplashScreen: {fileID: 0}
+ XboxOneAllowedProductIds: []
+ XboxOnePersistentLocalStorageSize: 0
+ XboxOneXTitleMemory: 8
+ XboxOneOverrideIdentityName:
+ XboxOneOverrideIdentityPublisher:
+ vrEditorSettings: {}
+ cloudServicesEnabled:
+ UNet: 1
+ luminIcon:
+ m_Name:
+ m_ModelFolderPath:
+ m_PortalFolderPath:
+ luminCert:
+ m_CertPath:
+ m_SignPackage: 1
+ luminIsChannelApp: 0
+ luminVersion:
+ m_VersionCode: 1
+ m_VersionName:
+ apiCompatibilityLevel: 6
+ activeInputHandler: 0
+ cloudProjectId:
+ framebufferDepthMemorylessMode: 0
+ qualitySettingsNames: []
+ projectName:
+ organizationId:
+ cloudEnabled: 0
+ legacyClampBlendShapeWeights: 0
+ virtualTexturingSupportEnabled: 0
diff --git a/.yamato/PickAndPlaceTests/set-up-integration-tests.py b/.yamato/PickAndPlaceTests/set-up-integration-tests.py
new file mode 100644
index 00000000..e224f421
--- /dev/null
+++ b/.yamato/PickAndPlaceTests/set-up-integration-tests.py
@@ -0,0 +1,66 @@
+import os
+import shutil
+import glob
+from collections import OrderedDict
+from unityparser import UnityDocument
+
+# NOTE: This must match the flag defined in the Unity Integration Tests
+_INTEGRATION_TEST_DEFINE = "INTEGRATION_TEST"
+
+# This script is executed inside of a bokken image in order to automate the manual steps a user would
+# perform when going through the tutorials. This allows us to perform integration tests on the expected final
+# state of a tutorial project.
+
+
+script_dir = os.path.dirname(os.path.realpath(__file__))
+root_dir = os.path.join(script_dir, "..", "..", "tutorials", "pick_and_place")
+external_scripts_dir = os.path.join(root_dir, "Scripts")
+project_dir = os.path.join(root_dir, "PickAndPlaceProject")
+project_scripts_dir = os.path.join(project_dir, "Assets", "Scripts")
+# project_settings_file = os.path.join(project_dir, "ProjectSettings", "ProjectSettings.asset")
+
+scripts_to_move = glob.glob(os.path.join(external_scripts_dir, "*.cs"))
+for external_script in scripts_to_move:
+ script_name = os.path.basename(external_script)
+ script_destination = os.path.join(project_scripts_dir, script_name)
+ print(f">>> Copying {external_script} to {script_destination}")
+ shutil.copyfile(external_script, script_destination)
+
+files_to_cat = []
+message_dir = os.path.join(project_dir, "Assets", "RosMessages")
+print(f">>> Files in {message_dir}:")
+for root, _, files in os.walk(message_dir):
+ level = root.replace(message_dir, '').count(os.sep)
+ indent = ' ' * 4 * level
+ print('{}{}/'.format(indent, os.path.basename(root)))
+ subindent = ' ' * 4 * (level + 1)
+ for f in files:
+ print('{}{}'.format(subindent, f))
+ if f.endswith(".cs") or f.endswith(".asmdef"):
+ files_to_cat.append(os.path.join(root, f))
+
+# On Yamato, Unity fails to recompile the message directory under mysterious circumstances, so moving it into
+# the Scripts directory to attempt to force a recompile
+print(f"Moving {message_dir} to {project_scripts_dir}")
+shutil.move(message_dir, project_scripts_dir)
+
+# for f in files_to_cat:
+# print(f">>> {f}:")
+# os.system(f"cat {f}")
+# print("\n")
+
+# We must keep a backup copy of the ProjectSettings.asset because UTR will serialize the one in the project as a binary
+# file, making it impossible to load as a yaml file here
+test_settings = os.path.join(".", ".yamato", "PickAndPlaceTests", "IntegrationTestSettings.asset")
+project_settings_relative = os.path.join(".", "tutorials", "pick_and_place", "PickAndPlaceProject", "ProjectSettings", "ProjectSettings.asset")
+shutil.copyfile(test_settings, project_settings_relative)
+
+# TODO: We have to use the above, bad solution, for now, because the below solution won't work until
+# UTR stops re-serializing the settings
+# project_settings_asset = UnityDocument.load_yaml(project_settings_file)
+# scripting_defines = project_settings_asset.entry.scriptingDefineSymbols # type: OrderedDict
+# if scripting_defines[1]:
+# scripting_defines[1] += f";{_INTEGRATION_TEST_DEFINE}"
+# else:
+# scripting_defines[1] = _INTEGRATION_TEST_DEFINE
+# project_settings_asset.dump_yaml()
diff --git a/.yamato/PickAndPlaceTests/start-ros.bash b/.yamato/PickAndPlaceTests/start-ros.bash
new file mode 100644
index 00000000..d50145b2
--- /dev/null
+++ b/.yamato/PickAndPlaceTests/start-ros.bash
@@ -0,0 +1,11 @@
+source /opt/ros/noetic/setup.bash
+
+set -e
+
+# Assuming this script is invoked from the root of the repository...
+DIR_ORIGINAL=$PWD
+cd tutorials/pick_and_place/ROS
+catkin_make
+source devel/setup.bash
+cd "$DIR_ORIGINAL"
+roslaunch niryo_moveit part_3.launch &
diff --git a/.yamato/yamato-config.yml b/.yamato/yamato-config.yml
index 6c5eea4d..e08dd9d2 100644
--- a/.yamato/yamato-config.yml
+++ b/.yamato/yamato-config.yml
@@ -1,30 +1,41 @@
name: Robotics Hub Tests
agent:
- type: Unity::VM
- image: robotics/ci-ubuntu20:latest
- flavor: i1.large
+ type: Unity::VM
+ image: robotics/ci-ubuntu20:v0.1.0pnp-796097
+ flavor: i1.large
variables:
- PATH: /root/.local/bin:/home/bokken/bin:/home/bokken/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/sbin:/home/bokken/.npm-global/bin
+ PATH: /root/.local/bin:/home/bokken/bin:/home/bokken/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/sbin:/home/bokken/.npm-global/bin
commands:
- - git submodule update --init --recursive
- # TODO: Fix this hack - our bokken image is missing a .NET dependency (System.CodeDom) without which causes compilation to fail
- - rm ./tutorials/pick_and_place/PickAndPlaceProject/Assets/DemoScripts/Demo.*
- # This is another hack to ensure audio is disabled. Unity built-in audio fails to initialize in our Bokken image.
- - "sed -i -e '/m_DisableAudio/ s/: .*/: 1/' ./tutorials/pick_and_place/PickAndPlaceProject/ProjectSettings/AudioManager.asset"
- - python3 -m pip install unity-downloader-cli --index-url https://artifactory.prd.it.unity3d.com/artifactory/api/pypi/pypi/simple --upgrade
- - unity-downloader-cli -u 2020.2.0b9 -c editor -c StandaloneSupport-IL2CPP -c Linux --wait --published
- - git clone git@github.cds.internal.unity3d.com:unity/utr.git utr
- - utr/utr --testproject=./tutorials/pick_and_place/PickAndPlaceProject --editor-location=.Editor --reruncount=0 --artifacts_path=test-results --suite=playmode --suite=editor --platform=Editor --editorTestsCategories MessageGeneration
- - mkdir -p ./tutorials/pick_and_place/PickAndPlaceProject/Assets/Scripts && cp ./tutorials/pick_and_place/Scripts/*.cs ./tutorials/pick_and_place/PickAndPlaceProject/Assets
- - utr/utr --testproject=./tutorials/pick_and_place/PickAndPlaceProject --editor-location=.Editor --reruncount=0 --artifacts_path=test-results --suite=playmode --suite=editor --platform=Editor --editorTestsCategories BuildTests
+ - git submodule update --init --recursive
+ # We must remove the Demo.cs script because the System.CodeDom assembly is not in the bokken .NET sdk
+ - rm ./tutorials/pick_and_place/PickAndPlaceProject/Assets/DemoScripts/Demo.*
+ # Ensure audio is disabled. Unity built-in audio fails to initialize in our Bokken image.
+ - "sed -i -e '/m_DisableAudio/ s/: .*/: 1/' ./tutorials/pick_and_place/PickAndPlaceProject/ProjectSettings/AudioManager.asset"
+ - python3 -m pip install unity-downloader-cli --index-url https://artifactory.prd.it.unity3d.com/artifactory/api/pypi/pypi/simple --upgrade
+ - unity-downloader-cli -u 2020.3.11f1 -c editor -c StandaloneSupport-IL2CPP -c Linux --wait --published
+ - git clone git@github.cds.internal.unity3d.com:unity/utr.git utr
+ # Explicitly run MessageGeneration tests first to generate dependencies
+ - utr/utr --testproject=./tutorials/pick_and_place/PickAndPlaceProject --editor-location=.Editor --reruncount=0
+ --artifacts_path=test-results --suite=editor --platform=Editor --editorTestsCategories
+ MessageGeneration
+ # Run each category of tests in its own process, in order of increasing complexity
+ - utr/utr --testproject=./tutorials/pick_and_place/PickAndPlaceProject --editor-location=.Editor --reruncount=0
+ --artifacts_path=test-results --suite=playmode --suite=editor --platform=Editor --editorTestCategories UnitTests
+ # - utr/utr --testproject=./tutorials/pick_and_place/PickAndPlaceProject --editor-location=.Editor --reruncount=0
+ #--artifacts_path=test-results --suite=editor --platform=Editor --testfilter BuildTests.PlayerBuilder.BuildPlayerLinux
+ - python3 .yamato/PickAndPlaceTests/set-up-integration-tests.py
+ #TODO: Determine how best to capture ROS logging as test artifacts
+ - /bin/bash .yamato/PickAndPlaceTests/start-ros.bash
+ # NOTE: Simply specifying the testCategory is not enough to get a test marked with [Explicit] to run
+ - utr/utr --testproject=./tutorials/pick_and_place/PickAndPlaceProject --editor-location=.Editor --reruncount=0
+ --artifacts_path=test-results --suite=editor --platform=Editor --testfilter IntegrationTests.RosIntegrationTests
+ #TODO: Determine when it would be prudent to run BuildTests and add them here or in a new config
triggers:
- cancel_old_ci: true
- expression: |
- (pull_request.target eq "main" AND
- NOT pull_request.push.changes.all match ["**/*.md","**/*.jpg","**/*.jpeg","**/*.gif","**/*.pdf"]) OR
- (push.branch eq "dev" AND
- NOT push.changes.all match ["**/*.md","**/*.jpg","**/*.jpeg","**/*.gif","**/*.pdf"])
+ cancel_old_ci: true
+ expression: |
+ (pull_request.target in ["main", "dev"] AND
+ NOT pull_request.changes.all match ["**/*.md","**/*.jpg","**/*.jpeg","**/*.gif","**/*.pdf"])
artifacts:
- logs:
- paths:
- - "test-results/**/*"
+ logs:
+ paths:
+ - "test-results/**/*"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 40da5b13..734b52cb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
### Changed
+Changed the Pick and Place Demo's topic from SourceDestination to SourceDestination_input
+
### Deprecated
### Removed
diff --git a/README.md b/README.md
index 0e39bc8d..c7d552c0 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,12 @@
# Unity Robotics Hub
-[](https://opensource.org/licenses/Apache-2.0)
+[](https://github.com/Unity-Technologies/Unity-Robotics-Hub/releases)
+[](LICENSE.md)
+
+
+
+
This is a central repository for tools, tutorials, resources, and documentation for robotic simulation in Unity.
diff --git a/Third Party Notices.md b/Third Party Notices.md
index 184bb758..f74aff6b 100644
--- a/Third Party Notices.md
+++ b/Third Party Notices.md
@@ -1,22 +1,27 @@
-Component Name: ROS# (siemens/ros-sharp)
+Component name: ROS# (siemens/ros-sharp)
-License Type: Apache 2.0
+License Type: Apache 2.0
-Copyright 2017-2020 Siemens AG
+Copyright 2017-2020 Siemens AG
```
-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
+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.
+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.
```
---
-Component Name: Niryo One ROS Stack (niryo_one_ros/niryo_one_description)
+Component Name: Niryo One ROS Stack (niryo_one_ros/niryo_one_description)
-License Type: GPLv3
+License Type: GPLv3
```
Copyright (C) 2017 Niryo
@@ -36,3 +41,37 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
```
+---
+
+Component Name: MoveIt Msgs (ros-planning/moveit_msgs)
+
+License Type: BSD 3-clause
+
+```
+Copyright (c)
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ Neither the name of the copyright holder nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+```
diff --git a/tutorials/pick_and_place/1_urdf.md b/tutorials/pick_and_place/1_urdf.md
index aaaa30b4..7b869796 100644
--- a/tutorials/pick_and_place/1_urdf.md
+++ b/tutorials/pick_and_place/1_urdf.md
@@ -22,9 +22,14 @@ This part includes downloading and installing the Unity Editor, setting up a bas
1. Install [Unity Hub](https://unity3d.com/get-unity/download).
-1. Go to the [Unity 2020.2 Beta website](https://unity3d.com/unity/beta/2020.2.0b9) to install this project's version of Unity: **2020.2.0b9**.
+1. Go it the "Installs" tab in the Unity Hub, and click the "Add" button. Select Unity **2020.3.11f1 (LTS)**. If this version is no longer available through the hub, you can find it in the [Unity Download Archive](https://unity3d.com/get-unity/download/archive).
+ > Note: If you want to use another Unity version, the following versions work for the Pick-and-Place tutorial:
-1. Click the "Add" button in the top right of the "Projects" tab on Unity Hub, and navigate to and select the PickAndPlaceProject directory within this cloned repository (`/PATH/TO/Unity-Robotics-Hub/tutorials/pick_and_place/PickAndPlaceProject/`) to add the tutorial project to your Hub.
+ > - Unity 2020.3: 2020.3.10f1 or later
+ > - Unity 2021.1: 2021.1.8f1 or later
+ > - Unity 2021.2: 2021.2.a16 or later
+
+1. Go to the "Projects" tab in the Unity Hub, click the "Add" button, and navigate to and select the PickAndPlaceProject directory within this cloned repository (`/PATH/TO/Unity-Robotics-Hub/tutorials/pick_and_place/PickAndPlaceProject/`) to add the tutorial project to your Hub.

diff --git a/tutorials/pick_and_place/2_ros_tcp.md b/tutorials/pick_and_place/2_ros_tcp.md
index b92620e0..acaa7ae1 100644
--- a/tutorials/pick_and_place/2_ros_tcp.md
+++ b/tutorials/pick_and_place/2_ros_tcp.md
@@ -47,6 +47,8 @@ To enable communication between Unity and ROS, a TCP endpoint running as a ROS n
In the ROS Message Browser window, click `Browse` next to the ROS message path. Navigate to and select the ROS directory of this cloned repository (`Unity-Robotics-Hub/tutorials/pick_and_place/ROS/`). This window will populate with all msg and srv files found in this directory.
+ In the ROS Message Browser window, type in `Scripts/RosMessages` in the text field of Build message path.
+

> Note: If any of these ROS directories appear to be empty, you can run the command `git submodule update --init --recursive` to download the packages via Git submodules.
@@ -55,7 +57,7 @@ To enable communication between Unity and ROS, a TCP endpoint running as a ROS n

- - One new C# script should populate the `Assets/RosMessages/Moveit/msg` directory: MRobotTrajectory. This name is the same as the message you built, with an "M" prefix (for message).
+ - One new C# script should populate the `Assets/RosMessages/Moveit/msg` directory: RobotTrajectoryMsg.cs. This name is the same as the message you built, with an "Msg" suffix (for message).
1. Next, the custom message scripts for this tutorial will need to be generated.
@@ -63,7 +65,7 @@ To enable communication between Unity and ROS, a TCP endpoint running as a ROS n

- - Two new C# scripts should populate the `Assets/RosMessages/NiryoMoveit/msg` directory: MNiryoMoveitJoints and MNiryoTrajectory. MNiryoMoveitJoints describes a value for each joint in the Niryo arm as well as poses for the target object and target goal. MNiryoTrajectory describes a list of RobotTrajectory values, which will hold the calculated trajectories for the pick-and-place task.
+ - Two new C# scripts should populate the `Assets/RosMessages/NiryoMoveit/msg` directory: NiryoMoveitJointsMsg.cs and NiryoTrajectoryMsg.cs. The NiryoMoveitJoints message describes a value for each joint in the Niryo arm as well as poses for the target object and target goal. NiryoTrajectory describes a list of RobotTrajectory values, which will hold the calculated trajectories for the pick-and-place task.
> MessageGeneration generates a C# class from a ROS msg file with protections for use of C# reserved keywords and conversion to C# datatypes. Learn more about [ROS Messages](https://wiki.ros.org/Messages).
@@ -73,7 +75,7 @@ To enable communication between Unity and ROS, a TCP endpoint running as a ROS n

- - Two new C# scripts should populate the `Assets/RosMessages/NiryoMoveit/srv` directory: MMoverServiceRequest and MMoverServiceResponse. These files describe the expected input and output formats for the service requests and responses when calculating trajectories.
+ - Two new C# scripts should populate the `Assets/RosMessages/NiryoMoveit/srv` directory: MoverServiceRequest and MoverServiceResponse. These files describe the expected input and output formats for the service requests and responses when calculating trajectories.
> MessageGeneration generates two C# classes, a request and response, from a ROS srv file with protections for use of C# reserved keywords and conversion to C# datatypes. Learn more about [ROS Services](https://wiki.ros.org/Services).
@@ -86,7 +88,7 @@ To enable communication between Unity and ROS, a TCP endpoint running as a ROS n
```csharp
public void Publish()
{
- MNiryoMoveitJoints sourceDestinationMessage = new MNiryoMoveitJoints();
+ NiryoMoveitJointsMsg sourceDestinationMessage = new NiryoMoveitJointsMsg();
sourceDestinationMessage.joint_00 = jointArticulationBodies[0].xDrive.target;
sourceDestinationMessage.joint_01 = jointArticulationBodies[1].xDrive.target;
@@ -96,7 +98,7 @@ To enable communication between Unity and ROS, a TCP endpoint running as a ROS n
sourceDestinationMessage.joint_05 = jointArticulationBodies[5].xDrive.target;
// Pick Pose
- sourceDestinationMessage.pick_pose = new MPose
+ sourceDestinationMessage.pick_pose = new PoseMsg
{
position = target.transform.position.To(),
// The hardcoded x/z angles assure that the gripper is always positioned above the target cube before grasping.
@@ -104,7 +106,7 @@ To enable communication between Unity and ROS, a TCP endpoint running as a ROS n
};
// Place Pose
- sourceDestinationMessage.place_pose = new MPose
+ sourceDestinationMessage.place_pose = new PoseMsg
{
position = targetPlacement.transform.position.To(),
orientation = pickOrientation.To()
@@ -117,7 +119,7 @@ To enable communication between Unity and ROS, a TCP endpoint running as a ROS n
> This function first takes in the current joint target values. Then, it grabs the poses of the `target` and the `targetPlacement` objects, adds them to the newly created message `sourceDestinationMessage`, and calls `Send()` to send this information to the ROS topic `topicName` (defined as `"SourceDestination_input"`).
- > Note: Going from Unity world space to ROS world space requires a conversion. Unity's `(x,y,z)` is equivalent to the ROS `(z,-x,y)` coordinate. These conversions are provided via the [ROSGeometry component](https://github.com/Unity-Technologies/ROS-TCP-Connector/blob/main/ROSGeometry.md) in the ROS-TCP-Connector package.
+ > Note: Going from Unity world space to ROS world space requires a conversion. Unity's coordinate space has x Right, y Up, and z Forward (hence "RUF" coordinates); ROS has x Forward, y Left and z Up (hence "FLU"). So a Unity `(x,y,z)` coordinate is equivalent to the ROS `(z,-x,y)` coordinate. These conversions are done by the `To` function in the ROS-TCP-Connector package's [ROSGeometry component](https://github.com/Unity-Technologies/ROS-TCP-Connector/blob/main/ROSGeometry.md).
1. Return to the Unity Editor. Now that the message contents have been defined and the publisher script added, it needs to be added to the Unity world to run its functionality.
@@ -148,7 +150,7 @@ To enable communication between Unity and ROS, a TCP endpoint running as a ROS n
> Note: While using the ROS Settings menu is the suggested workflow as of this version, you may still manually create a GameObject with an attached ROSConnection component.
-1. Next, we will add a UI element that will allow user input to trigger the `Publish()` function. In the Hierarchy window, right click to add a new UI > Button. Note that this will create a new Canvas parent as well.
+1. Next, we will add a UI element that will allow user input to trigger the `Publish()` function. In the Hierarchy window, right click to add a new UI > Button. Note that this will also create a new Canvas parent, as well as an Event System.
> Note: In the `Game` view, you will see the button appear in the bottom left corner as an overlay. In `Scene` view the button will be rendered on a canvas object that may not be visible.
> Note: In case the Button does not start in the bottom left, it can be moved by setting the `Pos X` and `Pos Y` values in its Rect Transform component. For example, setting its Position to `(-200, -200, 0)` would set its position to the bottom right area of the screen.
@@ -208,6 +210,8 @@ ROS and Unity have now successfully connected!
- If the ROS TCP handshake fails (e.g. `ROS-Unity server listening...` printed on the Unity side but no `ROS-Unity Handshake received` on the ROS side), the ROS IP may not have been set correctly in the params.yaml file. Try running `echo "ROS_IP: $(hostname -I)" > src/niryo_moveit/config/params.yaml` in a terminal from your ROS workspace.
+- If the UI buttons appear to be unresponsive, such as not responding to clicks, ensure there is an [EventSystem](https://docs.unity3d.com/2020.1/Documentation/Manual/UIE-Events.html) in the scene hierarchy. This should be added automatically when adding UI elements, but if it is not, you can add one to your scene from the Hierarchy window via `(+) > UI > Event System`. You can also access this dropdown from right-clicking in an empty area in the Hierarchy window.
+
---
## Resources
diff --git a/tutorials/pick_and_place/3_pick_and_place.md b/tutorials/pick_and_place/3_pick_and_place.md
index eb43dbb9..50925035 100644
--- a/tutorials/pick_and_place/3_pick_and_place.md
+++ b/tutorials/pick_and_place/3_pick_and_place.md
@@ -31,11 +31,11 @@ Steps covered in this tutorial includes invoking a motion planning service in RO
```csharp
public void PublishJoints()
{
- MMoverServiceRequest request = new MMoverServiceRequest();
+ MoverServiceRequest request = new MoverServiceRequest();
request.joints_input = CurrentJointConfig();
// Pick Pose
- request.pick_pose = new MPose
+ request.pick_pose = new PoseMsg
{
position = (target.transform.position + pickPoseOffset).To(),
// The hardcoded x/z angles assure that the gripper is always positioned above the target cube before grasping.
@@ -43,16 +43,16 @@ Steps covered in this tutorial includes invoking a motion planning service in RO
};
// Place Pose
- request.place_pose = new MPose
+ request.place_pose = new PoseMsg
{
position = (targetPlacement.transform.position + pickPoseOffset).To(),
orientation = pickOrientation.To()
};
- ros.SendServiceMessage(rosServiceName, request, TrajectoryResponse);
+ ros.SendServiceMessage(rosServiceName, request, TrajectoryResponse);
}
- void TrajectoryResponse(MMoverServiceResponse response)
+ void TrajectoryResponse(MoverServiceResponse response)
{
if (response.trajectories != null)
{
@@ -71,7 +71,7 @@ Steps covered in this tutorial includes invoking a motion planning service in RO
> The `response.trajectories` are received in the `TrajectoryResponse()` callback, as defined in the `ros.SendServiceMessage` parameters. These trajectories are passed to `ExecuteTrajectories()` and executed as a [coroutine](https://docs.unity3d.com/Manual/Coroutines.html):
```csharp
- private IEnumerator ExecuteTrajectories(MMoverServiceResponse response)
+ private IEnumerator ExecuteTrajectories(MoverServiceResponse response)
{
if (response.trajectories != null)
{
diff --git a/tutorials/pick_and_place/4_pick_and_place.md b/tutorials/pick_and_place/4_pick_and_place.md
index dad4e25f..f23beed4 100644
--- a/tutorials/pick_and_place/4_pick_and_place.md
+++ b/tutorials/pick_and_place/4_pick_and_place.md
@@ -265,7 +265,7 @@ void Start()
- The ExecuteTrajectories function has been updated to accept a single RobotTrajectory object and execute the robot poses one at a time:
```csharp
- private IEnumerator ExecuteTrajectories(RobotTrajectory trajectories)
+ private IEnumerator ExecuteTrajectories(RobotTrajectoryMsg trajectories)
{
// For every robot pose in trajectory plan
foreach (var point in trajectories.joint_trajectory.points)
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/.gitignore b/tutorials/pick_and_place/PickAndPlaceProject/.gitignore
index 39ee8722..f96bc123 100644
--- a/tutorials/pick_and_place/PickAndPlaceProject/.gitignore
+++ b/tutorials/pick_and_place/PickAndPlaceProject/.gitignore
@@ -12,6 +12,12 @@
/[Aa]ssets/[Rr]os[Mm]essages/
/[Aa]ssets/[Rr]os[Mm]essages.meta
+
+# Ignore scripts that are expected to get copied in at some point
+/**/SourceDestinationPublisher.*
+/**/TrajectoryPlanner.*
+
+
# MemoryCaptures can get excessive in size.
# They also could contain extremely sensitive data
/[Mm]emoryCaptures/
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/DemoScripts/Demo.cs b/tutorials/pick_and_place/PickAndPlaceProject/Assets/DemoScripts/Demo.cs
index c30ea524..4ea42f98 100644
--- a/tutorials/pick_and_place/PickAndPlaceProject/Assets/DemoScripts/Demo.cs
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/DemoScripts/Demo.cs
@@ -6,19 +6,16 @@
using System.IO;
using System.Reflection;
using System.Text;
-using RosSharp;
-using RosSharp.Control;
-using RosSharp.Urdf;
-using RosSharp.Urdf.Editor;
using UnityEditor;
using UnityEngine;
using Unity.Robotics.ROSTCPConnector;
using Unity.Robotics.ROSTCPConnector.MessageGeneration;
+using Unity.Robotics.UrdfImporter;
+using Unity.Robotics.UrdfImporter.Control;
public class Demo : MonoBehaviour
{
public string hostIP = "127.0.0.1";
- public string overrideUnityIP = "127.0.0.1";
public bool generateRosMessages = true;
public bool deleteRosMessagesAfterSimulation = true;
@@ -44,7 +41,7 @@ public class Demo : MonoBehaviour
float controllerSpeed = 30;
float controllerAcceleration = 10;
- string rosMessagesDirectory = "Assets/RosMessages";
+ string rosMessagesDirectory = "Assets/Scripts/RosMessages";
string rosSrcDirectory = "../ROS/src";
string msgDirectory = "msg";
string srvDirectory = "srv";
@@ -54,15 +51,23 @@ public class Demo : MonoBehaviour
string moverServiceFileName = "MoverService.srv";
string scriptPattern = "*.cs";
+ string registerMethodName = "Register";
+ string[] rosGeneratedTypeFullName = new string[]
+ {
+ "RosMessageTypes.Moveit.RobotTrajectoryMsg",
+ "RosMessageTypes.NiryoMoveit.NiryoMoveitJointsMsg",
+ "RosMessageTypes.NiryoMoveit.NiryoTrajectoryMsg",
+ "RosMessageTypes.NiryoMoveit.MoverServiceResponse",
+ "RosMessageTypes.NiryoMoveit.MoverServiceRequest"
+ };
+
+
string externalScriptsDirectory = "../Scripts";
//string scriptsDirectory = "Assets/Scripts";
string rosConnectName = "ROSConnect";
string publisherName = "Publisher";
int hostPort = 10000;
- int unityPort = 5005;
- int awaitDataMaxRetries = 10;
- int awaitDataSleepSeconds = 1;
string trajectoryPlannerType = "TrajectoryPlanner";
string rosServiceName = "niryo_moveit";
@@ -142,6 +147,12 @@ private void AddRosMessages()
scripts.AddRange(Directory.GetFiles(rosMessagesDirectory, scriptPattern, SearchOption.AllDirectories));
scripts.AddRange(Directory.GetFiles(externalScriptsDirectory));
RecompileScripts(scripts.ToArray());
+
+ // Register Ros message names and their deserialize function
+ foreach (var typeFullName in rosGeneratedTypeFullName)
+ {
+ assembly.GetType(typeFullName).GetMethod(registerMethodName).Invoke(null, null);
+ }
}
private void CreateTrajectoryPlannerPublisher()
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/Prefabs/TargetPlacement.prefab b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Prefabs/TargetPlacement.prefab
index c5015a79..29738293 100644
--- a/tutorials/pick_and_place/PickAndPlaceProject/Assets/Prefabs/TargetPlacement.prefab
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Prefabs/TargetPlacement.prefab
@@ -11,6 +11,8 @@ GameObject:
- component: {fileID: 850690186460591411}
- component: {fileID: 850690186460591410}
- component: {fileID: 850690186460591413}
+ - component: {fileID: 4980278694990496136}
+ - component: {fileID: 7978903071639371792}
m_Layer: 0
m_Name: TargetPlacement
m_TagString: Untagged
@@ -81,3 +83,30 @@ MeshRenderer:
m_SortingLayer: 0
m_SortingOrder: 0
m_AdditionalVertexStreams: {fileID: 0}
+--- !u!65 &4980278694990496136
+BoxCollider:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 850690186460591414}
+ m_Material: {fileID: 0}
+ m_IsTrigger: 1
+ m_Enabled: 1
+ serializedVersion: 2
+ m_Size: {x: 1, y: 1.2, z: 1}
+ m_Center: {x: 0, y: 0, z: 0}
+--- !u!114 &7978903071639371792
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 850690186460591414}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: f7ac960dc884b4042a0de8920854c9e5, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Target: {fileID: 0}
+ m_ColorAlpha: 100
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/RosMessages.meta b/tutorials/pick_and_place/PickAndPlaceProject/Assets/RosMessages.meta
new file mode 100644
index 00000000..a9f13ce5
--- /dev/null
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/RosMessages.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 7e9ac35ae6089214eb6d10352af3bc26
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/RosMessages/Unity.Robotics.RosMessages.asmdef b/tutorials/pick_and_place/PickAndPlaceProject/Assets/RosMessages/Unity.Robotics.RosMessages.asmdef
new file mode 100644
index 00000000..51f0522b
--- /dev/null
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/RosMessages/Unity.Robotics.RosMessages.asmdef
@@ -0,0 +1,16 @@
+{
+ "name": "Unity.Robotics.RosMessages",
+ "rootNamespace": "",
+ "references": [
+ "GUID:625bfc588fb96c74696858f2c467e978"
+ ],
+ "includePlatforms": [],
+ "excludePlatforms": [],
+ "allowUnsafeCode": false,
+ "overrideReferences": false,
+ "precompiledReferences": [],
+ "autoReferenced": true,
+ "defineConstraints": [],
+ "versionDefines": [],
+ "noEngineReferences": false
+}
\ No newline at end of file
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/RosMessages/Unity.Robotics.RosMessages.asmdef.meta b/tutorials/pick_and_place/PickAndPlaceProject/Assets/RosMessages/Unity.Robotics.RosMessages.asmdef.meta
new file mode 100644
index 00000000..f38d7320
--- /dev/null
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/RosMessages/Unity.Robotics.RosMessages.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 204b12c73a0ba074c888ec09a2713605
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/Scripts.meta b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Scripts.meta
new file mode 100644
index 00000000..c563aa44
--- /dev/null
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Scripts.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: d4e987dd3f8374e458f751390c3982b8
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/Scripts/TargetPlacement.cs b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Scripts/TargetPlacement.cs
new file mode 100644
index 00000000..6a148660
--- /dev/null
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Scripts/TargetPlacement.cs
@@ -0,0 +1,185 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace Unity.Robotics.PickAndPlace
+{
+
+ [RequireComponent(typeof(MeshRenderer))]
+ [RequireComponent(typeof(BoxCollider))]
+ public class TargetPlacement : MonoBehaviour
+ {
+ const string k_NameExpectedTarget = "Target";
+ static readonly int k_ShaderColorId = Shader.PropertyToID("_Color");
+ // The threshold that the Target's speed must be under to be considered "placed" in the target area
+ const float k_MaximumSpeedForStopped = 0.01f;
+
+ [SerializeField]
+ [Tooltip("Target object expected by this placement area. Can be left blank if only one Target in scene")]
+ GameObject m_Target;
+ [SerializeField]
+ [Range(0, 255)]
+ [Tooltip("Alpha value for any color set during state changes.")]
+ int m_ColorAlpha = 100;
+
+ MeshRenderer m_TargetMeshRenderer;
+
+ float m_ColorAlpha01 => m_ColorAlpha / 255f;
+ MeshRenderer m_MeshRenderer;
+ BoxCollider m_BoxCollider;
+ PlacementState m_CurrentState;
+ PlacementState m_LastColoredState;
+
+ public PlacementState CurrentState
+ {
+ get => m_CurrentState;
+ private set
+ {
+ m_CurrentState = value;
+ UpdateStateColor();
+ }
+ }
+
+ public enum PlacementState
+ {
+ Outside,
+ InsideFloating,
+ InsidePlaced
+ }
+
+ // Start is called before the first frame update
+ void Start()
+ {
+ // Check for mis-configurations and disable if something has changed without this script being updated
+ // These are warnings because this script does not contain critical functionality
+ if (m_Target == null)
+ {
+ m_Target = GameObject.Find(k_NameExpectedTarget);
+ }
+
+ if (m_Target == null)
+ {
+ Debug.LogWarning($"{nameof(TargetPlacement)} expects to find a GameObject named " +
+ $"{k_NameExpectedTarget} to track, but did not. Can't track placement state.");
+ enabled = false;
+ return;
+ }
+
+ if (!TrySetComponentReferences())
+ {
+ enabled = false;
+ return;
+ }
+ InitializeState();
+ }
+
+ bool TrySetComponentReferences()
+ {
+ m_TargetMeshRenderer = m_Target.GetComponent();
+ if (m_TargetMeshRenderer == null)
+ {
+ Debug.LogWarning($"{nameof(TargetPlacement)} expects a {nameof(MeshRenderer)} to be attached " +
+ $"to {k_NameExpectedTarget}. Cannot check bounds without it, so cannot track placement state.");
+ return false;
+ }
+
+ // Assume these are here because they are RequiredComponent components
+ m_MeshRenderer = GetComponent();
+ m_BoxCollider = GetComponent();
+ return true;
+ }
+
+ void OnValidate()
+ {
+ // Useful for visualizing state in editor, but doesn't wholly guarantee accurate coloring in EditMode
+ // Enter PlayMode to see color update correctly
+ if (m_Target != null)
+ {
+ if (TrySetComponentReferences())
+ {
+ InitializeState();
+ }
+ }
+ }
+
+ void InitializeState()
+ {
+ if (m_Target.GetComponent().bounds.Intersects(m_BoxCollider.bounds))
+ {
+ CurrentState = IsTargetStoppedInsideBounds() ?
+ PlacementState.InsidePlaced : PlacementState.InsideFloating;
+ }
+ else
+ {
+ CurrentState = PlacementState.Outside;
+ }
+ }
+
+ void OnTriggerEnter(Collider other)
+ {
+ if (other.gameObject.name == m_Target.name)
+ {
+ CurrentState = PlacementState.InsideFloating;
+ }
+ }
+
+ void OnTriggerExit(Collider other)
+ {
+ if (other.gameObject.name == m_Target.name)
+ {
+ CurrentState = PlacementState.Outside;
+ }
+ }
+
+ bool IsTargetStoppedInsideBounds()
+ {
+ var targetIsStopped = m_Target.GetComponent().velocity.magnitude < k_MaximumSpeedForStopped;
+ var targetIsInBounds = m_BoxCollider.bounds.Contains(m_TargetMeshRenderer.bounds.center);
+
+ return targetIsStopped && targetIsInBounds;
+ }
+
+ // Update is called once per frame
+ void Update()
+ {
+ if (CurrentState != PlacementState.Outside)
+ {
+ CurrentState = IsTargetStoppedInsideBounds() ?
+ PlacementState.InsidePlaced : PlacementState.InsideFloating;
+ }
+ }
+
+ void UpdateStateColor()
+ {
+ if (m_CurrentState == m_LastColoredState)
+ {
+ return;
+ }
+
+ var mpb = new MaterialPropertyBlock();
+ Color stateColor;
+ switch (m_CurrentState)
+ {
+ case PlacementState.Outside:
+ stateColor = Color.red;
+ break;
+ case PlacementState.InsideFloating:
+ stateColor = Color.yellow;
+ break;
+ case PlacementState.InsidePlaced:
+ stateColor = Color.green;
+ break;
+ default:
+ Debug.LogError($"No state handling implemented for {m_CurrentState}");
+ stateColor = Color.magenta;
+ break;
+ }
+
+ stateColor.a = m_ColorAlpha01;
+ mpb.SetColor(k_ShaderColorId, stateColor);
+ m_MeshRenderer.SetPropertyBlock(mpb);
+ m_LastColoredState = m_CurrentState;
+ }
+ }
+}
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/Scripts/TargetPlacement.cs.meta b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Scripts/TargetPlacement.cs.meta
new file mode 100644
index 00000000..987a8717
--- /dev/null
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Scripts/TargetPlacement.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f7ac960dc884b4042a0de8920854c9e5
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/Scripts/Unity.Robotics.PickAndPlace.asmdef b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Scripts/Unity.Robotics.PickAndPlace.asmdef
new file mode 100644
index 00000000..239348dc
--- /dev/null
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Scripts/Unity.Robotics.PickAndPlace.asmdef
@@ -0,0 +1,17 @@
+{
+ "name": "Unity.Robotics.PickAndPlace",
+ "rootNamespace": "",
+ "references": [
+ "GUID:204b12c73a0ba074c888ec09a2713605",
+ "GUID:625bfc588fb96c74696858f2c467e978"
+ ],
+ "includePlatforms": [],
+ "excludePlatforms": [],
+ "allowUnsafeCode": false,
+ "overrideReferences": false,
+ "precompiledReferences": [],
+ "autoReferenced": true,
+ "defineConstraints": [],
+ "versionDefines": [],
+ "noEngineReferences": false
+}
\ No newline at end of file
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/Scripts/Unity.Robotics.PickAndPlace.asmdef.meta b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Scripts/Unity.Robotics.PickAndPlace.asmdef.meta
new file mode 100644
index 00000000..bfaf7159
--- /dev/null
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Scripts/Unity.Robotics.PickAndPlace.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 79169c04a5f9b014e919b69ac8df4286
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/EditMode/EditMode.asmdef b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/EditMode/EditMode.asmdef
index 52b1e786..ec396661 100644
--- a/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/EditMode/EditMode.asmdef
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/EditMode/EditMode.asmdef
@@ -2,10 +2,14 @@
"name": "EditMode",
"rootNamespace": "",
"references": [
- "UnityEngine.TestRunner",
- "UnityEditor.TestRunner",
- "Unity.Robotics.ROSTCPConnector.Editor",
- "Unity.Robotics.ROSTCPConnector"
+ "GUID:27619889b8ba8c24980f49ee34dbb44a",
+ "GUID:0acc523941302664db1f4e527237feb3",
+ "GUID:1da8e23352f14494396eac5033ba9894",
+ "GUID:625bfc588fb96c74696858f2c467e978",
+ "GUID:204b12c73a0ba074c888ec09a2713605",
+ "GUID:465c1207fffb96245a352265e7622205",
+ "GUID:b1ef917f7a8a86a4eb639ec2352edbf8",
+ "GUID:79169c04a5f9b014e919b69ac8df4286"
],
"includePlatforms": [
"Editor"
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/EditMode/IntegrationTest.cs b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/EditMode/IntegrationTest.cs
new file mode 100644
index 00000000..47e5a878
--- /dev/null
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/EditMode/IntegrationTest.cs
@@ -0,0 +1,175 @@
+using System;
+using System.Collections;
+using System.IO;
+using NUnit.Framework;
+using Unity.Robotics.PickAndPlace;
+using UnityEngine;
+using Unity.Robotics.ROSTCPConnector;
+using Unity.Robotics.UrdfImporter;
+using Unity.Robotics.UrdfImporter.Control;
+using UnityEditor;
+using UnityEditor.SceneManagement;
+using UnityEngine.TestTools;
+
+namespace IntegrationTests
+{
+ [TestFixture, Explicit, Category("IntegrationTests")]
+ // IMPORTANT: In order for this category of tests to run correctly, MessageGeneration must be run first and the
+ // INTEGRATION_TEST script define must be set
+ public class RosIntegrationTests
+ {
+ #region Parameters
+
+ // Testing parameters
+ const float k_TestTimeoutSeconds = 20f;
+
+ const string k_NamePackageNiryoMoveIt = "niryo_moveit";
+ const string k_NameNiryoOne = "niryo_one";
+ const string k_NameBaseLink = "base_link";
+
+ // Prefabs that get instantiated into scene
+ const string k_NameTable = "Table";
+ const string k_NameTarget = "Target";
+ const string k_NameTargetPlacement = "TargetPlacement";
+
+ // GameObjects that hold important components
+ const string k_NameCamera = "Main Camera";
+ const string k_NameRosConnect = "ROSConnect";
+ const string k_NamePublisher = "Publisher";
+
+ // Parameters for robot joint controller
+ const float k_ControllerStiffness = 10000f;
+ const float k_ControllerDamping = 100f;
+ const float k_ControllerForceLimit = 1000f;
+ const float k_ControllerSpeed = 30f;
+ const float k_ControllerAcceleration = 10f;
+
+ // Parameters for ROS connection
+ const string k_IpAddressLoopback = "127.0.0.1";
+ const int k_HostPort = 10000;
+ const int k_UnityPort = 5005;
+ const int k_NumAwaitDataRetries = 10;
+ const int k_NumAwaitDataSleepSeconds = 1;
+
+ const string k_PrefabSuffix = ".prefab";
+ readonly string k_DirectoryPrefabs = Path.Combine("Assets", "Prefabs");
+ readonly string k_PathUrdf = Path.Combine("URDF", "niryo_one", "niryo_one.urdf");
+ readonly string k_PathTestScene = Path.Combine("Assets", "Scenes", "EmptyScene.unity");
+
+ readonly Vector3 k_CameraPosition = new Vector3(0, 1.4f, -0.7f);
+ readonly Quaternion k_CameraRotation = Quaternion.Euler(new Vector3(45, 0, 0));
+
+ readonly ImportSettings k_UrdfImportSettings = new ImportSettings
+ {
+ choosenAxis = ImportSettings.axisType.yAxis,
+ convexMethod = ImportSettings.convexDecomposer.unity
+ };
+ #endregion
+
+ float m_TimeElapsedSeconds;
+ [SerializeField, HideInInspector]
+ ROSConnection m_RosConnection;
+ [SerializeField, HideInInspector]
+ TargetPlacement m_TargetPlacement;
+
+ // NOTE: This check could be made more robust by checking the gripper state of the arm to confirm it has
+ // released the Target
+ bool DidPlacementSucceed => m_TargetPlacement.CurrentState == TargetPlacement.PlacementState.InsidePlaced;
+
+
+ [UnityTest]
+ public IEnumerator TrajectoryPublisher_PickAndPlaceDemo_CompletesTask()
+ {
+#if INTEGRATION_TEST
+ SetUpScene();
+ // TODO: This test could be made a PlayMode test once ImportRobot can use the PlayMode URDF import
+ ImportRobot();
+ CreateRosConnection();
+ CreateTrajectoryPlannerPublisher();
+ yield return new EnterPlayMode();
+
+ m_TargetPlacement = GameObject.Find(k_NameTargetPlacement).GetComponent();
+ Assert.IsNotNull(m_TargetPlacement, $"Unable to find {nameof(TargetPlacement)} attached to a " +
+ $"GameObject called {k_NameTargetPlacement} in scene.");
+
+ var publisher = GameObject.Find(k_NamePublisher).GetComponent();
+ publisher.PublishJoints();
+
+ while(!DidPlacementSucceed && m_TimeElapsedSeconds < k_TestTimeoutSeconds)
+ {
+ m_TimeElapsedSeconds += Time.deltaTime;
+ yield return null;
+ }
+
+ Assert.IsTrue(DidPlacementSucceed, "Pick and Place did not complete before test timed out.");
+
+ yield return new ExitPlayMode();
+ }
+
+ void SetUpScene()
+ {
+ EditorSceneManager.OpenScene(k_PathTestScene);
+
+ InstantiatePrefabFromName(k_NameTable);
+ InstantiatePrefabFromName(k_NameTarget);
+ InstantiatePrefabFromName(k_NameTargetPlacement);
+
+ var camera = GameObject.Find(k_NameCamera);
+ camera.transform.position = k_CameraPosition;
+ camera.transform.rotation = k_CameraRotation;
+ }
+
+ void CreateTrajectoryPlannerPublisher()
+ {
+ var planner = new GameObject(k_NamePublisher).AddComponent();
+ planner.rosServiceName = k_NamePackageNiryoMoveIt;
+ planner.niryoOne = GameObject.Find(k_NameNiryoOne);
+ planner.target = GameObject.Find(k_NameTarget);
+ planner.targetPlacement = GameObject.Find(k_NameTargetPlacement);
+ }
+
+ GameObject InstantiatePrefabFromName(string name)
+ {
+ var filepath = Path.Combine(k_DirectoryPrefabs, $"{name}{k_PrefabSuffix}");
+ var gameObject = (GameObject) PrefabUtility.InstantiatePrefab(
+ AssetDatabase.LoadAssetAtPath(filepath));
+ gameObject.name = name;
+ return gameObject;
+ }
+
+ void CreateRosConnection()
+ {
+ m_RosConnection = new GameObject(k_NameRosConnect).AddComponent();
+ m_RosConnection.RosIPAddress = k_IpAddressLoopback;
+ m_RosConnection.RosPort = k_HostPort;
+ //m_RosConnection.overrideUnityIP = k_IpAddressLoopback;
+ //m_RosConnection.unityPort = k_UnityPort;
+ //m_RosConnection.awaitDataMaxRetries = k_NumAwaitDataRetries;
+ //m_RosConnection.awaitDataSleepSeconds = k_NumAwaitDataSleepSeconds;
+ }
+
+ void ImportRobot()
+ {
+ var urdfFullPath = Path.Combine(Application.dataPath, k_PathUrdf);
+ var robotImporter = UrdfRobotExtensions.Create(urdfFullPath, k_UrdfImportSettings, false);
+ // Create is a coroutine that would usually run only in EditMode, so we need to force its execution here
+ while (robotImporter.MoveNext())
+ {
+ }
+
+ // Ensure parameters are set to reasonable values
+ var controller = GameObject.Find(k_NameNiryoOne).GetComponent();
+ controller.stiffness = k_ControllerStiffness;
+ controller.damping = k_ControllerDamping;
+ controller.forceLimit = k_ControllerForceLimit;
+ controller.speed = k_ControllerSpeed;
+ controller.acceleration = k_ControllerAcceleration;
+ GameObject.Find(k_NameBaseLink).GetComponent().immovable = true;
+#else
+ throw new NotImplementedException(
+ "This integration test can only be executed with the INTEGRATION_TEST scripting define set. " +
+ "The dependencies of this test are not guaranteed to exist in the Project by default.");
+#endif
+ }
+ }
+}
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/EditMode/IntegrationTest.cs.meta b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/EditMode/IntegrationTest.cs.meta
new file mode 100644
index 00000000..e0e18053
--- /dev/null
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/EditMode/IntegrationTest.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 47248c975ddb5bb498501829315c818d
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/EditMode/PickAndPlaceMessageGenerationtests.cs b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/EditMode/PickAndPlaceMessageGenerationtests.cs
index 09500a63..c2048b40 100644
--- a/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/EditMode/PickAndPlaceMessageGenerationtests.cs
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/EditMode/PickAndPlaceMessageGenerationtests.cs
@@ -4,54 +4,93 @@
using Unity.Robotics.ROSTCPConnector.MessageGeneration;
using Unity.Robotics.ROSTCPConnector.Editor.MessageGeneration;
using UnityEditor;
+using UnityEngine;
-[TestFixture]
-[Category("MessageGeneration")]
-public class PickAndPlaceMessageGenerationTests
+namespace MessageGenerationTests
{
- // Relative path to the directory containing the catkin packages
- static readonly string k_ROSDirectory = Path.GetFullPath(Path.Combine("..", "ROS", "src"));
- static string m_MessageGenOutputPath => MessageGenBrowserSettings.Get().outputPath;
-
- // Define more individual messages to run generation on within this test case enumerable
- static IEnumerable IndividualMessages()
+ // This gets a special category to enable running independently when needed to generate message definitions
+ [TestFixture, Category("MessageGeneration")]
+ public class MessageGenerationTests
{
- yield return new TestCaseData(Path.Combine(k_ROSDirectory, "moveit_msgs", "msg", "RobotTrajectory.msg"));
- }
+ enum PathType
+ {
+ File,
+ Directory
+ }
- // Define directories of message files to be generated here
- static IEnumerable MessageDirectories()
- {
- yield return new TestCaseData(Path.Combine(k_ROSDirectory, "niryo_moveit", "msg"));
- }
+ // Relative path to the directory containing the catkin packages
+ static readonly string k_ROSDirectory = Path.GetFullPath(Path.Combine("..", "ROS", "src"));
+ static string m_MessageGenOutputPath => MessageGenBrowserSettings.Get().outputPath;
- // Define directories of service files to be generated here
- static IEnumerable ServiceDirectories()
- {
- yield return new TestCaseData(Path.Combine(k_ROSDirectory, "niryo_moveit", "srv"));
- }
+ static void WarnIfAlreadyExists(string path, PathType pathType)
+ {
+ var alreadyExists = pathType == PathType.File ? File.Exists(path) : Directory.Exists(path);
+ if (alreadyExists)
+ {
+ Debug.LogWarning($"{path} already exists. Test can't validate files were generated correctly unless " +
+ "this path is manually deleted first.");
+ }
+ }
- [Test]
- [TestCaseSource(nameof(IndividualMessages))]
- public void TestMessageBuildSingle_ThrowsNoExceptions(string messageToBuild)
- {
- MessageAutoGen.GenerateSingleMessage(messageToBuild, m_MessageGenOutputPath);
- AssetDatabase.Refresh();
- }
+ static void AssertExists(string path, PathType pathType)
+ {
+ Assert.IsTrue(pathType == PathType.File ? File.Exists(path) : Directory.Exists(path));
+ }
- [Test]
- [TestCaseSource(nameof(MessageDirectories))]
- public void TestMessageBuildDirectory_ThrowsNoExceptions(string directoryToBuild)
- {
- MessageAutoGen.GenerateDirectoryMessages(directoryToBuild, m_MessageGenOutputPath);
- AssetDatabase.Refresh();
- }
+ // Define more individual messages to run generation on within this test case enumerable
+ static IEnumerable IndividualMessages()
+ {
+ yield return new TestCaseData(Path.Combine(k_ROSDirectory, "moveit_msgs", "msg", "RobotTrajectory.msg"));
+ }
- [Test]
- [TestCaseSource(nameof(ServiceDirectories))]
- public void TestServiceBuildDirectory_ThrowsNoExceptions(string directoryToBuild)
- {
- ServiceAutoGen.GenerateDirectoryServices(directoryToBuild, m_MessageGenOutputPath);
- AssetDatabase.Refresh();
+ // Define directories of message files to be generated here
+ static IEnumerable MessageDirectories()
+ {
+ yield return new TestCaseData(Path.Combine(k_ROSDirectory, "niryo_moveit", "msg"));
+ }
+
+ // Define directories of service files to be generated here
+ static IEnumerable ServiceDirectories()
+ {
+ yield return new TestCaseData(Path.Combine(k_ROSDirectory, "niryo_moveit", "srv"));
+ }
+
+ [Test]
+ [TestCaseSource(nameof(IndividualMessages))]
+ public void TestMessageBuildSingle_ThrowsNoExceptions(string messageToBuild)
+ {
+ var msgPath = MessageAutoGen.GetMessageClassPath(messageToBuild, m_MessageGenOutputPath);
+ Debug.Log($"Generating code for {messageToBuild}, output should be at {msgPath}");
+ WarnIfAlreadyExists(msgPath, PathType.File);
+ MessageAutoGen.GenerateSingleMessage(messageToBuild, m_MessageGenOutputPath);
+ AssetDatabase.Refresh();
+ AssertExists(msgPath, PathType.File);
+ }
+
+ [Test]
+ [TestCaseSource(nameof(MessageDirectories))]
+ public void TestMessageBuildDirectory_ThrowsNoExceptions(string directoryToBuild)
+ {
+ var msgPath = MessageAutoGen.GetMessageClassPath(directoryToBuild, m_MessageGenOutputPath);
+ var msgDirectory = Path.GetDirectoryName(msgPath);
+ Debug.Log($"Generating code in {directoryToBuild}, output should be in {msgDirectory}");
+ WarnIfAlreadyExists(msgDirectory, PathType.Directory);
+ MessageAutoGen.GenerateDirectoryMessages(directoryToBuild, m_MessageGenOutputPath);
+ AssetDatabase.Refresh();
+ AssertExists(msgDirectory, PathType.Directory);
+ }
+
+ [Test]
+ [TestCaseSource(nameof(ServiceDirectories))]
+ public void TestServiceBuildDirectory_ThrowsNoExceptions(string directoryToBuild)
+ {
+ var msgPath = ServiceAutoGen.GetServiceClassPaths(directoryToBuild, m_MessageGenOutputPath);
+ var msgDirectory = Path.GetDirectoryName(msgPath[0]);
+ Debug.Log($"Generating code in {directoryToBuild}, output should be in {msgDirectory}");
+ WarnIfAlreadyExists(msgDirectory, PathType.Directory);
+ ServiceAutoGen.GenerateDirectoryServices(directoryToBuild, m_MessageGenOutputPath);
+ AssetDatabase.Refresh();
+ AssertExists(msgDirectory, PathType.Directory);
+ }
}
}
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/EditMode/PlayerBuildTests.cs b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/EditMode/PlayerBuildTests.cs
index 11b7732e..d896fc88 100644
--- a/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/EditMode/PlayerBuildTests.cs
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/EditMode/PlayerBuildTests.cs
@@ -9,8 +9,7 @@
namespace BuildTests
{
- [TestFixture]
- [Category("BuildTests")]
+ [TestFixture, Explicit, Category("BuildTests")]
public class PlayerBuilder
{
List m_EditorBuildSettingsScenes = new List();
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/PlayMode/ExamplePlayModeTests.cs b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/PlayMode/ExamplePlayModeTests.cs
deleted file mode 100644
index 67978343..00000000
--- a/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/PlayMode/ExamplePlayModeTests.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using System.Collections;
-using System.Collections.Generic;
-using NUnit.Framework;
-using UnityEngine;
-using UnityEngine.TestTools;
-
-public class ExamplePlayModeTests
-{
- // A Test behaves as an ordinary method
- [Test]
- public void ExamplePlayModeTestsSimplePasses()
- {
- // Use the Assert class to test conditions
- }
-
- // A UnityTest behaves like a coroutine in Play Mode. In Edit Mode you can use
- // `yield return null;` to skip a frame.
- [UnityTest]
- public IEnumerator ExamplePlayModeTestsWithEnumeratorPasses()
- {
- // Use the Assert class to test conditions.
- // Use yield to skip a frame.
- yield return null;
- }
-}
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/PlayMode/PlayMode.asmdef b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/PlayMode/PlayMode.asmdef
index 5c77dfe9..5cfe0fc9 100644
--- a/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/PlayMode/PlayMode.asmdef
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/PlayMode/PlayMode.asmdef
@@ -1,6 +1,25 @@
{
"name": "PlayMode",
- "optionalUnityReferences": [
- "TestAssemblies"
- ]
-}
+ "rootNamespace": "",
+ "references": [
+ "UnityEngine.TestRunner",
+ "UnityEditor.TestRunner",
+ "Unity.Robotics.URDFImporter",
+ "Unity.Robotics.ROSTCPConnector",
+ "Unity.Robotics.RosMessages",
+ "Unity.Robotics.PickAndPlace"
+ ],
+ "includePlatforms": [],
+ "excludePlatforms": [],
+ "allowUnsafeCode": false,
+ "overrideReferences": true,
+ "precompiledReferences": [
+ "nunit.framework.dll"
+ ],
+ "autoReferenced": false,
+ "defineConstraints": [
+ "UNITY_INCLUDE_TESTS"
+ ],
+ "versionDefines": [],
+ "noEngineReferences": false
+}
\ No newline at end of file
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/PlayMode/PlayModeTestScenes.meta b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/PlayMode/PlayModeTestScenes.meta
new file mode 100644
index 00000000..fa46d563
--- /dev/null
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/PlayMode/PlayModeTestScenes.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 01cfe2c2ad3030e45aece82563af9de1
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/PlayMode/PlayModeTestScenes/TargetPlacementTest.unity b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/PlayMode/PlayModeTestScenes/TargetPlacementTest.unity
new file mode 100644
index 00000000..edf9b4d0
--- /dev/null
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/PlayMode/PlayModeTestScenes/TargetPlacementTest.unity
@@ -0,0 +1,874 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!29 &1
+OcclusionCullingSettings:
+ m_ObjectHideFlags: 0
+ serializedVersion: 2
+ m_OcclusionBakeSettings:
+ smallestOccluder: 5
+ smallestHole: 0.25
+ backfaceThreshold: 100
+ m_SceneGUID: 00000000000000000000000000000000
+ m_OcclusionCullingData: {fileID: 0}
+--- !u!104 &2
+RenderSettings:
+ m_ObjectHideFlags: 0
+ serializedVersion: 9
+ m_Fog: 0
+ m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
+ m_FogMode: 3
+ m_FogDensity: 0.01
+ m_LinearFogStart: 0
+ m_LinearFogEnd: 300
+ m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
+ m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
+ m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
+ m_AmbientIntensity: 1
+ m_AmbientMode: 0
+ m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
+ m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
+ m_HaloStrength: 0.5
+ m_FlareStrength: 1
+ m_FlareFadeSpeed: 3
+ m_HaloTexture: {fileID: 0}
+ m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
+ m_DefaultReflectionMode: 0
+ m_DefaultReflectionResolution: 128
+ m_ReflectionBounces: 1
+ m_ReflectionIntensity: 1
+ m_CustomReflection: {fileID: 0}
+ m_Sun: {fileID: 0}
+ m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1}
+ m_UseRadianceAmbientProbe: 0
+--- !u!157 &3
+LightmapSettings:
+ m_ObjectHideFlags: 0
+ serializedVersion: 12
+ m_GIWorkflowMode: 1
+ m_GISettings:
+ serializedVersion: 2
+ m_BounceScale: 1
+ m_IndirectOutputScale: 1
+ m_AlbedoBoost: 1
+ m_EnvironmentLightingMode: 0
+ m_EnableBakedLightmaps: 1
+ m_EnableRealtimeLightmaps: 0
+ m_LightmapEditorSettings:
+ serializedVersion: 12
+ m_Resolution: 2
+ m_BakeResolution: 40
+ m_AtlasSize: 1024
+ m_AO: 0
+ m_AOMaxDistance: 1
+ m_CompAOExponent: 1
+ m_CompAOExponentDirect: 0
+ m_ExtractAmbientOcclusion: 0
+ m_Padding: 2
+ m_LightmapParameters: {fileID: 0}
+ m_LightmapsBakeMode: 1
+ m_TextureCompression: 1
+ m_FinalGather: 0
+ m_FinalGatherFiltering: 1
+ m_FinalGatherRayCount: 256
+ m_ReflectionCompression: 2
+ m_MixedBakeMode: 2
+ m_BakeBackend: 1
+ m_PVRSampling: 1
+ m_PVRDirectSampleCount: 32
+ m_PVRSampleCount: 512
+ m_PVRBounces: 2
+ m_PVREnvironmentSampleCount: 256
+ m_PVREnvironmentReferencePointCount: 2048
+ m_PVRFilteringMode: 1
+ m_PVRDenoiserTypeDirect: 1
+ m_PVRDenoiserTypeIndirect: 1
+ m_PVRDenoiserTypeAO: 1
+ m_PVRFilterTypeDirect: 0
+ m_PVRFilterTypeIndirect: 0
+ m_PVRFilterTypeAO: 0
+ m_PVREnvironmentMIS: 1
+ m_PVRCulling: 1
+ m_PVRFilteringGaussRadiusDirect: 1
+ m_PVRFilteringGaussRadiusIndirect: 5
+ m_PVRFilteringGaussRadiusAO: 2
+ m_PVRFilteringAtrousPositionSigmaDirect: 0.5
+ m_PVRFilteringAtrousPositionSigmaIndirect: 2
+ m_PVRFilteringAtrousPositionSigmaAO: 1
+ m_ExportTrainingData: 0
+ m_TrainingDataDestination: TrainingData
+ m_LightProbeSampleCountMultiplier: 4
+ m_LightingDataAsset: {fileID: 0}
+ m_LightingSettings: {fileID: 0}
+--- !u!196 &4
+NavMeshSettings:
+ serializedVersion: 2
+ m_ObjectHideFlags: 0
+ m_BuildSettings:
+ serializedVersion: 2
+ agentTypeID: 0
+ agentRadius: 0.5
+ agentHeight: 2
+ agentSlope: 45
+ agentClimb: 0.4
+ ledgeDropHeight: 0
+ maxJumpAcrossDistance: 0
+ minRegionArea: 2
+ manualCellSize: 0
+ cellSize: 0.16666667
+ manualTileSize: 0
+ tileSize: 256
+ accuratePlacement: 0
+ maxJobWorkers: 0
+ preserveTilesOutsideBounds: 0
+ debug:
+ m_Flags: 0
+ m_NavMeshData: {fileID: 0}
+--- !u!1001 &249878388
+PrefabInstance:
+ m_ObjectHideFlags: 0
+ serializedVersion: 2
+ m_Modification:
+ m_TransformParent: {fileID: 0}
+ m_Modifications:
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_RootOrder
+ value: 4
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalPosition.x
+ value: -0.098
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalPosition.y
+ value: 0.643
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalPosition.z
+ value: 0.3215
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalRotation.w
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalRotation.x
+ value: -0
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalRotation.y
+ value: -0
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalRotation.z
+ value: -0
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591414, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_Name
+ value: TargetPlacementPlaced
+ objectReference: {fileID: 0}
+ - target: {fileID: 7978903071639371792, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_Target
+ value:
+ objectReference: {fileID: 587740271}
+ m_RemovedComponents: []
+ m_SourcePrefab: {fileID: 100100000, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+--- !u!1001 &444527226
+PrefabInstance:
+ m_ObjectHideFlags: 0
+ serializedVersion: 2
+ m_Modification:
+ m_TransformParent: {fileID: 0}
+ m_Modifications:
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_RootOrder
+ value: 3
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalPosition.x
+ value: -0.098
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalPosition.y
+ value: 0.643
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalPosition.z
+ value: -0.07790001
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalRotation.w
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalRotation.x
+ value: -0
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalRotation.y
+ value: -0
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalRotation.z
+ value: -0
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591414, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_Name
+ value: TargetPlacementOutside
+ objectReference: {fileID: 0}
+ - target: {fileID: 7978903071639371792, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_Target
+ value:
+ objectReference: {fileID: 1731673593}
+ m_RemovedComponents: []
+ m_SourcePrefab: {fileID: 100100000, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+--- !u!1001 &587740270
+PrefabInstance:
+ m_ObjectHideFlags: 0
+ serializedVersion: 2
+ m_Modification:
+ m_TransformParent: {fileID: 0}
+ m_Modifications:
+ - target: {fileID: 4064412142990923027, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_UseGravity
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_RootOrder
+ value: 5
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalPosition.x
+ value: -0.09569999
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalPosition.y
+ value: 0.6501
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalPosition.z
+ value: 0.3185
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalRotation.w
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalRotation.x
+ value: -0
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalRotation.y
+ value: -0
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalRotation.z
+ value: -0
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 5601983281253769233, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_Name
+ value: TargetPlaced
+ objectReference: {fileID: 0}
+ m_RemovedComponents: []
+ m_SourcePrefab: {fileID: 100100000, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+--- !u!1 &587740271 stripped
+GameObject:
+ m_CorrespondingSourceObject: {fileID: 5601983281253769233, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ m_PrefabInstance: {fileID: 587740270}
+ m_PrefabAsset: {fileID: 0}
+--- !u!1 &721719780 stripped
+GameObject:
+ m_CorrespondingSourceObject: {fileID: 5601983281253769233, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ m_PrefabInstance: {fileID: 1722777672}
+ m_PrefabAsset: {fileID: 0}
+--- !u!1001 &1044694655
+PrefabInstance:
+ m_ObjectHideFlags: 0
+ serializedVersion: 2
+ m_Modification:
+ m_TransformParent: {fileID: 0}
+ m_Modifications:
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_RootOrder
+ value: 10
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalPosition.x
+ value: -0.2789
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalPosition.y
+ value: 0.643
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalPosition.z
+ value: 0.119
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalRotation.w
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalRotation.x
+ value: -0
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalRotation.y
+ value: -0
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalRotation.z
+ value: -0
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591414, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_Name
+ value: TargetPlacementStateChange
+ objectReference: {fileID: 0}
+ - target: {fileID: 4980278694990496136, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_Center.y
+ value: 0.25
+ objectReference: {fileID: 0}
+ - target: {fileID: 7978903071639371792, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_Target
+ value:
+ objectReference: {fileID: 721719780}
+ m_RemovedComponents: []
+ m_SourcePrefab: {fileID: 100100000, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+--- !u!1001 &1080763006
+PrefabInstance:
+ m_ObjectHideFlags: 0
+ serializedVersion: 2
+ m_Modification:
+ m_TransformParent: {fileID: 0}
+ m_Modifications:
+ - target: {fileID: 4064412142990923027, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_UseGravity
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_RootOrder
+ value: 7
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalPosition.x
+ value: -0.106999986
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalPosition.y
+ value: 0.65760005
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalPosition.z
+ value: 0.1506
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalRotation.w
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalRotation.x
+ value: -0
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalRotation.y
+ value: -0
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalRotation.z
+ value: -0
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 5601983281253769233, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_Name
+ value: TargetFloating
+ objectReference: {fileID: 0}
+ m_RemovedComponents: []
+ m_SourcePrefab: {fileID: 100100000, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+--- !u!1 &1080763007 stripped
+GameObject:
+ m_CorrespondingSourceObject: {fileID: 5601983281253769233, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ m_PrefabInstance: {fileID: 1080763006}
+ m_PrefabAsset: {fileID: 0}
+--- !u!1 &1616270945
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1616270948}
+ - component: {fileID: 1616270947}
+ - component: {fileID: 1616270946}
+ m_Layer: 0
+ m_Name: Main Camera
+ m_TagString: MainCamera
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!81 &1616270946
+AudioListener:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1616270945}
+ m_Enabled: 1
+--- !u!20 &1616270947
+Camera:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1616270945}
+ m_Enabled: 1
+ serializedVersion: 2
+ m_ClearFlags: 1
+ m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
+ m_projectionMatrixMode: 1
+ m_GateFitMode: 2
+ m_FOVAxisMode: 0
+ m_SensorSize: {x: 36, y: 24}
+ m_LensShift: {x: 0, y: 0}
+ m_FocalLength: 50
+ m_NormalizedViewPortRect:
+ serializedVersion: 2
+ x: 0
+ y: 0
+ width: 1
+ height: 1
+ near clip plane: 0.3
+ far clip plane: 1000
+ field of view: 60
+ orthographic: 0
+ orthographic size: 5
+ m_Depth: -1
+ m_CullingMask:
+ serializedVersion: 2
+ m_Bits: 4294967295
+ m_RenderingPath: -1
+ m_TargetTexture: {fileID: 0}
+ m_TargetDisplay: 0
+ m_TargetEye: 3
+ m_HDR: 1
+ m_AllowMSAA: 1
+ m_AllowDynamicResolution: 0
+ m_ForceIntoRT: 0
+ m_OcclusionCulling: 1
+ m_StereoConvergence: 10
+ m_StereoSeparation: 0.022
+--- !u!4 &1616270948
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1616270945}
+ m_LocalRotation: {x: -0.33147213, y: 0.66312367, z: -0.24441679, w: -0.6250229}
+ m_LocalPosition: {x: 0.473, y: 1.086, z: 0.100999914}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_Children: []
+ m_Father: {fileID: 0}
+ m_RootOrder: 0
+ m_LocalEulerAnglesHint: {x: 47.605, y: 261.538, z: -11.471}
+--- !u!1001 &1722777672
+PrefabInstance:
+ m_ObjectHideFlags: 0
+ serializedVersion: 2
+ m_Modification:
+ m_TransformParent: {fileID: 0}
+ m_Modifications:
+ - target: {fileID: 4064412142990923027, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_UseGravity
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_RootOrder
+ value: 9
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalPosition.x
+ value: -0.2787
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalPosition.y
+ value: 0.68
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalPosition.z
+ value: 0.1215
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalRotation.w
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalRotation.x
+ value: -0
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalRotation.y
+ value: -0
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalRotation.z
+ value: -0
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 5601983281253769233, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_Name
+ value: TargetFalling
+ objectReference: {fileID: 0}
+ m_RemovedComponents: []
+ m_SourcePrefab: {fileID: 100100000, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+--- !u!1001 &1731673592
+PrefabInstance:
+ m_ObjectHideFlags: 0
+ serializedVersion: 2
+ m_Modification:
+ m_TransformParent: {fileID: 0}
+ m_Modifications:
+ - target: {fileID: 4064412142990923027, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_UseGravity
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_RootOrder
+ value: 6
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalPosition.x
+ value: -0.12299999
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalPosition.y
+ value: 0.68200004
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalPosition.z
+ value: -0.055899993
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalRotation.w
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalRotation.x
+ value: -0
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalRotation.y
+ value: -0
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalRotation.z
+ value: -0
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 5113255398182140587, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 5601983281253769233, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ propertyPath: m_Name
+ value: TargetOutside
+ objectReference: {fileID: 0}
+ m_RemovedComponents: []
+ m_SourcePrefab: {fileID: 100100000, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+--- !u!1 &1731673593 stripped
+GameObject:
+ m_CorrespondingSourceObject: {fileID: 5601983281253769233, guid: 3901759e6233748538fffdbc519c1a68, type: 3}
+ m_PrefabInstance: {fileID: 1731673592}
+ m_PrefabAsset: {fileID: 0}
+--- !u!1001 &1970267000
+PrefabInstance:
+ m_ObjectHideFlags: 0
+ serializedVersion: 2
+ m_Modification:
+ m_TransformParent: {fileID: 0}
+ m_Modifications:
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_RootOrder
+ value: 2
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalPosition.x
+ value: -0.098
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalPosition.y
+ value: 0.643
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalPosition.z
+ value: 0.119
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalRotation.w
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalRotation.x
+ value: -0
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalRotation.y
+ value: -0
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalRotation.z
+ value: -0
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591411, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 850690186460591414, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_Name
+ value: TargetPlacementFloating
+ objectReference: {fileID: 0}
+ - target: {fileID: 4980278694990496136, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_Center.y
+ value: 0.25
+ objectReference: {fileID: 0}
+ - target: {fileID: 7978903071639371792, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+ propertyPath: m_Target
+ value:
+ objectReference: {fileID: 1080763007}
+ m_RemovedComponents: []
+ m_SourcePrefab: {fileID: 100100000, guid: 43bef545df3e344c4a7e089ca90c15a0, type: 3}
+--- !u!1 &2033834534
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 2033834536}
+ - component: {fileID: 2033834535}
+ m_Layer: 0
+ m_Name: Directional Light
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!108 &2033834535
+Light:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 2033834534}
+ m_Enabled: 1
+ serializedVersion: 10
+ m_Type: 1
+ m_Shape: 0
+ m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
+ m_Intensity: 1
+ m_Range: 10
+ m_SpotAngle: 30
+ m_InnerSpotAngle: 21.80208
+ m_CookieSize: 10
+ m_Shadows:
+ m_Type: 2
+ m_Resolution: -1
+ m_CustomResolution: -1
+ m_Strength: 1
+ m_Bias: 0.05
+ m_NormalBias: 0.4
+ m_NearPlane: 0.2
+ m_CullingMatrixOverride:
+ e00: 1
+ e01: 0
+ e02: 0
+ e03: 0
+ e10: 0
+ e11: 1
+ e12: 0
+ e13: 0
+ e20: 0
+ e21: 0
+ e22: 1
+ e23: 0
+ e30: 0
+ e31: 0
+ e32: 0
+ e33: 1
+ m_UseCullingMatrixOverride: 0
+ m_Cookie: {fileID: 0}
+ m_DrawHalo: 0
+ m_Flare: {fileID: 0}
+ m_RenderMode: 0
+ m_CullingMask:
+ serializedVersion: 2
+ m_Bits: 4294967295
+ m_RenderingLayerMask: 1
+ m_Lightmapping: 4
+ m_LightShadowCasterMode: 0
+ m_AreaSize: {x: 1, y: 1}
+ m_BounceIntensity: 1
+ m_ColorTemperature: 6570
+ m_UseColorTemperature: 0
+ m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
+ m_UseBoundingSphereOverride: 0
+ m_UseViewFrustumForShadowCasterCull: 1
+ m_ShadowRadius: 0
+ m_ShadowAngle: 0
+--- !u!4 &2033834536
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 2033834534}
+ m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
+ m_LocalPosition: {x: 0, y: 3, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_Children: []
+ m_Father: {fileID: 0}
+ m_RootOrder: 1
+ m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
+--- !u!1001 &2134712309
+PrefabInstance:
+ m_ObjectHideFlags: 0
+ serializedVersion: 2
+ m_Modification:
+ m_TransformParent: {fileID: 0}
+ m_Modifications:
+ - target: {fileID: 2781043625631727712, guid: 85db2308098d34a79837fb7356902f62, type: 3}
+ propertyPath: m_RootOrder
+ value: 8
+ objectReference: {fileID: 0}
+ - target: {fileID: 2781043625631727712, guid: 85db2308098d34a79837fb7356902f62, type: 3}
+ propertyPath: m_LocalPosition.x
+ value: -0.10367495
+ objectReference: {fileID: 0}
+ - target: {fileID: 2781043625631727712, guid: 85db2308098d34a79837fb7356902f62, type: 3}
+ propertyPath: m_LocalPosition.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2781043625631727712, guid: 85db2308098d34a79837fb7356902f62, type: 3}
+ propertyPath: m_LocalPosition.z
+ value: 0.121130586
+ objectReference: {fileID: 0}
+ - target: {fileID: 2781043625631727712, guid: 85db2308098d34a79837fb7356902f62, type: 3}
+ propertyPath: m_LocalRotation.w
+ value: 0.7025373
+ objectReference: {fileID: 0}
+ - target: {fileID: 2781043625631727712, guid: 85db2308098d34a79837fb7356902f62, type: 3}
+ propertyPath: m_LocalRotation.x
+ value: -0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2781043625631727712, guid: 85db2308098d34a79837fb7356902f62, type: 3}
+ propertyPath: m_LocalRotation.y
+ value: -0.711647
+ objectReference: {fileID: 0}
+ - target: {fileID: 2781043625631727712, guid: 85db2308098d34a79837fb7356902f62, type: 3}
+ propertyPath: m_LocalRotation.z
+ value: -0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2781043625631727712, guid: 85db2308098d34a79837fb7356902f62, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2781043625631727712, guid: 85db2308098d34a79837fb7356902f62, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.y
+ value: -90.738
+ objectReference: {fileID: 0}
+ - target: {fileID: 2781043625631727712, guid: 85db2308098d34a79837fb7356902f62, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 3302142234816977626, guid: 85db2308098d34a79837fb7356902f62, type: 3}
+ propertyPath: m_Name
+ value: Table
+ objectReference: {fileID: 0}
+ m_RemovedComponents: []
+ m_SourcePrefab: {fileID: 100100000, guid: 85db2308098d34a79837fb7356902f62, type: 3}
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/PlayMode/PlayModeTestScenes/TargetPlacementTest.unity.meta b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/PlayMode/PlayModeTestScenes/TargetPlacementTest.unity.meta
new file mode 100644
index 00000000..151eaccc
--- /dev/null
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/PlayMode/PlayModeTestScenes/TargetPlacementTest.unity.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 3d328f38f71b71e47bb8d96869012ffe
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/PlayMode/TargetPlacementTests.cs b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/PlayMode/TargetPlacementTests.cs
new file mode 100644
index 00000000..268a2898
--- /dev/null
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/PlayMode/TargetPlacementTests.cs
@@ -0,0 +1,83 @@
+using System.Collections;
+using System.Collections.Generic;
+using NUnit.Framework;
+using Unity.Robotics.PickAndPlace;
+using UnityEngine;
+using UnityEngine.SceneManagement;
+using UnityEngine.TestTools;
+
+[TestFixture, Category("UnitTests")]
+public class TargetPlacementTests
+{
+ const int k_NumAllowedFramesStatic = 5;
+ const int k_NumAllowedFramesDynamic = 20;
+ const string k_NamePlaced = "TargetPlacementPlaced";
+ const string k_NameOutside = "TargetPlacementOutside";
+ const string k_NameFloating = "TargetPlacementFloating";
+
+ [UnitySetUp]
+ public IEnumerator LoadSceneAndStartPlayMode()
+ {
+ SceneManager.LoadScene("TargetPlacementTest");
+ yield return new EnterPlayMode();
+ }
+
+ [UnityTearDown]
+ public IEnumerator ExitSceneOnTearDown()
+ {
+ yield return new ExitPlayMode();
+ }
+
+ public static IEnumerable TargetPlacementCases()
+ {
+ yield return new TestCaseData(k_NamePlaced, TargetPlacement.PlacementState.InsidePlaced).Returns(null);
+ yield return new TestCaseData(k_NameOutside, TargetPlacement.PlacementState.Outside).Returns(null);
+ yield return new TestCaseData(k_NameFloating, TargetPlacement.PlacementState.InsideFloating).Returns(null);
+ }
+
+ TargetPlacement GetTargetPlacement(string name)
+ {
+ var targetPlacement = GameObject.Find(name)?.GetComponent();
+ Assert.IsNotNull(targetPlacement, $"Failed to find {name}");
+ return targetPlacement;
+ }
+
+ static IEnumerator WaitForState(
+ TargetPlacement targetPlacement, TargetPlacement.PlacementState stateExpected, int numFramesToWait)
+ {
+ var numFramesTested = 0;
+
+ while (targetPlacement.CurrentState != stateExpected && numFramesTested < numFramesToWait)
+ {
+ numFramesTested++;
+ yield return null;
+ }
+
+ Assert.AreEqual(stateExpected, targetPlacement.CurrentState);
+ }
+
+ [UnityTest, TestCaseSource(nameof(TargetPlacementCases))]
+ public IEnumerator TargetPlacement_WithStaticObjects_SetsStateCorrectly(
+ string name, TargetPlacement.PlacementState stateExpected)
+ {
+ var targetPlacement = GetTargetPlacement(name);
+
+ yield return WaitForState(targetPlacement, stateExpected, k_NumAllowedFramesStatic);
+ }
+
+ [UnityTest]
+ public IEnumerator TargetPlacement_WithFallingObject_ChangesStateCorrectly()
+ {
+ const string name = "TargetPlacementStateChange";
+ var targetPlacement = GetTargetPlacement(name);
+
+ Assert.AreEqual(TargetPlacement.PlacementState.Outside, targetPlacement.CurrentState,
+ $"{name} should start with no Target in its bounds.");
+
+ // Target should fall into placement and come to reset
+ yield return WaitForState(
+ targetPlacement, TargetPlacement.PlacementState.InsideFloating, k_NumAllowedFramesDynamic);
+ yield return WaitForState(
+ targetPlacement, TargetPlacement.PlacementState.InsidePlaced, k_NumAllowedFramesDynamic);
+ }
+}
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/PlayMode/ExamplePlayModeTests.cs.meta b/tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/PlayMode/TargetPlacementTests.cs.meta
similarity index 100%
rename from tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/PlayMode/ExamplePlayModeTests.cs.meta
rename to tutorials/pick_and_place/PickAndPlaceProject/Assets/Tests/PlayMode/TargetPlacementTests.cs.meta
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/arm_link.dae.meta b/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/arm_link.dae.meta
index d4225d01..cfe0d2e4 100644
--- a/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/arm_link.dae.meta
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/arm_link.dae.meta
@@ -1,7 +1,7 @@
fileFormatVersion: 2
guid: 4385bf9cdd04d410abf0c13a4671c867
ModelImporter:
- serializedVersion: 20101
+ serializedVersion: 20200
internalIDToNameTable: []
externalObjects: {}
materials:
@@ -95,6 +95,7 @@ ModelImporter:
animationType: 0
humanoidOversampling: 1
avatarSetup: 0
+ addHumanoidExtraRootOnlyWhenUsingAvatar: 0
additionalBone: 0
userData:
assetBundleName:
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/base_link.dae.meta b/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/base_link.dae.meta
index bd5b3ae7..75aad008 100644
--- a/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/base_link.dae.meta
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/base_link.dae.meta
@@ -1,7 +1,7 @@
fileFormatVersion: 2
guid: 58835255abb66423abcf30402a3fb236
ModelImporter:
- serializedVersion: 20101
+ serializedVersion: 20200
internalIDToNameTable: []
externalObjects: {}
materials:
@@ -95,6 +95,7 @@ ModelImporter:
animationType: 0
humanoidOversampling: 1
avatarSetup: 0
+ addHumanoidExtraRootOnlyWhenUsingAvatar: 0
additionalBone: 0
userData:
assetBundleName:
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/elbow_link.dae.meta b/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/elbow_link.dae.meta
index f1dcad8a..25fcda82 100644
--- a/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/elbow_link.dae.meta
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/elbow_link.dae.meta
@@ -1,7 +1,7 @@
fileFormatVersion: 2
guid: 8b17dab746c4f40c5aea83c9b028635e
ModelImporter:
- serializedVersion: 20101
+ serializedVersion: 20200
internalIDToNameTable: []
externalObjects: {}
materials:
@@ -95,6 +95,7 @@ ModelImporter:
animationType: 0
humanoidOversampling: 1
avatarSetup: 0
+ addHumanoidExtraRootOnlyWhenUsingAvatar: 0
additionalBone: 0
userData:
assetBundleName:
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/forearm_link.dae.meta b/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/forearm_link.dae.meta
index 36255e1f..9a16dee5 100644
--- a/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/forearm_link.dae.meta
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/forearm_link.dae.meta
@@ -1,7 +1,7 @@
fileFormatVersion: 2
guid: 9494a43e68bac4ff5b335b4f38685b0f
ModelImporter:
- serializedVersion: 20101
+ serializedVersion: 20200
internalIDToNameTable: []
externalObjects: {}
materials:
@@ -95,6 +95,7 @@ ModelImporter:
animationType: 0
humanoidOversampling: 1
avatarSetup: 0
+ addHumanoidExtraRootOnlyWhenUsingAvatar: 0
additionalBone: 0
userData:
assetBundleName:
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/hand_link.dae.meta b/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/hand_link.dae.meta
index fc4cbc07..4006f8d0 100644
--- a/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/hand_link.dae.meta
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/hand_link.dae.meta
@@ -1,7 +1,7 @@
fileFormatVersion: 2
guid: 17014b319fad347d09ad182ea939d167
ModelImporter:
- serializedVersion: 20101
+ serializedVersion: 20200
internalIDToNameTable: []
externalObjects: {}
materials:
@@ -95,6 +95,7 @@ ModelImporter:
animationType: 0
humanoidOversampling: 1
avatarSetup: 0
+ addHumanoidExtraRootOnlyWhenUsingAvatar: 0
additionalBone: 0
userData:
assetBundleName:
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/shoulder_link.dae.meta b/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/shoulder_link.dae.meta
index a3d8dceb..ca4fc41b 100644
--- a/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/shoulder_link.dae.meta
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/shoulder_link.dae.meta
@@ -1,7 +1,7 @@
fileFormatVersion: 2
guid: 1a8e3a50f435d489bae37f36bd443001
ModelImporter:
- serializedVersion: 20101
+ serializedVersion: 20200
internalIDToNameTable: []
externalObjects: {}
materials:
@@ -95,6 +95,7 @@ ModelImporter:
animationType: 0
humanoidOversampling: 1
avatarSetup: 0
+ addHumanoidExtraRootOnlyWhenUsingAvatar: 0
additionalBone: 0
userData:
assetBundleName:
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/wrist_link.dae.meta b/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/wrist_link.dae.meta
index b8780b58..2468e069 100644
--- a/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/wrist_link.dae.meta
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Assets/URDF/niryo_one/niryo_one_urdf/meshes/collada/wrist_link.dae.meta
@@ -1,7 +1,7 @@
fileFormatVersion: 2
guid: 81700e0c647d64beeab06b71d2b614ae
ModelImporter:
- serializedVersion: 20101
+ serializedVersion: 20200
internalIDToNameTable: []
externalObjects: {}
materials:
@@ -95,6 +95,7 @@ ModelImporter:
animationType: 0
humanoidOversampling: 1
avatarSetup: 0
+ addHumanoidExtraRootOnlyWhenUsingAvatar: 0
additionalBone: 0
userData:
assetBundleName:
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/Packages/manifest.json b/tutorials/pick_and_place/PickAndPlaceProject/Packages/manifest.json
index a6a89d3d..b5d47257 100644
--- a/tutorials/pick_and_place/PickAndPlaceProject/Packages/manifest.json
+++ b/tutorials/pick_and_place/PickAndPlaceProject/Packages/manifest.json
@@ -1,14 +1,13 @@
{
"dependencies": {
- "com.unity.collab-proxy": "1.3.9",
"com.unity.ide.rider": "2.0.7",
- "com.unity.ide.visualstudio": "2.0.3",
- "com.unity.ide.vscode": "1.2.2",
- "com.unity.robotics.ros-tcp-connector": "https://github.com/Unity-Technologies/ROS-TCP-Connector.git?path=/com.unity.robotics.ros-tcp-connector#v0.4.0",
- "com.unity.robotics.urdf-importer": "https://github.com/Unity-Technologies/URDF-Importer.git?path=/com.unity.robotics.urdf-importer#v0.4.0",
- "com.unity.test-framework": "1.1.18",
- "com.unity.textmeshpro": "3.0.1",
- "com.unity.timeline": "1.4.3",
+ "com.unity.ide.visualstudio": "2.0.8",
+ "com.unity.ide.vscode": "1.2.3",
+ "com.unity.robotics.ros-tcp-connector": "https://github.com/Unity-Technologies/ROS-TCP-Connector.git?path=/com.unity.robotics.ros-tcp-connector#v0.5.0",
+ "com.unity.robotics.urdf-importer": "https://github.com/Unity-Technologies/URDF-Importer.git?path=/com.unity.robotics.urdf-importer#v0.5.0",
+ "com.unity.test-framework": "1.1.24",
+ "com.unity.textmeshpro": "3.0.6",
+ "com.unity.timeline": "1.4.8",
"com.unity.ugui": "1.0.0",
"com.unity.modules.ai": "1.0.0",
"com.unity.modules.androidjni": "1.0.0",
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/ProjectSettings/EditorBuildSettings.asset b/tutorials/pick_and_place/PickAndPlaceProject/ProjectSettings/EditorBuildSettings.asset
index 0147887e..6e08f865 100644
--- a/tutorials/pick_and_place/PickAndPlaceProject/ProjectSettings/EditorBuildSettings.asset
+++ b/tutorials/pick_and_place/PickAndPlaceProject/ProjectSettings/EditorBuildSettings.asset
@@ -4,5 +4,11 @@
EditorBuildSettings:
m_ObjectHideFlags: 0
serializedVersion: 2
- m_Scenes: []
+ m_Scenes:
+ - enabled: 0
+ path: Assets/Tests/PlayMode/PlayModeTestScenes/TargetPlacementTest.unity
+ guid: 3d328f38f71b71e47bb8d96869012ffe
+ - enabled: 1
+ path: Assets/Tests/PlayMode/PlayModeTestScenes/TargetPlacementTest.unity
+ guid: 3d328f38f71b71e47bb8d96869012ffe
m_configObjects: {}
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/ProjectSettings/EditorSettings.asset b/tutorials/pick_and_place/PickAndPlaceProject/ProjectSettings/EditorSettings.asset
index de5d0b2d..4062e59c 100644
--- a/tutorials/pick_and_place/PickAndPlaceProject/ProjectSettings/EditorSettings.asset
+++ b/tutorials/pick_and_place/PickAndPlaceProject/ProjectSettings/EditorSettings.asset
@@ -4,9 +4,8 @@
EditorSettings:
m_ObjectHideFlags: 0
serializedVersion: 11
- m_ExternalVersionControlSupport: Visible Meta Files
m_SerializationMode: 2
- m_LineEndingsForNewScripts: 0
+ m_LineEndingsForNewScripts: 1
m_DefaultBehaviorMode: 0
m_PrefabRegularEnvironment: {fileID: 0}
m_PrefabUIEnvironment: {fileID: 0}
@@ -18,13 +17,24 @@ EditorSettings:
m_EtcTextureBestCompressor: 4
m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;rsp;asmref
m_ProjectGenerationRootNamespace:
- m_CollabEditorSettings:
- inProgressEnabled: 1
m_EnableTextureStreamingInEditMode: 1
m_EnableTextureStreamingInPlayMode: 1
m_AsyncShaderCompilation: 1
+ m_CachingShaderPreprocessor: 1
+ m_PrefabModeAllowAutoSave: 1
m_EnterPlayModeOptionsEnabled: 0
m_EnterPlayModeOptions: 3
- m_ShowLightmapResolutionOverlay: 1
+ m_GameObjectNamingDigits: 1
+ m_GameObjectNamingScheme: 0
+ m_AssetNamingUsesSpace: 1
m_UseLegacyProbeSampleCount: 0
- m_SerializeInlineMappingsOnOneLine: 1
\ No newline at end of file
+ m_SerializeInlineMappingsOnOneLine: 1
+ m_DisableCookiesInLightmapper: 0
+ m_AssetPipelineMode: 1
+ m_CacheServerMode: 0
+ m_CacheServerEndpoint:
+ m_CacheServerNamespacePrefix: default
+ m_CacheServerEnableDownload: 1
+ m_CacheServerEnableUpload: 1
+ m_CacheServerEnableAuth: 0
+ m_CacheServerEnableTls: 0
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/ProjectSettings/ProjectSettings.asset b/tutorials/pick_and_place/PickAndPlaceProject/ProjectSettings/ProjectSettings.asset
index 2b2f2b00..51b1ad16 100644
--- a/tutorials/pick_and_place/PickAndPlaceProject/ProjectSettings/ProjectSettings.asset
+++ b/tutorials/pick_and_place/PickAndPlaceProject/ProjectSettings/ProjectSettings.asset
@@ -12,8 +12,8 @@ PlayerSettings:
targetDevice: 2
useOnDemandResources: 0
accelerometerFrequency: 60
- companyName: DefaultCompany
- productName: PickAndPlaceProject
+ companyName: UnityRobotics
+ productName: PickAndPlace
defaultCursor: {fileID: 0}
cursorHotspot: {x: 0, y: 0}
m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1}
@@ -146,7 +146,7 @@ PlayerSettings:
androidSupportedAspectRatio: 1
androidMaxAspectRatio: 2.1
applicationIdentifier:
- Standalone: com.DefaultCompany.PickAndPlaceProject
+ Standalone: com.UnityRobotics.PickAndPlace
buildNumber:
Standalone: 0
iPhone: 0
@@ -573,8 +573,10 @@ PlayerSettings:
webGLLinkerTarget: 1
webGLThreadsSupport: 0
webGLDecompressionFallback: 0
- scriptingDefineSymbols: {}
- additionalCompilerArguments: {}
+ scriptingDefineSymbols:
+ 1:
+ additionalCompilerArguments:
+ 1: []
platformArchitecture: {}
scriptingBackend: {}
il2cppCompilerConfiguration: {}
diff --git a/tutorials/pick_and_place/PickAndPlaceProject/ProjectSettings/ProjectVersion.txt b/tutorials/pick_and_place/PickAndPlaceProject/ProjectSettings/ProjectVersion.txt
index ccec5356..e610e282 100644
--- a/tutorials/pick_and_place/PickAndPlaceProject/ProjectSettings/ProjectVersion.txt
+++ b/tutorials/pick_and_place/PickAndPlaceProject/ProjectSettings/ProjectVersion.txt
@@ -1,2 +1,2 @@
-m_EditorVersion: 2020.2.0b9
-m_EditorVersionWithRevision: 2020.2.0b9 (ef2968fa77ae)
+m_EditorVersion: 2020.3.11f1
+m_EditorVersionWithRevision: 2020.3.11f1 (99c7afb366b3)
diff --git a/tutorials/pick_and_place/ROS/src/niryo_moveit/scripts/server_endpoint.py b/tutorials/pick_and_place/ROS/src/niryo_moveit/scripts/server_endpoint.py
index 3dc74ebe..9d9c65ac 100755
--- a/tutorials/pick_and_place/ROS/src/niryo_moveit/scripts/server_endpoint.py
+++ b/tutorials/pick_and_place/ROS/src/niryo_moveit/scripts/server_endpoint.py
@@ -15,7 +15,7 @@ def main():
# Start the Server Endpoint with a ROS communication objects dictionary for routing messages
tcp_server.start({
- 'SourceDestination_input': RosPublisher('SourceDestination', NiryoMoveitJoints, queue_size=10),
+ 'SourceDestination_input': RosPublisher('SourceDestination_input', NiryoMoveitJoints, queue_size=10),
'NiryoTrajectory': RosSubscriber('NiryoTrajectory', NiryoTrajectory, tcp_server),
'niryo_moveit': RosService('niryo_moveit', MoverService),
'niryo_one/commander/robot_action/goal': RosSubscriber('niryo_one/commander/robot_action/goal', RobotMoveActionGoal, tcp_server),
diff --git a/tutorials/pick_and_place/ROS/src/ros_tcp_endpoint b/tutorials/pick_and_place/ROS/src/ros_tcp_endpoint
index 18612dcb..f978d948 160000
--- a/tutorials/pick_and_place/ROS/src/ros_tcp_endpoint
+++ b/tutorials/pick_and_place/ROS/src/ros_tcp_endpoint
@@ -1 +1 @@
-Subproject commit 18612dcb5f8ce662e691926930aa6469714d82aa
+Subproject commit f978d948c35e5c14542839b5f8c2e715c4b61a1d
diff --git a/tutorials/pick_and_place/Scripts/SourceDestinationPublisher.cs b/tutorials/pick_and_place/Scripts/SourceDestinationPublisher.cs
index 7fc2fab5..a2d649a5 100644
--- a/tutorials/pick_and_place/Scripts/SourceDestinationPublisher.cs
+++ b/tutorials/pick_and_place/Scripts/SourceDestinationPublisher.cs
@@ -52,7 +52,7 @@ void Start()
public void Publish()
{
- MNiryoMoveitJoints sourceDestinationMessage = new MNiryoMoveitJoints();
+ NiryoMoveitJointsMsg sourceDestinationMessage = new NiryoMoveitJointsMsg();
sourceDestinationMessage.joint_00 = jointArticulationBodies[0].xDrive.target;
sourceDestinationMessage.joint_01 = jointArticulationBodies[1].xDrive.target;
@@ -62,14 +62,14 @@ public void Publish()
sourceDestinationMessage.joint_05 = jointArticulationBodies[5].xDrive.target;
// Pick Pose
- sourceDestinationMessage.pick_pose = new MPose
+ sourceDestinationMessage.pick_pose = new PoseMsg
{
position = target.transform.position.To(),
orientation = Quaternion.Euler(90, target.transform.eulerAngles.y, 0).To()
};
// Place Pose
- sourceDestinationMessage.place_pose = new MPose
+ sourceDestinationMessage.place_pose = new PoseMsg
{
position = targetPlacement.transform.position.To(),
orientation = pickOrientation.To()
diff --git a/tutorials/pick_and_place/Scripts/TrajectoryPlanner.cs b/tutorials/pick_and_place/Scripts/TrajectoryPlanner.cs
index a9b57d2e..cd8251d6 100644
--- a/tutorials/pick_and_place/Scripts/TrajectoryPlanner.cs
+++ b/tutorials/pick_and_place/Scripts/TrajectoryPlanner.cs
@@ -78,9 +78,9 @@ private void OpenGripper()
/// Get the current values of the robot's joint angles.
///
/// NiryoMoveitJoints
- MNiryoMoveitJoints CurrentJointConfig()
+ NiryoMoveitJointsMsg CurrentJointConfig()
{
- MNiryoMoveitJoints joints = new MNiryoMoveitJoints();
+ NiryoMoveitJointsMsg joints = new NiryoMoveitJointsMsg();
joints.joint_00 = jointArticulationBodies[0].xDrive.target;
joints.joint_01 = jointArticulationBodies[1].xDrive.target;
@@ -101,11 +101,11 @@ MNiryoMoveitJoints CurrentJointConfig()
///
public void PublishJoints()
{
- MMoverServiceRequest request = new MMoverServiceRequest();
+ MoverServiceRequest request = new MoverServiceRequest();
request.joints_input = CurrentJointConfig();
// Pick Pose
- request.pick_pose = new MPose
+ request.pick_pose = new PoseMsg
{
position = (target.transform.position + pickPoseOffset).To(),
// The hardcoded x/z angles assure that the gripper is always positioned above the target cube before grasping.
@@ -113,16 +113,16 @@ public void PublishJoints()
};
// Place Pose
- request.place_pose = new MPose
+ request.place_pose = new PoseMsg
{
position = (targetPlacement.transform.position + pickPoseOffset).To(),
orientation = pickOrientation.To()
};
- ros.SendServiceMessage(rosServiceName, request, TrajectoryResponse);
+ ros.SendServiceMessage(rosServiceName, request, TrajectoryResponse);
}
- void TrajectoryResponse(MMoverServiceResponse response)
+ void TrajectoryResponse(MoverServiceResponse response)
{
if (response.trajectories.Length > 0)
{
@@ -149,7 +149,7 @@ void TrajectoryResponse(MMoverServiceResponse response)
///
/// MoverServiceResponse received from niryo_moveit mover service running in ROS
///
- private IEnumerator ExecuteTrajectories(MMoverServiceResponse response)
+ private IEnumerator ExecuteTrajectories(MoverServiceResponse response)
{
if (response.trajectories != null)
{
diff --git a/tutorials/pick_and_place/Scripts_Part4/RealSimPickAndPlace.cs b/tutorials/pick_and_place/Scripts_Part4/RealSimPickAndPlace.cs
index a02eef5a..86b1005a 100644
--- a/tutorials/pick_and_place/Scripts_Part4/RealSimPickAndPlace.cs
+++ b/tutorials/pick_and_place/Scripts_Part4/RealSimPickAndPlace.cs
@@ -81,7 +81,7 @@ private void OpenGripper()
///
public void PublishJoints()
{
- MMoverServiceRequest request = new MMoverServiceRequest
+ MoverServiceRequest request = new MoverServiceRequest
{
joints_input =
{
@@ -92,13 +92,13 @@ public void PublishJoints()
joint_04 = jointArticulationBodies[4].xDrive.target,
joint_05 = jointArticulationBodies[5].xDrive.target
},
- pick_pose = new MPose
+ pick_pose = new PoseMsg
{
position = (target.transform.position + PICK_POSE_OFFSET).To(),
// The hardcoded x/z angles assure that the gripper is always positioned above the target cube before grasping.
orientation = Quaternion.Euler(90, target.transform.eulerAngles.y, 0).To()
},
- place_pose = new MPose
+ place_pose = new PoseMsg
{
position = (targetPlacement.transform.position + PICK_POSE_OFFSET).To(),
orientation = pickOrientation.To()
@@ -146,7 +146,7 @@ void Awake()
void Start()
{
- ros.Subscribe(rosRobotCommandsTopicName, ExecuteRobotCommands);
+ ros.Subscribe(rosRobotCommandsTopicName, ExecuteRobotCommands);
}
///
@@ -155,7 +155,7 @@ void Start()
/// executed in a coroutine.
///
/// RobotMoveActionGoal of trajectory or gripper commands
- void ExecuteRobotCommands(MRobotMoveActionGoal robotAction)
+ void ExecuteRobotCommands(RobotMoveActionGoal robotAction)
{
if (robotAction.goal.cmd.cmd_type == TRAJECTORY_COMMAND_EXECUTION)
{
@@ -184,7 +184,7 @@ void ExecuteRobotCommands(MRobotMoveActionGoal robotAction)
///
///
/// The array of poses for the robot to execute
- private IEnumerator ExecuteTrajectories(MRobotTrajectory trajectories)
+ private IEnumerator ExecuteTrajectories(RobotTrajectoryMsg trajectories)
{
// For every robot pose in trajectory plan
foreach (var point in trajectories.joint_trajectory.points)
diff --git a/tutorials/pick_and_place/docker/Dockerfile b/tutorials/pick_and_place/docker/Dockerfile
index 72ecc072..c92a365f 100644
--- a/tutorials/pick_and_place/docker/Dockerfile
+++ b/tutorials/pick_and_place/docker/Dockerfile
@@ -1,5 +1,7 @@
FROM ros:melodic-ros-base
+RUN sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys F42ED6FBAB17C654
+
RUN sudo apt-get update && sudo apt-get install -y vim iputils-ping net-tools python-pip ros-melodic-robot-state-publisher ros-melodic-moveit ros-melodic-rosbridge-suite ros-melodic-joy ros-melodic-ros-control ros-melodic-ros-controllers ros-melodic-tf2-web-republisher dos2unix
RUN sudo -H pip install rospkg jsonpickle
diff --git a/tutorials/pick_and_place/docker/set-up-workspace b/tutorials/pick_and_place/docker/set-up-workspace
index 3669ecbb..9eee40eb 100644
--- a/tutorials/pick_and_place/docker/set-up-workspace
+++ b/tutorials/pick_and_place/docker/set-up-workspace
@@ -1,6 +1,6 @@
#!/bin/bash
source /opt/ros/melodic/setup.bash
-echo "ROS_IP: $(hostname -i)" > $ROS_WORKSPACE/src/niryo_moveit/config/params.yaml
+echo "ROS_IP: $(hostname -i)" > $ROS_WORKSPACE/src/ros-tcp-endpoint/config/params.yaml
cd $ROS_WORKSPACE
-catkin_make
\ No newline at end of file
+catkin_make
diff --git a/tutorials/quick_setup.md b/tutorials/quick_setup.md
index 04cbf438..bd90fbd3 100644
--- a/tutorials/quick_setup.md
+++ b/tutorials/quick_setup.md
@@ -11,7 +11,7 @@ This page provides brief instructions on installing the Unity Robotics packages.

-1. Enter the git URL for the desired package. Note: you can append a version tag to the end of the git url, like `#v0.3.0` or `#v0.4.0`, to declare a specific package version, or exclude the tag to get the latest from the package's `main` branch.
+1. Enter the git URL for the desired package. Note: you can append a version tag to the end of the git url, like `#v0.4.0` or `#v0.5.0`, to declare a specific package version, or exclude the tag to get the latest from the package's `main` branch.
1. For the [ROS-TCP-Connector](https://github.com/Unity-Technologies/ROS-TCP-Connector), enter `https://github.com/Unity-Technologies/ROS-TCP-Connector.git?path=/com.unity.robotics.ros-tcp-connector`.
1. For the [URDF-Importer](https://github.com/Unity-Technologies/URDF-Importer), enter `https://github.com/Unity-Technologies/URDF-Importer.git?path=/com.unity.robotics.urdf-importer`.
diff --git a/tutorials/ros_packages/robotics_demo/scripts/color_publisher.py b/tutorials/ros_packages/robotics_demo/scripts/color_publisher.py
deleted file mode 100755
index ac38b11f..00000000
--- a/tutorials/ros_packages/robotics_demo/scripts/color_publisher.py
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/usr/bin/env python
-
-import random
-import rospy
-from robotics_demo.msg import UnityColor
-
-
-TOPIC_NAME = 'color'
-NODE_NAME = 'color_publisher'
-
-
-def post_color():
- pub = rospy.Publisher(TOPIC_NAME, UnityColor, queue_size=10)
- rospy.init_node(NODE_NAME, anonymous=True)
- rate = rospy.Rate(10) # 10hz
-
- while not rospy.is_shutdown():
-
- r = random.randint(0, 255)
- g = random.randint(0, 255)
- b = random.randint(0, 255)
- color = UnityColor(r, g, b, 1)
- pub.publish(color)
- rate.sleep()
- break
-
-
-if __name__ == '__main__':
- try:
- post_color()
- except rospy.ROSInterruptException:
- pass
diff --git a/tutorials/ros_packages/robotics_demo/scripts/object_pose_client.py b/tutorials/ros_packages/robotics_demo/scripts/object_pose_client.py
deleted file mode 100755
index 3ebe8b07..00000000
--- a/tutorials/ros_packages/robotics_demo/scripts/object_pose_client.py
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/usr/bin/env python
-
-from __future__ import print_function
-
-import random
-import rospy
-import sys
-
-from robotics_demo.srv import ObjectPoseService, ObjectPoseServiceResponse
-
-
-def get_object_pose_client(name):
- rospy.wait_for_service('obj_pose_srv')
- try:
- get_obj_pose = rospy.ServiceProxy('obj_pose_srv', ObjectPoseService)
- obj_pose_resp = get_obj_pose(name)
- return obj_pose_resp.object_pose
- except rospy.ServiceException as e:
- print("Service call failed: %s"%e)
-
-
-def usage():
- return "%s [object_name]"%sys.argv[0]
-
-if __name__ == "__main__":
- if len(sys.argv) == 2:
- name = str(sys.argv[1])
- else:
- print(usage())
- sys.exit(1)
- print("Requesting pose for %s"%(name))
- print("Pose for %s: %s"%(name, get_object_pose_client(name)))
diff --git a/tutorials/ros_packages/robotics_demo/scripts/server_endpoint.py b/tutorials/ros_packages/robotics_demo/scripts/server_endpoint.py
deleted file mode 100644
index ababf68c..00000000
--- a/tutorials/ros_packages/robotics_demo/scripts/server_endpoint.py
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/env python
-
-import rospy
-
-from ros_tcp_endpoint import TcpServer, RosPublisher, RosSubscriber, RosService, UnityService
-from robotics_demo.msg import PosRot, UnityColor
-from robotics_demo.srv import PositionService, ObjectPoseService
-
-def main():
- ros_node_name = rospy.get_param("/TCP_NODE_NAME", 'TCPServer')
- buffer_size = rospy.get_param("/TCP_BUFFER_SIZE", 1024)
- connections = rospy.get_param("/TCP_CONNECTIONS", 10)
- tcp_server = TcpServer(ros_node_name, buffer_size, connections)
- rospy.init_node(ros_node_name, anonymous=True)
-
- tcp_server.start({
- 'pos_rot': RosPublisher('pos_rot', PosRot, queue_size=10),
- 'color': RosSubscriber('color', UnityColor, tcp_server),
- 'pos_srv': RosService('pos_srv', PositionService),
- 'obj_pose_srv': UnityService('obj_pose_srv', ObjectPoseService, tcp_server),
- })
-
- rospy.spin()
-
-
-if __name__ == "__main__":
- main()
diff --git a/tutorials/ros_unity_integration/README.md b/tutorials/ros_unity_integration/README.md
index 45997364..f96b7202 100644
--- a/tutorials/ros_unity_integration/README.md
+++ b/tutorials/ros_unity_integration/README.md
@@ -14,13 +14,12 @@ The `ROSConnection` plugin (also from [ROS TCP Connector](https://github.com/Uni
## Tutorials
-- [ROS–Unity Integration: Initial Setup](setup.md) - ROS-Unity Initial Setup
+- [ROS–Unity Integration: Initial Setup](setup.md) - ROS–Unity Initial Setup
- [ROS–Unity Integration: Network Description](network.md) - Description of network settings and troubleshooting
-- [ROS–Unity Integration: Publisher](publisher.md) - Adding a Publisher to a Unity Scene
-- [ROS–Unity Integration: Subscriber](subscriber.md) - Adding a Subscriber to a Unity Scene
-- [ROS–Unity Integration: Service](service.md) - Adding a Service call to a Unity Scene
-- [ROS–Unity Integration: UnityService](unity_service.md) - Adding a Service that runs in a Unity Scene
-- [ROS–Unity Integration: Server Endpoint](server_endpoint.md) - How to write a Server Endpoint
+- [ROS–Unity Integration: Publisher](publisher.md) - Publish messages from a Unity Scene
+- [ROS–Unity Integration: Subscriber](subscriber.md) - Subscribe to receive messages in a Unity Scene
+- [ROS–Unity Integration: Unity Service](unity_service.md) - Implement a service inside a Unity Scene
+- [ROS–Unity Integration: Service Call](service_call.md) - Call an external service from a Unity Scene
## Example Unity Scripts
@@ -32,9 +31,9 @@ Example scripts implemented in tutorials:
- `unity_scripts/RosSubscriberExample.cs`
- Subscribes to a topic that accepts color messages and uses them to change the color of a GameObject in the Unity scene.
-- `unity_scripts/RosServiceExample.cs`
- - Returns a destination position for a GameObject to move towards each time the service is called.
-
- `unity_scripts/RosUnityServiceExample.cs`
- Runs a service in the Unity scene that takes a GameObject's name and responds with the Pose of that object.
+- `unity_scripts/RosServiceExample.cs`
+ - Returns a destination position for a GameObject to move towards each time the service is called.
+
diff --git a/tutorials/ros_unity_integration/images/create_cube.png b/tutorials/ros_unity_integration/images/create_cube.png
new file mode 100644
index 00000000..a91fec1a
Binary files /dev/null and b/tutorials/ros_unity_integration/images/create_cube.png differ
diff --git a/tutorials/ros_unity_integration/images/docker_cli.png b/tutorials/ros_unity_integration/images/docker_cli.png
new file mode 100644
index 00000000..98eceac3
Binary files /dev/null and b/tutorials/ros_unity_integration/images/docker_cli.png differ
diff --git a/tutorials/ros_unity_integration/images/generate_messages_3.png b/tutorials/ros_unity_integration/images/generate_messages_3.png
new file mode 100644
index 00000000..14058159
Binary files /dev/null and b/tutorials/ros_unity_integration/images/generate_messages_3.png differ
diff --git a/tutorials/ros_unity_integration/images/move_tool.png b/tutorials/ros_unity_integration/images/move_tool.png
new file mode 100644
index 00000000..b5d97840
Binary files /dev/null and b/tutorials/ros_unity_integration/images/move_tool.png differ
diff --git a/tutorials/ros_unity_integration/images/ros1_icon.png b/tutorials/ros_unity_integration/images/ros1_icon.png
new file mode 100644
index 00000000..34f2784f
Binary files /dev/null and b/tutorials/ros_unity_integration/images/ros1_icon.png differ
diff --git a/tutorials/ros_unity_integration/images/ros2_icon.png b/tutorials/ros_unity_integration/images/ros2_icon.png
new file mode 100644
index 00000000..dcb7d71d
Binary files /dev/null and b/tutorials/ros_unity_integration/images/ros2_icon.png differ
diff --git a/tutorials/ros_unity_integration/images/ros2_protocol.png b/tutorials/ros_unity_integration/images/ros2_protocol.png
new file mode 100644
index 00000000..d7116862
Binary files /dev/null and b/tutorials/ros_unity_integration/images/ros2_protocol.png differ
diff --git a/tutorials/ros_unity_integration/images/settings_ros_ip.png b/tutorials/ros_unity_integration/images/settings_ros_ip.png
new file mode 100644
index 00000000..dd33dce4
Binary files /dev/null and b/tutorials/ros_unity_integration/images/settings_ros_ip.png differ
diff --git a/tutorials/ros_unity_integration/images/unity-tab-square-white.png b/tutorials/ros_unity_integration/images/unity-tab-square-white.png
new file mode 100644
index 00000000..154551f5
Binary files /dev/null and b/tutorials/ros_unity_integration/images/unity-tab-square-white.png differ
diff --git a/tutorials/ros_unity_integration/network.md b/tutorials/ros_unity_integration/network.md
index cefb66ed..35b5d822 100644
--- a/tutorials/ros_unity_integration/network.md
+++ b/tutorials/ros_unity_integration/network.md
@@ -15,8 +15,6 @@
`ROS_IP` : The IP address of the machine, VM, or container running ROS.
-`UNITY_IP` : The IP address of the machine running Unity.
-
> It is possible to set both of these variables on the machines running Unity and ROS. The specifics of where and why each of these settings will be described below.
On the ROS machine these settings are set as a rosparam and will typically be set in a launch file like [this](https://github.com/Unity-Technologies/Unity-Robotics-Hub/blob/main/tutorials/ros_packages/robotics_demo/launch/robo_demo.launch) or in a [param file](https://github.com/Unity-Technologies/Unity-Robotics-Hub/blob/main/tutorials/pick_and_place/ROS/src/niryo_moveit/config/params.yaml) loaded by a launch file like [this](https://github.com/Unity-Technologies/Unity-Robotics-Hub/blob/main/tutorials/pick_and_place/ROS/src/niryo_moveit/launch/part_3.launch#L2). The param file can also be loaded manually by running the `rosparam load params.yaml` command.
@@ -37,19 +35,10 @@ The container will need to be started with the following arguments to forward th
- On the ROS side, set `ROS_IP` to `0.0.0.0`.
-- On the Unity side, set `ROS_IP` to `127.0.0.1` and the `Override Unity IP Address` to your local machine's IP address.
+- On the Unity side, set `ROS_IP` to `127.0.0.1`.

-## Explicitly setting `UNITY_IP`
-
-The `UNITY_IP` can be set in two different places.
-
-1. If set on the ROS side as a rosparam, the `server_endpoint` will only use this IP to send messages to Unity.
-1. If set on the Unity side as the `Override Unity IP Address`, the `UNITY_IP` on the ROS side will be set to this value during the initial handshake between ROS and Unity once play is pressed in the Editor.
-
-> If the `UNITY_IP` is not set in either of these places, then the IP that makes the first connection to ROS during the initial handshake will be used.
-
# Troubleshooting
## Where Does Communication Break Down
diff --git a/tutorials/ros_unity_integration/publisher.md b/tutorials/ros_unity_integration/publisher.md
index 502d1ab2..9c3421b3 100644
--- a/tutorials/ros_unity_integration/publisher.md
+++ b/tutorials/ros_unity_integration/publisher.md
@@ -2,44 +2,20 @@
Create a simple Unity scene which publishes a GameObject's position and rotation to a [ROS topic](http://wiki.ros.org/ROS/Tutorials/UnderstandingTopics#ROS_Topics).
-## Setting Up ROS
+These instructions cover the setup for both ROS1 and ROS2. Instructions for ROS2 users are marked with this icon:
.
-- Copy the `tutorials/ros_packages/robotics_demo` folder of this repo into the `src` folder in your Catkin workspace.
+## Setting Up
-- Follow the [ROS–Unity Initial Setup](setup.md) guide.
+- Follow the [ROS–Unity Demo Setup](setup.md#ros2-environment) guide.
-- Open a new terminal window and run the following commands:
-
- ```bash
- source devel/setup.bash
- rosrun robotics_demo server_endpoint.py
- ```
-
-Once the server_endpoint has started, it will print something similar to `[INFO] [1603488341.950794]: Starting server on 192.168.50.149:10000`.
-
-- Open another new terminal window, navigate to your ROS workspace, and run the following commands:
- ```bash
- source devel/setup.bash
- rostopic echo pos_rot
- ```
-
-## Setting Up Unity Scene
-- In the menu bar, find and select `Robotics` -> `Generate ROS Messages...`
-- Set the ROS message path to `PATH/TO/Unity-Robotics-Hub/tutorials/ros_packages/robotics_demo`.
- - Expand the robotics_demo subfolder and click "Build 2 msgs" to generate new C# scripts from the ROS .msg files.
-
-
-
- - The generated files will be saved in the default directory `Assets/RosMessages/RoboticsDemo/msg`.
-- Create a new directory in `Assets` and name it `Scripts`
-- Create a new script in the `Scripts` directory and name it `RosPublisherExample.cs`
-- Open `RosPublisherExample.cs` and paste the following code:
- - **Note** Script can be found at `tutorials/ros_unity_integration/unity_scripts`
+## Create Unity Publisher
+- In your Project tab in Unity, create a new C# script and name it `RosPublisherExample`. Paste the following code into the new script file.
+ - (Alternatively, you can drag the script file into Unity from `tutorials/ros_unity_integration/unity_scripts/RosPublisherExample.cs` in this repo.)
```csharp
-using RosMessageTypes.RoboticsDemo;
using UnityEngine;
using Unity.Robotics.ROSTCPConnector;
+using RosMessageTypes.UnityRoboticsDemo;
///
///
@@ -61,6 +37,7 @@ public class RosPublisherExample : MonoBehaviour
{
// start the ROS connection
ros = ROSConnection.instance;
+ ros.RegisterPublisher(topicName);
}
private void Update()
@@ -71,7 +48,7 @@ public class RosPublisherExample : MonoBehaviour
{
cube.transform.rotation = Random.rotation;
- MPosRot cubePos = new MPosRot(
+ PosRotMsg cubePos = new PosRotMsg(
cube.transform.position.x,
cube.transform.position.y,
cube.transform.position.z,
@@ -90,14 +67,48 @@ public class RosPublisherExample : MonoBehaviour
}
```
-- Add a plane and a cube to the empty Unity scene
-- Move the cube a little ways up so it is hovering above the plane
-- In the main menu bar, open `Robotics/ROS Settings`.
- - Set the ROS IP address and port to match the ROS IP and port variables defined when you set up ROS.
+- Add a plane and a cube to your Unity scene. You can create simple geometric shapes in Unity by going to the Hierarchy window, clicking the + button, and navigating to the shape you want to create.
+
+
+
+- Move the cube a little ways up so it is hovering above the plane. To do this, select the cube in the hierarchy window, and click on the move tool in the toolbar at the top left of the Unity window.
+
+
+
+- Draggable arrows will appear around the cube in the Scene view; to move the cube up, drag the vertical (green) arrow upwards.
+
- Create another empty GameObject, name it `RosPublisher` and attach the `RosPublisherExample` script.
- Drag the cube GameObject onto the `Cube` parameter.
-- Pressing play in the Editor should publish a message to the terminal running the `rostopic echo pos_rot` command every 0.5 seconds
+- Press play in the Editor. You should see the connection lights at the top left corner of the Game window turn blue, and something like `[INFO] [1622242057.562860400] [TCPServer]: Connection from 172.17.0.1` appear in the terminal running your server_endpoint.
+
+## Common Errors
+
+If you see the error `Failed to resolve message name: No module named unity_robotics_demo_msgs.msg` followed by `Topic 'pos_rot' is not registered` in the ROS-TCP-Endpoint log, you may have missed the step about installing the unity_robotics_demo_msgs package, or perhaps you forgot to build and/or source it afterwards. Try following the "Install Unity Robotics Demo" instructions [here](setup.md#install-unity-robotics-demo).
+
+## Start the Echo monitor
+
+- To prove that messages are actually being received by ROS, let's run the rostopic echo command.
+
+ a)
In ROS1, open a new terminal window, navigate to your ROS workspace, and run the following commands:
+
+ ```bash
+ source devel/setup.bash
+ rostopic echo pos_rot
+ ```
+
+ b)
In ROS2, the commands to run are
+
+ ```bash
+ source install/setup.bash
+ ros2 topic echo pos_rot
+ ```
+
+- If you're using Docker, you can use the command `docker ps` to get a list of all running containers; `docker exec -ti bash bash` starts a new terminal for the specified container. Alternatively, click the "CLI" button in the Docker UI to open a new terminal ("command line interface").
+
+
+
+- If it's working correctly, you should see the contents of the message Unity is sending appearing every 0.5 seconds.
> Please reference [networking troubleshooting](network.md) doc if any errors are thrown.
diff --git a/tutorials/ros_unity_integration/ros2_docker/Dockerfile b/tutorials/ros_unity_integration/ros2_docker/Dockerfile
new file mode 100644
index 00000000..1daec65a
--- /dev/null
+++ b/tutorials/ros_unity_integration/ros2_docker/Dockerfile
@@ -0,0 +1,22 @@
+FROM ros:foxy-ros-base
+
+# Make ROS2 Workspace Dirss
+RUN mkdir -p /home/dev_ws/src
+
+# Copy ROS2 packages into workspace
+COPY ./ros2_packages/ /home/dev_ws/src
+
+#Check out ROS-TCP-Endpoint, ROS2 version
+RUN git clone https://github.com/Unity-Technologies/ROS-TCP-Endpoint /home/dev_ws/src/ros_tcp_endpoint -b ROS2v0.5.0
+
+# Reference script with commands to source workspace
+COPY ./ros2_docker/source_ros.sh /home/dev_ws/source_ros.sh
+
+# Change to workspace on sign in
+RUN echo "cd home/dev_ws" >> ~/.bashrc
+
+# Build the workspace
+RUN cd home/dev_ws && . /opt/ros/foxy/setup.sh && colcon build
+
+# Source the workspace on sign in
+RUN echo ". install/local_setup.bash" >> ~/.bashrc
diff --git a/tutorials/ros_unity_integration/ros2_docker/source_ros.sh b/tutorials/ros_unity_integration/ros2_docker/source_ros.sh
new file mode 100644
index 00000000..c8b4e141
--- /dev/null
+++ b/tutorials/ros_unity_integration/ros2_docker/source_ros.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+source /opt/ros/foxy/setup.bash
+. install/local_setup.bash
+ros2 launch ros2_test test_launcher.py
diff --git a/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/package.xml b/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/package.xml
new file mode 100644
index 00000000..bf4f2f0c
--- /dev/null
+++ b/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/package.xml
@@ -0,0 +1,25 @@
+
+
+
+ unity_robotics_demo
+ 0.0.1
+ Package for use in ROS-Unity Integration tutorials (ROS2 version)
+ Unity Robotics
+ TODO: License declaration
+
+ ament_copyright
+ ament_flake8
+ ament_pep257
+ python3-pytest
+
+ rclpy
+ std_msgs
+
+ rosidl_default_generators
+ rosidl_default_runtime
+ rosidl_interface_packages
+
+
+ ament_python
+
+
diff --git a/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/resource/unity_robotics_demo b/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/resource/unity_robotics_demo
new file mode 100644
index 00000000..e69de29b
diff --git a/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/setup.cfg b/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/setup.cfg
new file mode 100644
index 00000000..183d7717
--- /dev/null
+++ b/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/setup.cfg
@@ -0,0 +1,4 @@
+[develop]
+script-dir=$base/lib/unity_robotics_demo
+[install]
+install-scripts=$base/lib/unity_robotics_demo
diff --git a/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/setup.py b/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/setup.py
new file mode 100644
index 00000000..a612e7eb
--- /dev/null
+++ b/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/setup.py
@@ -0,0 +1,29 @@
+import glob
+import os
+
+from setuptools import setup
+
+package_name = 'unity_robotics_demo'
+
+setup(
+ name=package_name,
+ version='0.0.1',
+ packages=[package_name],
+ data_files=[
+ ('share/ament_index/resource_index/packages', ['resource/' + package_name]),
+ ('share/' + package_name, ['package.xml']),
+ ],
+ install_requires=['setuptools'],
+ zip_safe=True,
+ maintainer='Unity Robotics',
+ maintainer_email='unity-robotics@unity3d.com',
+ description='ROS2 Unity Integration Testing',
+ license='TODO: License declaration',
+ tests_require=['pytest'],
+ entry_points={
+ 'console_scripts': [
+ 'color_publisher = unity_robotics_demo.color_publisher:main',
+ 'position_service = unity_robotics_demo.position_service:main',
+ ],
+ },
+)
diff --git a/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/test/test_copyright.py b/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/test/test_copyright.py
new file mode 100644
index 00000000..cc8ff03f
--- /dev/null
+++ b/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/test/test_copyright.py
@@ -0,0 +1,23 @@
+# Copyright 2015 Open Source Robotics Foundation, Inc.
+#
+# 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.
+
+from ament_copyright.main import main
+import pytest
+
+
+@pytest.mark.copyright
+@pytest.mark.linter
+def test_copyright():
+ rc = main(argv=['.', 'test'])
+ assert rc == 0, 'Found errors'
diff --git a/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/test/test_flake8.py b/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/test/test_flake8.py
new file mode 100644
index 00000000..27ee1078
--- /dev/null
+++ b/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/test/test_flake8.py
@@ -0,0 +1,25 @@
+# Copyright 2017 Open Source Robotics Foundation, Inc.
+#
+# 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.
+
+from ament_flake8.main import main_with_errors
+import pytest
+
+
+@pytest.mark.flake8
+@pytest.mark.linter
+def test_flake8():
+ rc, errors = main_with_errors(argv=[])
+ assert rc == 0, \
+ 'Found %d code style errors / warnings:\n' % len(errors) + \
+ '\n'.join(errors)
diff --git a/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/test/test_pep257.py b/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/test/test_pep257.py
new file mode 100644
index 00000000..b234a384
--- /dev/null
+++ b/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/test/test_pep257.py
@@ -0,0 +1,23 @@
+# Copyright 2015 Open Source Robotics Foundation, Inc.
+#
+# 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.
+
+from ament_pep257.main import main
+import pytest
+
+
+@pytest.mark.linter
+@pytest.mark.pep257
+def test_pep257():
+ rc = main(argv=['.', 'test'])
+ assert rc == 0, 'Found code style errors / warnings'
diff --git a/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/unity_robotics_demo/__init__.py b/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/unity_robotics_demo/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/unity_robotics_demo/color_publisher.py b/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/unity_robotics_demo/color_publisher.py
new file mode 100644
index 00000000..a6427f1c
--- /dev/null
+++ b/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/unity_robotics_demo/color_publisher.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+
+import random
+import rclpy
+
+from rclpy.node import Node
+
+from unity_robotics_demo_msgs.msg import UnityColor
+
+
+class ColorPublisher(Node):
+
+ def __init__(self):
+ super().__init__('color_publisher')
+ self.publisher_ = self.create_publisher(UnityColor, 'color', 10)
+ timer_period = 0.5 # seconds
+ self.timer = self.create_timer(timer_period, self.timer_callback)
+ self.i = 0
+ self.do_publish()
+
+ def do_publish(self):
+ if self.i == 0:
+ color = UnityColor()
+ color.r = random.randint(0, 255)
+ color.g = random.randint(0, 255)
+ color.b = random.randint(0, 255)
+ color.a = 1
+ self.get_logger().info(f'Publishing: {color}')
+ self.publisher_.publish(color)
+
+ self.i += 1
+
+ def timer_callback(self):
+ quit()
+
+
+def main(args=None):
+ rclpy.init(args=args)
+
+ color_pub = ColorPublisher()
+
+ while rclpy.ok():
+ rclpy.spin_once(color_pub)
+
+ #color_pub.destroy_node()
+ #rclpy.shutdown()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/unity_robotics_demo/position_service.py b/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/unity_robotics_demo/position_service.py
new file mode 100644
index 00000000..72a4d63d
--- /dev/null
+++ b/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/unity_robotics_demo/position_service.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+import random
+import rclpy
+
+from unity_robotics_demo_msgs.srv import PositionService
+
+from rclpy.node import Node
+
+class PositionServiceNode(Node):
+
+ def __init__(self):
+ super().__init__('position_service_node')
+ self.srv = self.create_service(PositionService, 'pos_srv', self.new_position_callback)
+
+ def new_position_callback(self, request, response):
+ response.output.pos_x = random.uniform(-4.0, 4.0)
+ response.output.pos_z = random.uniform(-4.0, 4.0)
+
+ return response
+
+
+def main(args=None):
+ rclpy.init(args=args)
+
+ pos_service = PositionServiceNode()
+
+ rclpy.spin(pos_service)
+
+ rclpy.shutdown()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo_msgs/CMakeLists.txt b/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo_msgs/CMakeLists.txt
new file mode 100644
index 00000000..b3348a74
--- /dev/null
+++ b/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo_msgs/CMakeLists.txt
@@ -0,0 +1,34 @@
+cmake_minimum_required(VERSION 3.5)
+project(unity_robotics_demo_msgs)
+
+# find dependencies
+find_package(rosidl_default_generators REQUIRED)
+find_package(builtin_interfaces REQUIRED)
+find_package(geometry_msgs REQUIRED)
+find_package(std_msgs REQUIRED)
+
+rosidl_generate_interfaces(${PROJECT_NAME}
+ "msg/PosRot.msg"
+ "msg/UnityColor.msg"
+ "srv/PositionService.srv"
+ "srv/ObjectPoseService.srv"
+ DEPENDENCIES builtin_interfaces geometry_msgs std_msgs
+ )
+
+if(BUILD_TESTING)
+ find_package(ament_lint_auto REQUIRED)
+ # the following line skips the linter which checks for copyrights
+ # uncomment the line when a copyright and license is not present in all source files
+ #set(ament_cmake_copyright_FOUND TRUE)
+ # the following line skips cpplint (only works in a git repo)
+ # uncomment the line when this package is not in a git repo
+ #set(ament_cmake_cpplint_FOUND TRUE)
+ ament_lint_auto_find_test_dependencies()
+endif()
+
+ament_package()
+
+
+
+
+
diff --git a/tutorials/ros_packages/robotics_demo/msg/PosRot.msg b/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo_msgs/msg/PosRot.msg
similarity index 100%
rename from tutorials/ros_packages/robotics_demo/msg/PosRot.msg
rename to tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo_msgs/msg/PosRot.msg
diff --git a/tutorials/ros_packages/robotics_demo/msg/UnityColor.msg b/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo_msgs/msg/UnityColor.msg
similarity index 100%
rename from tutorials/ros_packages/robotics_demo/msg/UnityColor.msg
rename to tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo_msgs/msg/UnityColor.msg
diff --git a/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo_msgs/package.xml b/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo_msgs/package.xml
new file mode 100644
index 00000000..74488d6b
--- /dev/null
+++ b/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo_msgs/package.xml
@@ -0,0 +1,25 @@
+
+
+
+ unity_robotics_demo_msgs
+ 0.0.1
+ Messages used by ROS-Unity Integration tutorial (ROS2 version)
+ Unity Robotics
+ TODO: License declaration
+
+ ament_cmake
+
+ ament_lint_auto
+ ament_lint_common
+
+ rosidl_default_generators
+
+ rosidl_default_runtime
+
+ rosidl_interface_packages
+
+
+
+ ament_cmake
+
+
diff --git a/tutorials/ros_packages/robotics_demo/srv/ObjectPoseService.srv b/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo_msgs/srv/ObjectPoseService.srv
similarity index 100%
rename from tutorials/ros_packages/robotics_demo/srv/ObjectPoseService.srv
rename to tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo_msgs/srv/ObjectPoseService.srv
diff --git a/tutorials/ros_packages/robotics_demo/srv/PositionService.srv b/tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo_msgs/srv/PositionService.srv
similarity index 100%
rename from tutorials/ros_packages/robotics_demo/srv/PositionService.srv
rename to tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo_msgs/srv/PositionService.srv
diff --git a/tutorials/ros_unity_integration/ros_docker/Dockerfile b/tutorials/ros_unity_integration/ros_docker/Dockerfile
new file mode 100644
index 00000000..f2ea2a15
--- /dev/null
+++ b/tutorials/ros_unity_integration/ros_docker/Dockerfile
@@ -0,0 +1,24 @@
+FROM ros:melodic-ros-base
+
+ENV ROS_WORKSPACE=/catkin_ws
+
+# Copy packages
+COPY ./ros_packages/ $ROS_WORKSPACE/src/
+
+RUN git clone https://github.com/Unity-Technologies/ROS-TCP-Endpoint $ROS_WORKSPACE/src/ros_tcp_endpoint -b v0.5.0
+
+COPY ./ros_docker/set-up-workspace /setup.sh
+#COPY docker/tutorial /
+
+RUN chmod +x /setup.sh && /setup.sh && rm /setup.sh
+
+WORKDIR $ROS_WORKSPACE
+
+# Source the workspace on sign in
+RUN echo ". devel/setup.bash" >> ~/.bashrc
+
+# making sure the file modes are executable
+RUN chmod +x src/ros_tcp_endpoint/src/ros_tcp_endpoint/*.py
+
+#ENTRYPOINT ["/tutorial"]
+
diff --git a/tutorials/ros_unity_integration/ros_docker/set-up-workspace b/tutorials/ros_unity_integration/ros_docker/set-up-workspace
new file mode 100644
index 00000000..634d1a13
--- /dev/null
+++ b/tutorials/ros_unity_integration/ros_docker/set-up-workspace
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+source /opt/ros/melodic/setup.bash
+echo "ROS_IP: 0.0.0.0" > $ROS_WORKSPACE/src/ros_tcp_endpoint/config/params.yaml
+cd $ROS_WORKSPACE
+catkin_make
\ No newline at end of file
diff --git a/tutorials/ros_packages/robotics_demo/CMakeLists.txt b/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo/CMakeLists.txt
similarity index 79%
rename from tutorials/ros_packages/robotics_demo/CMakeLists.txt
rename to tutorials/ros_unity_integration/ros_packages/unity_robotics_demo/CMakeLists.txt
index bd843c37..993703c9 100644
--- a/tutorials/ros_packages/robotics_demo/CMakeLists.txt
+++ b/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo/CMakeLists.txt
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 2.8.3)
-project(robotics_demo)
+project(unity_robotics_demo)
find_package(catkin REQUIRED COMPONENTS
rospy
@@ -9,22 +9,11 @@ find_package(catkin REQUIRED COMPONENTS
message_generation
)
-add_message_files(DIRECTORY msg)
-
-add_service_files(DIRECTORY srv)
-
-generate_messages(
- DEPENDENCIES
- geometry_msgs
- std_msgs
-)
-
catkin_package(CATKIN_DEPENDS
ros_tcp_endpoint
message_runtime)
catkin_install_python(PROGRAMS
- scripts/server_endpoint.py
scripts/position_service.py
scripts/color_publisher.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
diff --git a/tutorials/ros_packages/robotics_demo/launch/robo_demo.launch b/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo/launch/robo_demo.launch
similarity index 100%
rename from tutorials/ros_packages/robotics_demo/launch/robo_demo.launch
rename to tutorials/ros_unity_integration/ros_packages/unity_robotics_demo/launch/robo_demo.launch
diff --git a/tutorials/ros_packages/robotics_demo/package.xml b/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo/package.xml
similarity index 75%
rename from tutorials/ros_packages/robotics_demo/package.xml
rename to tutorials/ros_unity_integration/ros_packages/unity_robotics_demo/package.xml
index f7ee200f..a967ae0d 100644
--- a/tutorials/ros_packages/robotics_demo/package.xml
+++ b/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo/package.xml
@@ -1,8 +1,8 @@
- robotics_demo
+ unity_robotics_demo
0.0.0
- The robotics_demo package
+ The unity_robotics_demo package (ROS1 version)
Unity Robotics
@@ -14,13 +14,16 @@
message_generation
std_msgs
ros_tcp_endpoint
+ unity_robotics_demo_msgs
rospy
std_msgs
ros_tcp_endpoint
+ unity_robotics_demo_msgs
message_runtime
rospy
std_msgs
ros_tcp_endpoint
+ unity_robotics_demo_msgs
diff --git a/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo/scripts/color_publisher.py b/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo/scripts/color_publisher.py
new file mode 100644
index 00000000..28dc4e29
--- /dev/null
+++ b/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo/scripts/color_publisher.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+
+import random
+import rospy
+import rosgraph
+import time
+from unity_robotics_demo_msgs.msg import UnityColor
+
+
+TOPIC_NAME = 'color'
+NODE_NAME = 'color_publisher'
+
+
+def post_color():
+ pub = rospy.Publisher(TOPIC_NAME, UnityColor, queue_size=10)
+ rospy.init_node(NODE_NAME, anonymous=True)
+
+ r = random.randint(0, 255)
+ g = random.randint(0, 255)
+ b = random.randint(0, 255)
+ color = UnityColor(r, g, b, 1)
+
+ wait_for_connections(pub, TOPIC_NAME)
+ pub.publish(color)
+
+ time.sleep(0.1)
+
+
+def wait_for_connections(pub, topic):
+ ros_master = rosgraph.Master('/rostopic')
+ topic = rosgraph.names.script_resolve_name('rostopic', topic)
+ num_subs = 0
+ for sub in ros_master.getSystemState()[1]:
+ if sub[0] == topic:
+ num_subs+=1
+
+ for i in range(10):
+ if pub.get_num_connections() == num_subs:
+ return
+ time.sleep(0.1)
+ raise RuntimeError("failed to get publisher")
+
+
+if __name__ == '__main__':
+ try:
+ post_color()
+ except rospy.ROSInterruptException:
+ pass
diff --git a/tutorials/ros_packages/robotics_demo/scripts/position_service.py b/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo/scripts/position_service.py
old mode 100755
new mode 100644
similarity index 87%
rename from tutorials/ros_packages/robotics_demo/scripts/position_service.py
rename to tutorials/ros_unity_integration/ros_packages/unity_robotics_demo/scripts/position_service.py
index 1a0e11a5..d2e5ef2a
--- a/tutorials/ros_packages/robotics_demo/scripts/position_service.py
+++ b/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo/scripts/position_service.py
@@ -5,7 +5,7 @@
import random
import rospy
-from robotics_demo.srv import PositionService, PositionServiceResponse
+from unity_robotics_demo_msgs.srv import PositionService, PositionServiceResponse
def new_position(req):
diff --git a/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/CMakeLists.txt b/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/CMakeLists.txt
new file mode 100644
index 00000000..5ab09ce3
--- /dev/null
+++ b/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/CMakeLists.txt
@@ -0,0 +1,40 @@
+cmake_minimum_required(VERSION 2.8.3)
+project(unity_robotics_demo_msgs)
+
+find_package(catkin REQUIRED COMPONENTS
+ rospy
+ std_msgs
+ geometry_msgs
+ message_generation
+)
+
+add_message_files(FILES
+ PosRot.msg
+ UnityColor.msg
+)
+add_service_files(FILES
+ ObjectPoseService.srv
+ PositionService.srv
+)
+
+generate_messages(
+ DEPENDENCIES
+ geometry_msgs
+ std_msgs
+)
+
+catkin_package(CATKIN_DEPENDS
+ message_runtime)
+
+#############
+## Testing ##
+#############
+
+## Add gtest based cpp test target and link libraries
+# catkin_add_gtest(${PROJECT_NAME}-test test/test_robotics_demo.cpp)
+# if(TARGET ${PROJECT_NAME}-test)
+# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
+# endif()
+
+## Add folders to be run by python nosetests
+# catkin_add_nosetests(test)
diff --git a/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/msg/PosRot.msg b/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/msg/PosRot.msg
new file mode 100644
index 00000000..43abb1f5
--- /dev/null
+++ b/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/msg/PosRot.msg
@@ -0,0 +1,7 @@
+float32 pos_x
+float32 pos_y
+float32 pos_z
+float32 rot_x
+float32 rot_y
+float32 rot_z
+float32 rot_w
\ No newline at end of file
diff --git a/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/msg/UnityColor.msg b/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/msg/UnityColor.msg
new file mode 100644
index 00000000..a77ff60b
--- /dev/null
+++ b/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/msg/UnityColor.msg
@@ -0,0 +1,4 @@
+int32 r
+int32 g
+int32 b
+int32 a
diff --git a/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/package.xml b/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/package.xml
new file mode 100644
index 00000000..39ab862f
--- /dev/null
+++ b/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/package.xml
@@ -0,0 +1,28 @@
+
+
+ unity_robotics_demo_msgs
+ 0.0.1
+ Messages for the unity_robotics_demo package (ROS1 version)
+
+ Unity Robotics
+
+
+ Apache 2.0
+
+ catkin
+ message_generation
+ std_msgs
+ rospy
+ std_msgs
+ message_runtime
+ rospy
+ std_msgs
+ ros_tcp_endpoint
+
+
+
+
+
+
+
+
diff --git a/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/srv/ObjectPoseService.srv b/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/srv/ObjectPoseService.srv
new file mode 100644
index 00000000..83d3c5b9
--- /dev/null
+++ b/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/srv/ObjectPoseService.srv
@@ -0,0 +1,3 @@
+string object_name
+---
+geometry_msgs/Pose object_pose
diff --git a/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/srv/PositionService.srv b/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/srv/PositionService.srv
new file mode 100644
index 00000000..e780c56e
--- /dev/null
+++ b/tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/srv/PositionService.srv
@@ -0,0 +1,3 @@
+PosRot input
+---
+PosRot output
\ No newline at end of file
diff --git a/tutorials/ros_unity_integration/server_endpoint.md b/tutorials/ros_unity_integration/server_endpoint.md
deleted file mode 100644
index a27fc7e6..00000000
--- a/tutorials/ros_unity_integration/server_endpoint.md
+++ /dev/null
@@ -1,154 +0,0 @@
-# ROS–Unity Integration: Server Endpoint
-
-A walkthrough of the important components of a ROS TCP endpoint script using the `robotics_demo` package as a example.
-
-The following is an example of a server endpoint Python script that:
-
-- Gets parameters from `rosparam`
-- Creates corresponding ROS Publisher, Subscriber, and Service objects to interact with topics and services running in ROS network
-- Starts TCP Server process to handle incoming and outgoing connections
-
-
-```python
-#!/usr/bin/env python
-
-import rospy
-
-from ros_tcp_endpoint import TcpServer, RosPublisher, RosSubscriber, RosService, UnityService
-from robotics_demo.msg import PosRot, UnityColor
-from robotics_demo.srv import PositionService, ObjectPoseService
-
-def main():
- ros_node_name = rospy.get_param("/TCP_NODE_NAME", 'TCPServer')
- buffer_size = rospy.get_param("/TCP_BUFFER_SIZE", 1024)
- connections = rospy.get_param("/TCP_CONNECTIONS", 10)
- tcp_server = TcpServer(ros_node_name, buffer_size, connections)
- rospy.init_node(ros_node_name, anonymous=True)
-
- tcp_server.start({
- 'pos_rot': RosPublisher('pos_rot', PosRot, queue_size=10),
- 'color': RosSubscriber('color', UnityColor, tcp_server),
- 'pos_srv': RosService('pos_srv', PositionService),
- 'obj_pose_srv': UnityService('obj_pose_srv', ObjectPoseService, tcp_server),
- })
-
- rospy.spin()
-
-
-if __name__ == "__main__":
- main()
-```
-
-
-## Import Statements for Services and Messages
-```python
-from ros_tcp_endpoint import TcpServer, RosPublisher, RosSubscriber, RosService, UnityService
-from robotics_demo.msg import PosRot, UnityColor
-from robotics_demo.srv import PositionService, ObjectPoseService
-```
-
-## Creating the Server
-
-Requires:
-
-- The ROS node name
-
-```python
- tcp_server = TcpServer(ros_node_name, buffer_size, connections)
-```
-
-The `ros_node_name` argument is required and the `buffer_size` and `connections` are optional. They are set to `1024` and `10` by default if not provided in the constructor arguments.
-
-## Instantiate the ROS Node
-
-```python
- rospy.init_node(ros_node_name, anonymous=True)
-```
-
-## Starting the Server
-
-```python
- tcp_server.start({
- 'pos_rot': RosPublisher('pos_rot', PosRot, queue_size=10),
- 'color': RosSubscriber('color', UnityColor, tcp_server),
- 'pos_srv': RosService('pos_srv', PositionService),
- 'obj_pose_srv': UnityService('obj_pose_srv', ObjectPoseService, tcp_server),
- })
-
- rospy.spin()
-```
-
-## Source Destination Dictionary
-
-The argument to start() is a dictionary keyed by topic or service with the corresponding ROS communication class as the value. The dictionary is used by the TCP server to direct messages to and from the ROS network.
-
-## ROS Publisher
-A ROS Publisher allows a Unity component to send messages on a given topic to other ROS nodes. It requires three components:
-
-- Topic name
-- ROS message class generated from running `catkin_make` command
-- Queue size (optional)
-
-`RosPublisher('pos_rot', PosRot, queue_size=10)`
-
-## ROS Subscriber
-A ROS Subscriber allows a Unity component to receive messages from other ROS nodes on a given topic. It requires three components:
-
-- Topic name
-- ROS message class generated from running `catkin_make` command
-- The tcp server that will connect to Unity
-
-`RosSubscriber('color', UnityColor, tcp_server)`
-
-## ROS Service
-A ROS Service is similar to a RosPublisher, in that a Unity component sends a Request message to another ROS node. Unlike a Publisher, the Unity component then waits for a Response back. It requires two components:
-
-- Service name
-- ROS Service class generated from running `catkin_make` command
-
-`RosService('pos_srv', PositionService)`
-
-## Unity Service
-
-A Unity Service is similar to a RosSubscriber, in that a Unity component receives a Request message from another ROS node. It then sends a Response back. It requires three components:
-
-- Service name
-- ROS Service class generated from running `catkin_make` command
-- The tcp server that will connect to Unity
-
-`UnityService('obj_pose_srv', ObjectPoseService, tcp_server)`
-
-
-## Parameters
-
-The following parameters can be hardcoded, but for the sake of portability, we recommend setting the parameters using the `rosparam set` command, or a `rosparam` YAML file.
-
-```python
- ros_node_name = rospy.get_param("/TCP_NODE_NAME", 'TCPServer')
- buffer_size = rospy.get_param("/TCP_BUFFER_SIZE", 1024)
- connections = rospy.get_param("/TCP_CONNECTIONS", 10)
-```
-
-In addition, the TCPServer class uses the ROS parameters ROS_IP and ROS_TCP_PORT to determine what ip & port to listen on.
-
-> Note: Read more about the ROS Parameter Server [here](http://wiki.ros.org/Parameter%20Server).
-
-## Launch File
-An example launch file that will set the appropriate ROSPARAM values required for a parameterized TCP Endpoint script.
-
-```
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-```
\ No newline at end of file
diff --git a/tutorials/ros_unity_integration/service.md b/tutorials/ros_unity_integration/service.md
deleted file mode 100644
index 6cb57f69..00000000
--- a/tutorials/ros_unity_integration/service.md
+++ /dev/null
@@ -1,112 +0,0 @@
-# ROS–Unity Integration: Service
-
-Create a simple Unity scene which calls a [ROS service](http://wiki.ros.org/Services) with a GameObject's position and rotation to receive a new position to move the GameObject towards.
-
-## Setting Up ROS
-
-(Skip to [Start the Position service](service.md#start-the-position-service) if you already did the [ROS–Unity Integration Publisher](publisher.md) or [Subscriber](subscriber.md) tutorials.)
-
-- Copy the `tutorials/ros_packages/robotics_demo` folder of this repo into the `src` folder in your Catkin workspace.
-
-- Follow the [ROS–Unity Initial Setup](setup.md) guide.
-
-- Open a new terminal window, navigate to your ROS workspace, and run the following commands:
-
- ```bash
- source devel/setup.bash
- rosrun robotics_demo server_endpoint.py
- ```
-
-Once the server_endpoint has started, it will print something similar to `[INFO] [1603488341.950794]: Starting server on 192.168.50.149:10000`.
-
-## Start the Position service
-- Open a new terminal window, navigate to your ROS workspace, and run the following commands:
-
- ```bash
- source devel/setup.bash
- rosrun robotics_demo position_service.py
- ```
-
-## Setting Up Unity Scene
-- Generate the C# code for `PositionService`'s messages by going to `Robotics` -> `Generate ROS Messages...`
-- Set the input file path to `PATH/TO/Unity-Robotics-Hub/tutorials/ros_packages/robotics_demo`, expand the robotics_demo folder and click `Build 2 srvs`.
-
-
-
- - The generated files will be saved in the default directory `Assets/RosMessages/RoboticsDemo/srv`.
-- Create a script and name it `RosServiceExample.cs`
-- Paste the following code into `RosServiceExample.cs`
- - **Note:** This script can be found at `tutorials/ros_unity_integration/unity_scripts`.
-
-```csharp
-using RosMessageTypes.RoboticsDemo;
-using UnityEngine;
-using Unity.Robotics.ROSTCPConnector;
-
-public class RosServiceExample : MonoBehaviour
-{
- ROSConnection ros;
-
- public string serviceName = "pos_srv";
-
- public GameObject cube;
-
- // Cube movement conditions
- public float delta = 1.0f;
- public float speed = 2.0f;
- private Vector3 destination;
-
- float awaitingResponseUntilTimestamp = -1;
-
- void Start()
- {
- ros = ROSConnection.instance;
- destination = cube.transform.position;
- }
-
- private void Update()
- {
- // Move our position a step closer to the target.
- float step = speed * Time.deltaTime; // calculate distance to move
- cube.transform.position = Vector3.MoveTowards(cube.transform.position, destination, step);
-
- if (Vector3.Distance(cube.transform.position, destination) < delta && Time.time > awaitingResponseUntilTimestamp)
- {
- Debug.Log("Destination reached.");
-
- MPosRot cubePos = new MPosRot(
- cube.transform.position.x,
- cube.transform.position.y,
- cube.transform.position.z,
- cube.transform.rotation.x,
- cube.transform.rotation.y,
- cube.transform.rotation.z,
- cube.transform.rotation.w
- );
-
- MPositionServiceRequest positionServiceRequest = new MPositionServiceRequest(cubePos);
-
- // Send message to ROS and return the response
- ros.SendServiceMessage(serviceName, positionServiceRequest, Callback_Destination);
- awaitingResponseUntilTimestamp = Time.time+1.0f; // don't send again for 1 second, or until we receive a response
- }
- }
-
- void Callback_Destination(MPositionServiceResponse response)
- {
- awaitingResponseUntilTimestamp = -1;
- destination = new Vector3(response.output.pos_x, response.output.pos_y, response.output.pos_z);
- Debug.Log("New Destination: " + destination);
- }
-}
-```
-
-- From the main menu bar, open `Robotics/ROS Settings`, and change the `ROS IP Address` variable to the ROS IP.
-- Create an empty GameObject and name it `RosService`.
-- Attach the `RosServiceExample` script to the `RosService` GameObject. Drag the cube GameObject onto its `cube` parameter.
-- Pressing play in the Editor should start communication with the `position_service` script, running as a ROS node, causing the cube to move to random positions in the scene.
-
-
-> Please reference [networking troubleshooting](network.md) doc if any errors are thrown.
-
-
diff --git a/tutorials/ros_unity_integration/service_call.md b/tutorials/ros_unity_integration/service_call.md
new file mode 100644
index 00000000..299737b1
--- /dev/null
+++ b/tutorials/ros_unity_integration/service_call.md
@@ -0,0 +1,103 @@
+# ROS–Unity Integration: Service Call
+
+Create a simple Unity scene which calls an external [ROS service](http://wiki.ros.org/Services) with a GameObject's position and rotation to receive a new position to move the GameObject towards.
+
+## Setting Up
+
+- Follow the [ROS–Unity Demo Setup](setup.md) guide if you haven't already done so.
+
+## Start the Position service
+- For this tutorial we will need a ros service for Unity to call. In a new terminal window, navigate to your ROS workspace.
+
+ a)
In ROS1, run the following commands:
+
+ ```bash
+ source devel/setup.bash
+ rosrun unity_robotics_demo position_service.py
+ ```
+
+ b)
In ROS2, instead run:
+
+ ```bash
+ source install/setup.bash
+ ros2 run unity_robotics_demo position_service
+ ```
+
+
+## Create Unity Service Caller
+- Create a script and name it `RosServiceCallExample.cs`
+- Paste the following code into `RosServiceCallExample.cs`
+ - (Alternatively, you can drag the script file into Unity from `tutorials/ros_unity_integration/unity_scripts`).
+
+```csharp
+using UnityEngine;
+using Unity.Robotics.ROSTCPConnector;
+using RosMessageTypes.UnityRoboticsDemo;
+
+public class RosServiceCallExample : MonoBehaviour
+{
+ ROSConnection ros;
+
+ public string serviceName = "pos_srv";
+
+ public GameObject cube;
+
+ // Cube movement conditions
+ public float delta = 1.0f;
+ public float speed = 2.0f;
+ private Vector3 destination;
+
+ float awaitingResponseUntilTimestamp = -1;
+
+ void Start()
+ {
+ ros = ROSConnection.instance;
+ ros.RegisterRosService(serviceName);
+ destination = cube.transform.position;
+ }
+
+ private void Update()
+ {
+ // Move our position a step closer to the target.
+ float step = speed * Time.deltaTime; // calculate distance to move
+ cube.transform.position = Vector3.MoveTowards(cube.transform.position, destination, step);
+
+ if (Vector3.Distance(cube.transform.position, destination) < delta && Time.time > awaitingResponseUntilTimestamp)
+ {
+ Debug.Log("Destination reached.");
+
+ PosRotMsg cubePos = new PosRotMsg(
+ cube.transform.position.x,
+ cube.transform.position.y,
+ cube.transform.position.z,
+ cube.transform.rotation.x,
+ cube.transform.rotation.y,
+ cube.transform.rotation.z,
+ cube.transform.rotation.w
+ );
+
+ PositionServiceRequest positionServiceRequest = new PositionServiceRequest(cubePos);
+
+ // Send message to ROS and return the response
+ ros.SendServiceMessage(serviceName, positionServiceRequest, Callback_Destination);
+ awaitingResponseUntilTimestamp = Time.time + 1.0f; // don't send again for 1 second, or until we receive a response
+ }
+ }
+
+ void Callback_Destination(PositionServiceResponse response)
+ {
+ awaitingResponseUntilTimestamp = -1;
+ destination = new Vector3(response.output.pos_x, response.output.pos_y, response.output.pos_z);
+ Debug.Log("New Destination: " + destination);
+ }
+}
+```
+
+- Create an empty GameObject and name it `RosService`.
+- Attach the `RosServiceExample` script to the `RosService` GameObject. Drag the cube GameObject onto its `cube` parameter.
+- Pressing play in the Editor should start communication with the `position_service` script, running as a ROS node, causing the cube to move to random positions in the scene.
+
+
+> Please reference [networking troubleshooting](network.md) doc if any errors are thrown.
+
+
diff --git a/tutorials/ros_unity_integration/setup.md b/tutorials/ros_unity_integration/setup.md
index bae5a7eb..ec06d393 100644
--- a/tutorials/ros_unity_integration/setup.md
+++ b/tutorials/ros_unity_integration/setup.md
@@ -1,65 +1,141 @@
-# ROS–Unity Initial Setup
+# ROS–Unity Demo Setup
-The minimum requirements for a ROS–Unity integration.
+This document is in two parts - part 1 covers the minimum requirements for a ROS–Unity integration. Part 2 sets up the Unity Robotics Demo package, which you will need if you're following the ROS–Unity Integration tutorials.
-## ROS Environment
+These instructions cover both ROS1 and ROS2. The symbols
and
indicate instructions for ROS1 and ROS2 users, respectively. If using ROS2, start with [ROS2 Environment](setup.md#-ros2-environment).
-1. Download and copy the [TCP Endpoint](https://github.com/Unity-Technologies/ROS-TCP-Endpoint) package to the `src` folder in your Catkin workspace.
+##
ROS Environment
-1. Navigate to your Catkin workspace and run `catkin_make && source devel/setup.bash`. Ensure there are no errors.
+Follow these steps to use ROS (melodic or noetic):
-1. Open a new terminal, navigate to your Catkin workspace, and run:
+1.
+ a) If you don't already have a ROS environment set up, we recommend using Docker. Navigate to `tutorials/ros_unity_integration` in your copy of this repo and run the following commands:
```bash
- source devel/setup.bash
- roscore &
+ docker build -t melodic -f ros_docker/Dockerfile .
+ docker run -it --rm -p 10000:10000 melodic /bin/bash
```
-Once ROS Core has started, it will print `started core service [/rosout]` to the terminal window.
+ This should build a docker image and start it.
-1. Note that in the `server_endpoint`, the script fetches parameters for the TCP connection. You will need to know the IP address of your ROS machine as well as the IP address of the machine running Unity.
- - The ROS machine IP, i.e. `ROS_IP` should be the same value as the one set as `Host Name` on the RosConnect component in Unity.
-1. The ROS parameter values can be set using a YAML file. Create a `params.yaml` file in your package, e.g. `./config/params.yaml`. Open the file for editing.
+ b) (Alternative) If you're using your own ROS environment, download and copy the [ROS-TCP-Endpoint](https://github.com/Unity-Technologies/ROS-TCP-Endpoint) package into the `src` folder in your Catkin workspace. Then navigate to your Catkin workspace and run `catkin_make`, then `source devel/setup.bash`. Ensure there are no errors.
-1. Update the `ROS_IP` below with the appropriate address and copy the contents into the `params.yaml` file.
+2. Open a new terminal, navigate to your Catkin workspace, and run:
- ```yaml
- ROS_IP:
- ROS_TCP_PORT: 10000
- ```
+ ```bash
+ source devel/setup.bash
+ roscore
+ ```
+
+ Once ROS Core has started, it will print `started core service [/rosout]` to the terminal window.
- e.g.
+3. In your previous terminal, run the following command, replacing the `` with your ROS machine's IP or hostname.
- ```yaml
- ROS_IP: 127.0.0.1
- ROS_TCP_PORT: 10000
+ ```bash
+ rosparam set ROS_IP
```
- Ensure that the `ROS_TCP_PORT` is set to 10000.
+ - If you're running ROS in a Docker container, you can just use `rosparam set ROS_IP 0.0.0.0`
+ - On Linux you can find out your IP address with the command `hostname -I`
+ - On MacOS you can find out your IP address with `ipconfig getifaddr en0`
-1. Set these newly defined parameters by running `rosparam load`, e.g.:
+6. (Optional) By default, the server_endpoint will listen on port 10000, but this is also controlled by a parameter. If you need to change it, you can run the command `rosparam set ROS_TCP_PORT 10000`, replacing 10000 with the desired port number.
- ```bash
- rosparam load PATH/TO/config/params.yaml
- ```
- Alternatively, this YAML can be loaded from a launch file, e.g.:
+7. Start the server endpoint with the following command:
- ```xml
-
-
-
- ```
+ ```bash
+ rosrun ros_tcp_endpoint default_server_endpoint.py
+ ```
+
+ Once the server_endpoint has started, it will print something similar to `[INFO] [1603488341.950794]: Starting server on 192.168.50.149:10000`.
+
+> Note, for this tutorial we have illustrated how to do everything manually, but for day-to-day use, we recommend starting the endpoint with a launch file. Replace all the above (including the roscore step) with the following command: `roslaunch ros_tcp_endpoint endpoint.launch`.
+> While using this launch file, your ROS_IP and ROS_TCP_PORT parameters are read from the file src/ros_tcp_endpoint/config/params.yaml. You can edit this file to adjust your settings - for example, this command will set the appropriate IP address for your machine:
+> `echo "ROS_IP: $(hostname -i)" > src/ros-tcp-endpoint/config/params.yaml`
> Read more about rosparam YAML options [here](http://wiki.ros.org/rosparam).
>
> Read more about the ROS Parameter Server [here](http://wiki.ros.org/Parameter%20Server).
-## Unity Scene
-1. Launch Unity and create a new scene.
-2. Open Package Manager and click the + button at the top left corner. Select "add package from git URL" and enter "https://github.com/Unity-Technologies/ROS-TCP-Connector.git?path=/com.unity.robotics.ros-tcp-connector" to install the [ROS TCP Connector](https://github.com/Unity-Technologies/ROS-TCP-Connector) package.
+##
ROS2 Environment
+
+Follow these steps if using ROS2:
+
+1.
+ a) If you don't already have a ROS2 environment set up, we recommend using Docker. Navigate to `tutorials/ros_unity_integration` in your copy of this repo and run the following commands:
+
+ ```bash
+ docker build -t foxy -f ros2_docker/Dockerfile .
+ docker run -it --rm -p 10000:10000 foxy /bin/bash
+ ```
+
+ This should build a docker image and start it.
+
+ b) Alternatively, if you're not going to use the Docker image, download the [ROS2 branch of the ROS-TCP-Endpoint](https://github.com/Unity-Technologies/ROS-TCP-Endpoint/tree/ROS2) repository and copy it into the `src` folder in your Colcon workspace. Then navigate to your Colcon workspace and run the following commands:
+
+ ```bash
+ source install/setup.bash
+ colcon build
+ source install/setup.bash
+ ```
+
+ Note: yes, you need to run the source command twice. The first sets up the environment for the build to use, the second time adds the newly built packages to the environent.
+
+2. In your Colcon workspace, run the following command, replacing `` with your ROS machine's IP or hostname.
+
+ ```bash
+ ros2 run ros_tcp_endpoint default_server_endpoint --ros-args -p ROS_IP:=
+ ```
+
+ - If you're running ROS in a Docker container, 0.0.0.0 is a valid incoming address, so you can write `ros2 run ros_tcp_endpoint default_server_endpoint --ros-args -p ROS_IP:=0.0.0.0`
+ - On Linux you can find out your IP address with the command `hostname -I`
+ - On MacOS you can find out your IP address with `ipconfig getifaddr en0`
+
+ Once the server_endpoint has started, it will print something similar to `[INFO] [1603488341.950794]: Starting server on 192.168.50.149:10000`.
+
+3. (Alternative) If you need the server to listen on a port that's different from the default 10000, here's the command line to also set the ROS_TCP_PORT parameter:
+
+ ```bash
+ ros2 run ros_tcp_endpoint default_server_endpoint --ros-args -p ROS_IP:=127.0.0.1 -p ROS_TCP_PORT:=10000
+ ```
+
+##
Unity Setup
+1. Launch Unity and create a new project. The Robotics package works best with a version of Unity no older than 2020.
+2. Open Package Manager and click the + button at the top left corner. Select "add package from git URL" and enter "https://github.com/Unity-Technologies/ROS-TCP-Connector.git?path=/com.unity.robotics.ros-tcp-connector#dev" to install the [ROS-TCP-Connector](https://github.com/Unity-Technologies/ROS-TCP-Connector) package.
+
+ 
+
+ 
+
+3. If you're not using a Docker container, open `Robotics/ROS Settings` from the Unity menu bar, and set the `ROS IP Address` variable to the IP you set earlier. (If you're using Docker, leave it as the default 127.0.0.1.)
+
+ 
+
+4.
Also in the ROS Settings window, ROS2 users should switch the protocol to ROS2 now.
+ 
+
+## Install Unity Robotics Demo
+
+The instructions so far have set up the ROS-TCP-Connector package for general use. If you are specifically following one of the [ROS–Unity Integration tutorials](README.md), you'll need to do the following additional steps:
+
+1. Copy the `unity_robotics_demo` and `unity_robotics_demo_msgs` packages into the `src` folder in your Catkin workspace. (Skip this step if you're using one of the Dockerfiles from this repo: they have the demo packages pre-installed.)
+
+ -
If using ROS1, copy them from from `tutorials/ros_unity_integration/ros_packages` in this repo.
+
+ -
If using ROS2, copy them from `tutorials/ros_unity_integration/ros2_packages` in this repo.
+
+1. Build the new packages.
+
+ -
In ROS1: Run `catkin_make`, and then `source devel/setup.bash` (again) so that ROS can find the newly built messages.
+
+ -
In ROS2: run `colcon build`, then `source install/setup.bash` (again) so that ROS can find the newly built messages.
+
+2. In the Unity menu bar, go to `Robotics` -> `Generate ROS Messages...`. In the Message Browser window, click the Browse button at the top right to set the ROS message path to `tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs` in this repo.
+
+ (Note: The version in the ros2_packages folder is equivalent; ROS2 users can feel free to use it, or not.)
-
+3. In the message browser, expand the unity_robotics_demo_msgs subfolder and click "Build 2 msgs" and "Build 2 srvs" to generate C# scripts from the ROS .msg and .srv files.
-
+ 
-Messages being passed between Unity and ROS need to be serialized exactly as ROS serializes them internally. This is achieved with the RosMessageGeneration utility, which generates C# classes, including serialization and deserialization functions, based on ROS message files. Adding the ROS TCP Connector package should have created a new Unity menu option, “Robotics/Generate ROS Messages”, which we will use to generate these messages later.
\ No newline at end of file
+ The generated files will be saved in the default directories `Assets/RosMessages/UnityRoboticsDemo/msg` and `Assets/RosMessages/UnityRoboticsDemo/srv`. Note, there is no difference between the message scripts generated in ROS1 and ROS2 mode. You don't need to regenerate messages when you switch between them.
diff --git a/tutorials/ros_unity_integration/subscriber.md b/tutorials/ros_unity_integration/subscriber.md
index 5ae578d6..5efea233 100644
--- a/tutorials/ros_unity_integration/subscriber.md
+++ b/tutorials/ros_unity_integration/subscriber.md
@@ -2,39 +2,19 @@
Create a simple Unity scene which subscribes to a [ROS topic](http://wiki.ros.org/ROS/Tutorials/UnderstandingTopics#ROS_Topics) to change the colour of a GameObject.
-## Setting Up ROS
+## Setting Up
-(Skip to [Setting Up Unity Scene](subscriber.md#setting-up-unity-scene) if you already did the [Publisher](publisher.md) tutorial.)
+- Follow the [ROS–Unity Demo Setup](setup.md) guide if you haven't already done so.
-- Copy the `tutorials/ros_packages/robotics_demo` folder of this repo into the `src` folder in your Catkin workspace.
+## Create Unity Subscriber
-- Follow the [ROS–Unity Initial Setup](setup.md) guide.
-
-- Open a new terminal window, navigate to your Catkin workspace, and run the following commands:
-
- ```bash
- source devel/setup.bash
- rosrun robotics_demo server_endpoint.py
- ```
-
-Once the server_endpoint has started, it will print something similar to `[INFO] [1603488341.950794]: Starting server on 192.168.50.149:10000`.
-
-- In Unity, we need to generate the C# code for the `UnityColor` message. Open `Robotics` -> `Generate ROS Messages...`.
- - Set the ROS message path to `PATH/TO/Unity-Robotics-Hub/tutorials/ros_packages/robotics_demo/`, expand the robotics_demo subfolder and click `Build 2 msgs`.
-
-
-
- - The generated files will be saved in the default directory `Assets/RosMessages/RoboticsDemo/msg`.
-
-## Setting Up Unity Scene
-- Create a script and name it `RosSubscriberExample.cs`
-- Paste the following code into `RosSubscriberExample.cs`
- - **Note** Script can be found at `tutorials/ros_unity_integration/unity_scripts`
+- In Unity, create a new C# script and name it `RosSubscriberExample`. Paste the following code into the new script file.
+ (Alternatively, you can drag the script file into Unity from `tutorials/ros_unity_integration/unity_scripts/RosSubscriberExample.cs`.)
```csharp
using UnityEngine;
using Unity.Robotics.ROSTCPConnector;
-using RosColor = RosMessageTypes.RoboticsDemo.MUnityColor;
+using RosColor = RosMessageTypes.UnityRoboticsDemo.UnityColorMsg;
public class RosSubscriberExample : MonoBehaviour
{
@@ -55,14 +35,17 @@ public class RosSubscriberExample : MonoBehaviour
- Create an empty GameObject and name it `RosSubscriber`
- Attach the `RosSubscriberExample` script to the `RosSubscriber` GameObject and drag the cube GameObject onto the `cube` parameter in the Inspector window.
-- From the Unity menu bar, open `Robotics/ROS Settings`, and set the `ROS IP Address` variable to your ROS IP.
- Press play in the editor
### In ROS Terminal Window
-- After the scene has entered Play mode, run the following command: `rosrun robotics_demo color_publisher.py` to change the color of the cube GameObject in Unity to a random color
+Let's send a color message to change the color of the cube GameObject in Unity to a random color.
+
+ a)
In ROS1, run: `rosrun unity_robotics_demo color_publisher.py`
+
+ b)
In ROS2, instead run: `ros2 run unity_robotics_demo color_publisher`
> Please reference [networking troubleshooting](network.md) doc if any errors are thrown.

-Continue to the [ROS–Unity Integration Service](service.md).
\ No newline at end of file
+Continue to the [ROS–Unity Integration Unity Service](unity_service.md).
\ No newline at end of file
diff --git a/tutorials/ros_unity_integration/unity_scripts/RosPublisherExample.cs b/tutorials/ros_unity_integration/unity_scripts/RosPublisherExample.cs
index 64eeba74..c65452be 100644
--- a/tutorials/ros_unity_integration/unity_scripts/RosPublisherExample.cs
+++ b/tutorials/ros_unity_integration/unity_scripts/RosPublisherExample.cs
@@ -1,6 +1,6 @@
-using RosMessageTypes.RoboticsDemo;
using UnityEngine;
using Unity.Robotics.ROSTCPConnector;
+using RosMessageTypes.UnityRoboticsDemo;
///
///
@@ -22,6 +22,7 @@ void Start()
{
// start the ROS connection
ros = ROSConnection.instance;
+ ros.RegisterPublisher(topicName);
}
private void Update()
@@ -32,7 +33,7 @@ private void Update()
{
cube.transform.rotation = Random.rotation;
- MPosRot cubePos = new MPosRot(
+ PosRotMsg cubePos = new PosRotMsg(
cube.transform.position.x,
cube.transform.position.y,
cube.transform.position.z,
diff --git a/tutorials/ros_unity_integration/unity_scripts/RosServiceExample.cs b/tutorials/ros_unity_integration/unity_scripts/RosServiceCallExample.cs
similarity index 79%
rename from tutorials/ros_unity_integration/unity_scripts/RosServiceExample.cs
rename to tutorials/ros_unity_integration/unity_scripts/RosServiceCallExample.cs
index d2e419b8..ea15ed96 100644
--- a/tutorials/ros_unity_integration/unity_scripts/RosServiceExample.cs
+++ b/tutorials/ros_unity_integration/unity_scripts/RosServiceCallExample.cs
@@ -1,4 +1,4 @@
-using RosMessageTypes.RoboticsDemo;
+using RosMessageTypes.UnityRoboticsDemo;
using UnityEngine;
using Unity.Robotics.ROSTCPConnector;
@@ -20,6 +20,7 @@ public class RosServiceExample : MonoBehaviour
void Start()
{
ros = ROSConnection.instance;
+ ros.RegisterRosService(serviceName);
destination = cube.transform.position;
}
@@ -33,7 +34,7 @@ private void Update()
{
Debug.Log("Destination reached.");
- MPosRot cubePos = new MPosRot(
+ PosRotMsg cubePos = new PosRotMsg(
cube.transform.position.x,
cube.transform.position.y,
cube.transform.position.z,
@@ -43,15 +44,15 @@ private void Update()
cube.transform.rotation.w
);
- MPositionServiceRequest positionServiceRequest = new MPositionServiceRequest(cubePos);
+ PositionServiceRequest positionServiceRequest = new PositionServiceRequest(cubePos);
// Send message to ROS and return the response
- ros.SendServiceMessage(serviceName, positionServiceRequest, Callback_Destination);
+ ros.SendServiceMessage(serviceName, positionServiceRequest, Callback_Destination);
awaitingResponseUntilTimestamp = Time.time + 1.0f; // don't send again for 1 second, or until we receive a response
}
}
- void Callback_Destination(MPositionServiceResponse response)
+ void Callback_Destination(PositionServiceResponse response)
{
awaitingResponseUntilTimestamp = -1;
destination = new Vector3(response.output.pos_x, response.output.pos_y, response.output.pos_z);
diff --git a/tutorials/ros_unity_integration/unity_scripts/RosSubscriberExample.cs b/tutorials/ros_unity_integration/unity_scripts/RosSubscriberExample.cs
index c36a3da3..4e1addd9 100644
--- a/tutorials/ros_unity_integration/unity_scripts/RosSubscriberExample.cs
+++ b/tutorials/ros_unity_integration/unity_scripts/RosSubscriberExample.cs
@@ -1,6 +1,6 @@
using UnityEngine;
using Unity.Robotics.ROSTCPConnector;
-using RosColor = RosMessageTypes.RoboticsDemo.MUnityColor;
+using RosColor = RosMessageTypes.UnityRoboticsDemo.UnityColorMsg;
public class RosSubscriberExample : MonoBehaviour
{
diff --git a/tutorials/ros_unity_integration/unity_scripts/RosUnityServiceExample.cs b/tutorials/ros_unity_integration/unity_scripts/RosUnityServiceExample.cs
index 83efb5b4..76ef4296 100644
--- a/tutorials/ros_unity_integration/unity_scripts/RosUnityServiceExample.cs
+++ b/tutorials/ros_unity_integration/unity_scripts/RosUnityServiceExample.cs
@@ -1,4 +1,4 @@
-using RosMessageTypes.RoboticsDemo;
+using RosMessageTypes.UnityRoboticsDemo;
using UnityEngine;
using Unity.Robotics.ROSTCPConnector;
using Unity.Robotics.ROSTCPConnector.ROSGeometry;
@@ -14,7 +14,7 @@ public class RosUnityServiceExample : MonoBehaviour
void Start()
{
// register the service with ROS
- ROSConnection.instance.ImplementService(m_ServiceName, GetObjectPose);
+ ROSConnection.instance.ImplementService(m_ServiceName, GetObjectPose);
}
///
@@ -22,13 +22,13 @@ void Start()
///
/// service request containing the object name
/// service response containing the object pose (or 0 if object not found)
- private MObjectPoseServiceResponse GetObjectPose(MObjectPoseServiceRequest request)
+ private ObjectPoseServiceResponse GetObjectPose(ObjectPoseServiceRequest request)
{
// process the service request
Debug.Log("Received request for object: " + request.object_name);
// prepare a response
- MObjectPoseServiceResponse objectPoseResponse = new MObjectPoseServiceResponse();
+ ObjectPoseServiceResponse objectPoseResponse = new ObjectPoseServiceResponse();
// Find a game object with the requested name
GameObject gameObject = GameObject.Find(request.object_name);
if (gameObject)
diff --git a/tutorials/ros_unity_integration/unity_service.md b/tutorials/ros_unity_integration/unity_service.md
index 15235896..68821934 100644
--- a/tutorials/ros_unity_integration/unity_service.md
+++ b/tutorials/ros_unity_integration/unity_service.md
@@ -1,38 +1,18 @@
# ROS–Unity Integration: UnityService
-Create a simple Unity scene which create a [Service](http://wiki.ros.org/Services) in Unity that takes a request with a GameObject's name and responds with the GameObject's pose (position and orientation) in the ROS coordinate system.
+Create a simple Unity scene which runs a [Service](http://wiki.ros.org/Services) in Unity that takes a request with a GameObject's name and responds with the GameObject's pose (position and orientation) in the ROS coordinate system.
-## Setting Up ROS
+## Setting Up
-(Skip to [Setting Up the Unity Scene](unity_service.md#setting-up-the-unity-scene) if you already did the [ROS–Unity Integration Publisher](publisher.md) or [Subscriber](subscriber.md) tutorials.)
-
-- Copy the `tutorials/ros_packages/robotics_demo` folder of this repo into the `src` folder in your Catkin workspace.
-
-- Follow the [ROS–Unity Initial Setup](setup.md) guide.
-
-- Open a new terminal window, navigate to your ROS workspace, and run the following commands:
-
- ```bash
- source devel/setup.bash
- rosrun robotics_demo server_endpoint.py
- ```
-
-Once the server_endpoint has started, it will print something similar to `[INFO] [1603488341.950794]: Starting server on 192.168.50.149:10000`.
-
-## Setting Up the Unity Scene
-- Generate the C# code for `ObjectPoseService`'s messages by going to `Robotics` -> `Generate ROS Messages...`
- - Set the input file path to `PATH/TO/Unity-Robotics-Hub/tutorials/ros_packages/robotics_demo`, expand the robotics_demo folder and click `Build 2 srvs` (Note that you may skip this step if you have already done it in the previous tutorial).
-
- 
-
- - The generated files will be saved in the default directory `Assets/RosMessages/RoboticsDemo/srv`.
+- Follow the [ROS–Unity Demo Setup](setup.md) guide if you haven't already done so.
+## Create Unity Service
- Create a new C# script and name it `RosUnityServiceExample.cs`
- Paste the following code into `RosUnityServiceExample.cs`
- - **Note:** This script can be found at `tutorials/ros_unity_integration/unity_scripts`.
+ - (Alternatively, you can drag the script file into Unity from `tutorials/ros_unity_integration/unity_scripts`).
```csharp
-using RosMessageTypes.RoboticsDemo;
+using RosMessageTypes.UnityRoboticsDemo;
using UnityEngine;
using Unity.Robotics.ROSTCPConnector;
using Unity.Robotics.ROSTCPConnector.ROSGeometry;
@@ -48,7 +28,7 @@ public class RosUnityServiceExample : MonoBehaviour
void Start()
{
// register the service with ROS
- ROSConnection.instance.ImplementService(m_ServiceName, GetObjectPose);
+ ROSConnection.instance.ImplementService(m_ServiceName, GetObjectPose);
}
///
@@ -56,13 +36,13 @@ public class RosUnityServiceExample : MonoBehaviour
///
/// service request containing the object name
/// service response containing the object pose (or 0 if object not found)
- private MObjectPoseServiceResponse GetObjectPose(MObjectPoseServiceRequest request)
+ private ObjectPoseServiceResponse GetObjectPose(ObjectPoseServiceRequest request)
{
// process the service request
Debug.Log("Received request for object: " + request.object_name);
// prepare a response
- MObjectPoseServiceResponse objectPoseResponse = new MObjectPoseServiceResponse();
+ ObjectPoseServiceResponse objectPoseResponse = new ObjectPoseServiceResponse();
// Find a game object with the requested name
GameObject gameObject = GameObject.Find(request.object_name);
if (gameObject)
@@ -77,41 +57,23 @@ public class RosUnityServiceExample : MonoBehaviour
}
```
-- From the main menu bar, open `Robotics/ROS Settings`, and change the `ROS IP Address` variable to the ROS IP.
- Create an empty GameObject and name it `UnityService`.
- Attach the `RosUnityServiceExample` script to the `UnityService` GameObject.
- Pressing play in the Editor should start running as a ROS node, waiting to accept ObjectPose requests. Once a connection to ROS has been established, a message will be printed on the ROS terminal similar to `Connection from 172.17.0.1`.
## Start the Client
-- On your ROS system, open a new terminal window, navigate to your ROS workspace, and run the following commands:
-
- ```bash
- source devel/setup.bash
- rosrun robotics_demo object_pose_client.py Cube
- ```
-- This wil print an output similar to the following with the current pose information of the game object (note that the coordinates are converted to the ROS coordinate system in our Unity Service):
- ```bash
- Requesting pose for Cube
- Pose for Cube:
- position:
- x: 0.0
- y: -1.0
- z: 0.20000000298023224
- orientation:
- x: 0.0
- y: -0.0
- z: 0.0
- w: -1.0
- ```
-You may replace `Cube` with the name of any other GameObject currently present in the Unity hierarchy.
+- To test our new service is working, let's call it using the built-in ROS service command.
-- Alternatively you may also call the ROS service using `rosservice call`:
+ a)
In ROS1, run the following command in your ROS terminal:
```bash
rosservice call /obj_pose_srv Cube
```
+
+ In your Unity console you should see the log message `Received request for object: Cube`, and in your terminal it will report the object's position, like this:
+
```bash
object_pose:
position:
@@ -123,4 +85,19 @@ You may replace `Cube` with the name of any other GameObject currently present i
y: -0.0
z: 0.0
w: -1.0
- ```
\ No newline at end of file
+ ```
+
+ b)
If you're using ROS2, the command is:
+ ```bash
+ ros2 service call obj_pose_srv unity_robotics_demo_msgs/ObjectPoseService "{object_name: Cube}"
+ ```
+
+ And the output will look like this:
+
+ ```bash
+ requester: making request: unity_robotics_demo_msgs.srv.ObjectPoseService_Request(object_name='Cube')
+ response:
+ unity_robotics_demo_msgs.srv.ObjectPoseService_Response(object_pose=geometry_msgs.msg.Pose(position=geometry_msgs.msg.Point(x=0.0, y=-0.0, z=0.0), orientation=geometry_msgs.msg.Quaternion(x=-0.558996319770813, y=-0.3232670724391937, z=-0.6114855408668518, w=-0.4572822153568268)))
+ ```
+
+Continue to the [ROS–Unity Integration Service Call](service_call.md).
\ No newline at end of file
diff --git a/tutorials/urdf_importer/images/link_hierarchy.png b/tutorials/urdf_importer/images/link_hierarchy.png
new file mode 100644
index 00000000..f6427495
Binary files /dev/null and b/tutorials/urdf_importer/images/link_hierarchy.png differ
diff --git a/tutorials/urdf_importer/images/primitive_scale.png b/tutorials/urdf_importer/images/primitive_scale.png
new file mode 100644
index 00000000..a3c4fbbc
Binary files /dev/null and b/tutorials/urdf_importer/images/primitive_scale.png differ
diff --git a/tutorials/urdf_importer/urdf_appendix.md b/tutorials/urdf_importer/urdf_appendix.md
index 9fd0e8c4..8cd924fe 100644
--- a/tutorials/urdf_importer/urdf_appendix.md
+++ b/tutorials/urdf_importer/urdf_appendix.md
@@ -1,4 +1,15 @@
# URDF Tutorials Appendix
+- [File Hierarchy](##File-Hierarchy)
+- [GameObject Hierarchy](##GameObject-Hierarchy)
+- [URDF Comparator](##URDF-Comparator)
+- [Articulation Body axis definition](##Articulation-Body-axis-definition)
+- [Guide to write your own controller](##Guide-to-write-your-own-controller)
+- [Using FK Robot Script](##Using-FK-Robot-Script)
+- [Convex Mesh Collider](##Convex-Mesh-Collider)
+- [Supported Tags in URDF](##Supported-Tags-in-URDF)
+- [Disable Collision Support](##Disable-Collision-Support)
+- [Sizing of Primitives](##Sizing-of-Primitives)
+
## File Hierarchy
URDF files and associated meshes should be placed in a single folder within the Assets directory of Unity. We suggest creating a new folder with the robot's name and place the URDF file in its root with all associated mesh files in sub folders. Be sure to update the file locations as described by the URDF file.
@@ -316,8 +327,59 @@ To address this predicament we have integrated another algorithm to create Conve

+## Supported Tags in URDF
+
+- Link
+ - Name
+ - Inertial
+ - origin
+ - xyz
+ - rpy
+ - mass
+ - inertia
+ - visual
+ - name
+ - origin
+ - xyz
+ - rpy
+ - geometry
+ - box
+ - cylinder
+ - sphere
+ - mesh
+ - material
+ - color
+ - texture
+ - collision
+ - name
+ - origin
+ - xyz
+ - rpy
+ - geometry
+- joint
+ - name
+ - type
+ - origin
+ - xyz
+ - rpy
+ - parent
+ - link
+ - child
+ - link
+ - axis
+ - xyz
+ - dynamics
+ - damping
+ - friction
+ - limit
+ - lower
+ - upper
+
+
+
+
## Disable Collision Support
-URDF defines the robot visually using Visual Meshes, and its collision using Collision Meshes. Collision meshes define the physical volume of the links, and are used to calculate the inertia of the links and also to detect collisions between different physical objects. In Unity, rigidbodies cannot have concave collision meshes, so when importing a concave collision mesh, all concave regions are closed over to produce a convex outline. As a result, the convex shapes might intersect with each other, creating a hindrance in robot movement. To remedy this, we support a ```disable collision``` tag in URDF. To add an exception for collision detection in Unity:
+URDF defines the robot visually using Visual Meshes, and its collision using Collision Meshes. Collision meshes define the physical volume of the links, and are used to calculate the inertia of the links and also to detect collisions between different physical objects. In Unity, [RigidBodies](https://docs.unity3d.com/ScriptReference/Rigidbody.html) cannot have concave collision meshes, so when importing a concave collision mesh, all concave regions are closed over to produce a convex outline. As a result, the convex shapes might intersect with each other, creating a hindrance in robot movement. To remedy this, we support a ```disable collision``` tag in URDF. To add an exception for collision detection in Unity:
1. Identify the links between which you want to ignore the collisions.
2. Add a tag in the URDF file with the format
@@ -331,3 +393,23 @@ The disable collision tag flags the links that need to be ignored to the URDF pa
Note: You can also manually ignore collisions in Unity using [APIs](https://docs.unity3d.com/ScriptReference/Physics.IgnoreCollision.html).
+## Sizing of Primitives
+
+```xml
+
+
+
+
+
+```
+
+The URDF Importer will set the size of the primitive using the "scale" parameter of the GameObject that contains the UrdfCollsion script.
+
+|  |  |
+|:---:|:---:|
+
+The reason we set the size via the "scale" of the parent GameObject as opposed to the "size" of the primitive collider is to have consistency across different mesh types; the size API is only available for primitive mesh colliders and not for complex collider meshes and visual meshes, whose size must be changed using their parent GameObject's "scale" parameter. The "scale" parameter of the gameObject is also used to set the values of primitive "size" in the URDF when performing a URDF export.
+
+
+
+