Skip to content

Commit

Permalink
Merge pull request #27 from edbeeching/down-fall-env
Browse files Browse the repository at this point in the history
Adds downfall environment
  • Loading branch information
edbeeching authored Feb 20, 2024
2 parents fea9774 + 489db35 commit 879ec38
Show file tree
Hide file tree
Showing 74 changed files with 10,187 additions and 1 deletion.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,7 @@ https://github.com/edbeeching/godot_rl_agents_examples/assets/61947090/d734fbc8-

#### Robot Volleyball:
https://github.com/edbeeching/godot_rl_agents_examples/assets/61947090/fbbba179-d7fb-441d-a98f-f129b15b8f8c

#### DownFall: (Trained with sb3 default params, 2M steps with 4 parallel envs
https://github.com/edbeeching/godot_rl_agents_examples/assets/7275864/a4e4f51f-6fca-465d-8359-f7bf18d2f1c7

2 changes: 2 additions & 0 deletions examples/DownFall/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Normalize EOL for all files that Git considers text files.
* text=auto eol=lf
6 changes: 6 additions & 0 deletions examples/DownFall/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Godot 4+ specific ignores
.godot/

*.import

raw_assets/
11 changes: 11 additions & 0 deletions examples/DownFall/DownFall.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Project Sdk="Godot.NET.Sdk/4.2.1">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework Condition=" '$(GodotTargetPlatform)' == 'android' ">net7.0</TargetFramework>
<TargetFramework Condition=" '$(GodotTargetPlatform)' == 'ios' ">net8.0</TargetFramework>
<EnableDynamicLoading>true</EnableDynamicLoading>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.ML.OnnxRuntime" Version="1.17.0" />
</ItemGroup>
</Project>
Binary file added examples/DownFall/DownFall.onnx
Binary file not shown.
19 changes: 19 additions & 0 deletions examples/DownFall/DownFall.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DownFall", "DownFall.csproj", "{87183EEC-4150-4367-A4CC-E3181E93BD3B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
ExportDebug|Any CPU = ExportDebug|Any CPU
ExportRelease|Any CPU = ExportRelease|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{87183EEC-4150-4367-A4CC-E3181E93BD3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{87183EEC-4150-4367-A4CC-E3181E93BD3B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{87183EEC-4150-4367-A4CC-E3181E93BD3B}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU
{87183EEC-4150-4367-A4CC-E3181E93BD3B}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU
{87183EEC-4150-4367-A4CC-E3181E93BD3B}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU
{87183EEC-4150-4367-A4CC-E3181E93BD3B}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU
EndGlobalSection
EndGlobal
10 changes: 10 additions & 0 deletions examples/DownFall/Godot RL Agents.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Project Sdk="Godot.NET.Sdk/4.0.3">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<EnableDynamicLoading>true</EnableDynamicLoading>
<RootNamespace>GodotRLAgents</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.ML.OnnxRuntime" Version="1.15.1" />
</ItemGroup>
</Project>
25 changes: 25 additions & 0 deletions examples/DownFall/Godot RL Agents.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.33530.505
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Godot RL Agents", "Godot RL Agents.csproj", "{055E8CBC-A3EC-41A8-BC53-EC3010682AE4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
ExportDebug|Any CPU = ExportDebug|Any CPU
ExportRelease|Any CPU = ExportRelease|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{055E8CBC-A3EC-41A8-BC53-EC3010682AE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{055E8CBC-A3EC-41A8-BC53-EC3010682AE4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{055E8CBC-A3EC-41A8-BC53-EC3010682AE4}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU
{055E8CBC-A3EC-41A8-BC53-EC3010682AE4}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU
{055E8CBC-A3EC-41A8-BC53-EC3010682AE4}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU
{055E8CBC-A3EC-41A8-BC53-EC3010682AE4}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
extends Node2D
class_name AIController2D

@export var reset_after := 1000

var heuristic := "human"
var done := false
var reward := 0.0
var n_steps := 0
var needs_reset := false

var _player: Node2D

func _ready():
add_to_group("AGENT")

func init(player: Node2D):
_player = player

#-- Methods that need implementing using the "extend script" option in Godot --#
func get_obs() -> Dictionary:
assert(false, "the get_obs method is not implemented when extending from ai_controller")
return {"obs":[]}

func get_reward() -> float:
assert(false, "the get_reward method is not implemented when extending from ai_controller")
return 0.0

func get_action_space() -> Dictionary:
assert(false, "the get get_action_space method is not implemented when extending from ai_controller")
return {
"example_actions_continous" : {
"size": 2,
"action_type": "continuous"
},
"example_actions_discrete" : {
"size": 2,
"action_type": "discrete"
},
}

func set_action(action) -> void:
assert(false, "the get set_action method is not implemented when extending from ai_controller")
# -----------------------------------------------------------------------------#

func _physics_process(delta):
n_steps += 1
if n_steps > reset_after:
needs_reset = true

func get_obs_space():
# may need overriding if the obs space is complex
var obs = get_obs()
return {
"obs": {
"size": [len(obs["obs"])],
"space": "box"
},
}

func reset():
n_steps = 0
needs_reset = false

func reset_if_done():
if done:
reset()

func set_heuristic(h):
# sets the heuristic from "human" or "model" nothing to change here
heuristic = h

func get_done():
return done

func set_done_false():
done = false

func zero_reward():
reward = 0.0


Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
extends Node3D
class_name AIController3D

@export var reset_after := 1000

var heuristic := "human"
var done := false
var reward := 0.0
var n_steps := 0
var needs_reset := false

var _player: Node3D

func _ready():
add_to_group("AGENT")

func init(player: Node3D):
_player = player

#-- Methods that need implementing using the "extend script" option in Godot --#
func get_obs() -> Dictionary:
assert(false, "the get_obs method is not implemented when extending from ai_controller")
return {"obs":[]}

func get_reward() -> float:
assert(false, "the get_reward method is not implemented when extending from ai_controller")
return 0.0

func get_action_space() -> Dictionary:
assert(false, "the get get_action_space method is not implemented when extending from ai_controller")
return {
"example_actions_continous" : {
"size": 2,
"action_type": "continuous"
},
"example_actions_discrete" : {
"size": 2,
"action_type": "discrete"
},
}

func set_action(action) -> void:
assert(false, "the get set_action method is not implemented when extending from ai_controller")
# -----------------------------------------------------------------------------#

func _physics_process(delta):
n_steps += 1
if n_steps > reset_after:
needs_reset = true

func get_obs_space():
# may need overriding if the obs space is complex
var obs = get_obs()
return {
"obs": {
"size": [len(obs["obs"])],
"space": "box"
},
}

func reset():
n_steps = 0
needs_reset = false

func reset_if_done():
if done:
reset()

func set_heuristic(h):
# sets the heuristic from "human" or "model" nothing to change here
heuristic = h

func get_done():
return done

func set_done_false():
done = false

func zero_reward():
reward = 0.0
16 changes: 16 additions & 0 deletions examples/DownFall/addons/godot_rl_agents/godot_rl_agents.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
@tool
extends EditorPlugin


func _enter_tree():
# Initialization of the plugin goes here.
# Add the new type with a name, a parent type, a script and an icon.
add_custom_type("Sync", "Node", preload("sync.gd"), preload("icon.png"))
#add_custom_type("RaycastSensor2D2", "Node", preload("raycast_sensor_2d.gd"), preload("icon.png"))


func _exit_tree():
# Clean-up of the plugin goes here.
# Always remember to remove it from the engine when deactivated.
remove_custom_type("Sync")
#remove_custom_type("RaycastSensor2D2")
Binary file added examples/DownFall/addons/godot_rl_agents/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
103 changes: 103 additions & 0 deletions examples/DownFall/addons/godot_rl_agents/onnx/csharp/ONNXInference.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
using Godot;
using Microsoft.ML.OnnxRuntime;
using Microsoft.ML.OnnxRuntime.Tensors;
using System.Collections.Generic;
using System.Linq;

namespace GodotONNX
{
/// <include file='docs/ONNXInference.xml' path='docs/members[@name="ONNXInference"]/ONNXInference/*'/>
public partial class ONNXInference : GodotObject
{

private InferenceSession session;
/// <summary>
/// Path to the ONNX model. Use Initialize to change it.
/// </summary>
private string modelPath;
private int batchSize;

private SessionOptions SessionOpt;

//init function
/// <include file='docs/ONNXInference.xml' path='docs/members[@name="ONNXInference"]/Initialize/*'/>
public void Initialize(string Path, int BatchSize)
{
modelPath = Path;
batchSize = BatchSize;
SessionOpt = SessionConfigurator.MakeConfiguredSessionOptions();
session = LoadModel(modelPath);

}
/// <include file='docs/ONNXInference.xml' path='docs/members[@name="ONNXInference"]/Run/*'/>
public Godot.Collections.Dictionary<string, Godot.Collections.Array<float>> RunInference(Godot.Collections.Array<float> obs, int state_ins)
{
//Current model: Any (Godot Rl Agents)
//Expects a tensor of shape [batch_size, input_size] type float named obs and a tensor of shape [batch_size] type float named state_ins

//Fill the input tensors
// create span from inputSize
var span = new float[obs.Count]; //There's probably a better way to do this
for (int i = 0; i < obs.Count; i++)
{
span[i] = obs[i];
}

IReadOnlyCollection<NamedOnnxValue> inputs = new List<NamedOnnxValue>
{
NamedOnnxValue.CreateFromTensor("obs", new DenseTensor<float>(span, new int[] { batchSize, obs.Count })),
NamedOnnxValue.CreateFromTensor("state_ins", new DenseTensor<float>(new float[] { state_ins }, new int[] { batchSize }))
};
IReadOnlyCollection<string> outputNames = new List<string> { "output", "state_outs" }; //ONNX is sensible to these names, as well as the input names

IDisposableReadOnlyCollection<DisposableNamedOnnxValue> results;
//We do not use "using" here so we get a better exception explaination later
try
{
results = session.Run(inputs, outputNames);
}
catch (OnnxRuntimeException e)
{
//This error usually means that the model is not compatible with the input, beacause of the input shape (size)
GD.Print("Error at inference: ", e);
return null;
}
//Can't convert IEnumerable<float> to Variant, so we have to convert it to an array or something
Godot.Collections.Dictionary<string, Godot.Collections.Array<float>> output = new Godot.Collections.Dictionary<string, Godot.Collections.Array<float>>();
DisposableNamedOnnxValue output1 = results.First();
DisposableNamedOnnxValue output2 = results.Last();
Godot.Collections.Array<float> output1Array = new Godot.Collections.Array<float>();
Godot.Collections.Array<float> output2Array = new Godot.Collections.Array<float>();

foreach (float f in output1.AsEnumerable<float>())
{
output1Array.Add(f);
}

foreach (float f in output2.AsEnumerable<float>())
{
output2Array.Add(f);
}

output.Add(output1.Name, output1Array);
output.Add(output2.Name, output2Array);

//Output is a dictionary of arrays, ex: { "output" : [0.1, 0.2, 0.3, 0.4, ...], "state_outs" : [0.5, ...]}
results.Dispose();
return output;
}
/// <include file='docs/ONNXInference.xml' path='docs/members[@name="ONNXInference"]/Load/*'/>
public InferenceSession LoadModel(string Path)
{
using Godot.FileAccess file = FileAccess.Open(Path, Godot.FileAccess.ModeFlags.Read);
byte[] model = file.GetBuffer((int)file.GetLength());
//file.Close(); file.Dispose(); //Close the file, then dispose the reference.
return new InferenceSession(model, SessionOpt); //Load the model
}
public void FreeDisposables()
{
session.Dispose();
SessionOpt.Dispose();
}
}
}
Loading

0 comments on commit 879ec38

Please sign in to comment.