gkemp181 commited on
Commit
da185c9
·
1 Parent(s): 3906110

initial commit

Browse files
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ venv
App/model/pick_and_place_dense.zip ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:56b4fdc265a5eb383726ce1dfee323ae99b489b4383cadd6dc0336e126caf2ed
3
+ size 3377664
App/model/pick_and_place_her.zip ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ab787b78fb54a6ee447bfd046248a1217a6e3207633e6753a2824282af3c08ad
3
+ size 3379264
App/model/push.zip ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9953fc1dfd1c19b9faa56d898cbc985790468b41c46c530f797e5b7f56106715
3
+ size 3377665
App/model/reach.zip ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:51a4a2ae881f240be42ff6cae71e54c2a0487d5b083cacd52e346359d6fbb139
3
+ size 3207511
README copy.md ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Fetch-Reinforcement Learning Project
3
+ emoji: 🐠
4
+ colorFrom: yellow
5
+ colorTo: yellow
6
+ sdk: gradio
7
+ sdk_version: 5.27.1
8
+ app_file: app.py
9
+ pinned: false
10
+ short_description: Final RL Project Using Gymnasium Robotics Fetch Environments
11
+ ---
12
+
13
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ import numpy as np
4
+ import torch
5
+ import imageio
6
+ from stable_baselines3 import SAC
7
+ from custom_env import create_env
8
+
9
+ # Update your run function to accept a model_name
10
+ def run_model_episode(x_start, y_start, x_targ, y_targ, z_targ, model_name, random_coords):
11
+
12
+ # map the radio‐choice to the actual checkpoint on disk
13
+ model_paths = {
14
+ "Pick & Place (HER)": "App/model/pick_and_place_her.zip",
15
+ "Pick & Place (Dense)": "App/model/pick_and_place_dense.zip",
16
+ "Push": "App/model/push.zip",
17
+ "Reach": "App/model/reach.zip",
18
+ }
19
+ checkpoint_path = model_paths[model_name]
20
+
21
+ # map the radio‐choice to the actual environment name
22
+ environments = {
23
+ "Pick & Place (HER)": "FetchPickAndPlace-v3",
24
+ "Pick & Place (Dense)": "FetchPickAndPlaceDense-v3",
25
+ "Push": "FetchPush-v3",
26
+ "Reach": "FetchReach-v3",
27
+ }
28
+ environment = environments[model_name]
29
+
30
+ # Handle environment coordinates
31
+ if(environment == "FetchPush-v3"):
32
+ z_targ = 0.0
33
+
34
+ block_xy=(x_start, y_start),
35
+ goal_xyz=(x_targ, y_targ, z_targ)
36
+
37
+ if random_coords:
38
+ block_xy = None
39
+ goal_xyz = None
40
+
41
+ # create the env
42
+ env = create_env(
43
+ render_mode="rgb_array",
44
+ block_xy=block_xy,
45
+ goal_xyz=goal_xyz,
46
+ environment=environment
47
+ )
48
+
49
+ # load the selected model
50
+ model = SAC.load(checkpoint_path, env=env, verbose=0)
51
+
52
+ frames = []
53
+ obs, info = env.reset()
54
+ for _ in range(200):
55
+ action, _ = model.predict(obs, deterministic=True)
56
+ obs, reward, done, trunc, info = env.step(action)
57
+ frames.append(env.render())
58
+ if done or trunc:
59
+ obs, info = env.reset()
60
+ env.close()
61
+
62
+ video_path = "run_video.mp4"
63
+ imageio.mimsave(video_path, frames, fps=30)
64
+ return video_path
65
+
66
+
67
+ with gr.Blocks() as demo:
68
+ gr.Markdown("## Fetch Robot: Model Demo App")
69
+ gr.Markdown("Enter coordinates, pick a model, then click **Run Model**.")
70
+ gr.Markdown("Coordinates are relative to the center of the table.")
71
+
72
+ # 1) add a radio (or gr.Dropdown) for model selection
73
+ model_selector = gr.Radio(
74
+ choices=["Pick & Place (HER)", "Pick & Place (Dense)", "Push", "Reach"],
75
+ value="Pick & Place (HER)",
76
+ label="Select a model/environment"
77
+ )
78
+
79
+ # Randomize coordinates
80
+ randomize = gr.Checkbox(
81
+ label="Use randomized coordinates?",
82
+ value=False
83
+ )
84
+
85
+ with gr.Row():
86
+ x_start = gr.Number(label="Start X", value=0.0)
87
+ y_start = gr.Number(label="Start Y", value=0.0)
88
+
89
+ with gr.Row():
90
+ x_targ = gr.Number(label="Target X", value=0.1)
91
+ y_targ = gr.Number(label="Target Y", value=0.1)
92
+ z_targ = gr.Number(label="Target Z", value=0.1)
93
+
94
+ run_button = gr.Button("Run Model")
95
+ output_video = gr.Video()
96
+
97
+ # 2) include the selector as an input to your click callback
98
+ run_button.click(
99
+ fn=run_model_episode,
100
+ inputs=[x_start, y_start, x_targ, y_targ, z_targ, model_selector, randomize],
101
+ outputs=output_video
102
+ )
103
+
104
+ if __name__ == "__main__":
105
+ demo.launch(
106
+ server_name="0.0.0.0", # bind to all interfaces
107
+ server_port=7860, # default HF Spaces port
108
+ )
custom_env.py ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # <-- this must come first, before any mujoco / gym imports
2
+ # import os
3
+ # os.environ["MUJOCO_GL"] = "egl"
4
+
5
+ import numpy as np
6
+ import gymnasium as gym
7
+ import gymnasium_robotics
8
+ import mujoco
9
+
10
+ class CustomFetchWrapper(gym.Wrapper):
11
+ def __init__(self, env, block_xy=None, goal_xyz=None, object=True):
12
+ super().__init__(env)
13
+ self.u = env.unwrapped # MujocoFetchPickAndPlaceEnv
14
+ # stash your fixed coords (or None to randomize)
15
+ self.default_block_xy = (np.array(block_xy, dtype=float)
16
+ if block_xy is not None else None)
17
+ self.default_goal_xyz = (np.array(goal_xyz, dtype=float)
18
+ if goal_xyz is not None else None)
19
+ self.object = object
20
+
21
+ def reset(self, *args, **kwargs):
22
+ # 1) do the normal reset — gets you a random goal in obs
23
+ obs, info = super().reset(*args, **kwargs)
24
+ u = self.unwrapped
25
+ model = u.model
26
+ data = u.data
27
+ utils = u._utils
28
+ rng = u.np_random
29
+
30
+ # 2) reset the robot slides to your home pose
31
+ for name, val in zip(
32
+ ["robot0:slide0","robot0:slide1","robot0:slide2"],
33
+ [0.405, 0.48, 0.0],
34
+ ):
35
+ utils.set_joint_qpos(model, data, name, val)
36
+
37
+ # pull out the actual goal so we can avoid it
38
+ goal_pos = obs["desired_goal"][:2].copy()
39
+
40
+ if (self.object==True):
41
+ # 3) pick block position
42
+ if self.default_block_xy is None:
43
+ home_xy = u.initial_gripper_xpos[:2]
44
+ obj_range = u.obj_range
45
+ min_dist = u.distance_threshold
46
+
47
+ while True:
48
+ offset = rng.uniform(-obj_range, obj_range, size=2)
49
+ # 3a) must be outside the “too-close to gripper” zone
50
+ if np.linalg.norm(offset) < min_dist:
51
+ continue
52
+ candidate_xy = home_xy + offset
53
+ # 3b) must be outside the “too-close to goal” zone
54
+ if np.linalg.norm(candidate_xy - goal_pos) < min_dist:
55
+ continue
56
+ # if we get here, both checks passed
57
+ break
58
+
59
+ block_xy = candidate_xy
60
+
61
+ else:
62
+ block_xy = self.default_block_xy
63
+
64
+ # place the block
65
+ blk_qpos = utils.get_joint_qpos(model, data, "object0:joint")
66
+ blk_qpos[0:2] = block_xy
67
+ blk_qpos[2] = 0.42 # table height
68
+ utils.set_joint_qpos(model, data, "object0:joint", blk_qpos)
69
+
70
+ # 4) pick goal position
71
+ if self.default_goal_xyz is not None:
72
+ new_goal = self.default_goal_xyz
73
+
74
+ # override the goal both in the env and in the MuJoCo site
75
+ u.goal = new_goal
76
+ sid = mujoco.mj_name2id(model,
77
+ mujoco.mjtObj.mjOBJ_SITE,
78
+ "target0")
79
+ data.site_xpos[sid] = new_goal
80
+
81
+ # 5) forward‐kinematics + fresh obs
82
+ u._mujoco.mj_forward(model, data)
83
+ obs = u._get_obs()
84
+
85
+ return obs, info
86
+
87
+
88
+ def create_env(render_mode=None, block_xy=None, goal_xyz=None, environment = "FetchPickAndPlace-v3"):
89
+ gym.register_envs(gymnasium_robotics)
90
+
91
+ if(environment == "FetchReach-v3"):
92
+ object = False
93
+ else:
94
+ object = True
95
+
96
+ base_env = gym.make(environment, render_mode=render_mode)
97
+ u = base_env.unwrapped
98
+
99
+ # 1) compute table center in world coords
100
+ # – X,Y: same as the gripper’s initial XY (over table center)
101
+ # – Z: the table‐top height the wrapper uses (0.42 m)
102
+ center_xy = u.initial_gripper_xpos[:2] # e.g. [1.366, 0.750]
103
+ table_z = 0.42 # match blk_qpos[2] in your wrapper
104
+ table_center = np.array([*center_xy, table_z])
105
+
106
+ # 2) turn your “relative” block_xy into an absolute XY
107
+ if block_xy is not None:
108
+ rel = np.array(block_xy, dtype=float)
109
+ abs_block_xy = center_xy + rel
110
+ else:
111
+ abs_block_xy = None
112
+
113
+ # 3) turn your “relative” goal_xyz into an absolute XYZ
114
+ if goal_xyz is not None:
115
+ rel = np.array(goal_xyz, dtype=float)
116
+ abs_goal_xyz = table_center + rel
117
+ else:
118
+ abs_goal_xyz = None
119
+
120
+ # 4) build the wrapped env with those absolutes
121
+ env = CustomFetchWrapper(
122
+ base_env,
123
+ block_xy=abs_block_xy,
124
+ goal_xyz=abs_goal_xyz,
125
+ object=object
126
+ )
127
+ return env
dockerfile ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use a lightweight Python base
2
+ FROM python:3.10-slim
3
+
4
+ # Set working directory in container
5
+ WORKDIR /app
6
+
7
+ # Copy and install dependencies
8
+ COPY requirements.txt .
9
+ RUN pip install --no-cache-dir -r requirements.txt
10
+
11
+ # Copy your app code
12
+ COPY . .
13
+
14
+ # Expose the port the app runs on
15
+ EXPOSE 7860
16
+
17
+ # Run your app
18
+ CMD ["python", "app.py"]
old_apps/app_test_2.py ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # <-- this must come first, before any mujoco / gym imports
2
+ import os
3
+ os.environ["MUJOCO_GL"] = "osmesa"
4
+
5
+
6
+ import gradio as gr
7
+ import wandb
8
+ import requests
9
+ from PIL import Image
10
+ from io import BytesIO
11
+
12
+ # Connect to W&B
13
+ api = wandb.Api()
14
+
15
+ # Replace this with your correct run path
16
+ ENTITY = "jarrett-defreitas-university-of-rhode-island" # your wandb username or team
17
+ PROJECT = "pickup-and-place"
18
+ RUN_ID = "trr5oagz" # NOT the display name; the ID like "3xi2sld8"
19
+
20
+ run = api.run(f"{ENTITY}/{PROJECT}/{RUN_ID}")
21
+
22
+ # Collect all images and metrics
23
+ logged_images = []
24
+ logged_scalars = []
25
+
26
+ # Scan all rows of logged history
27
+ for row in run.scan_history():
28
+ for key, val in row.items():
29
+ # Handle images correctly
30
+ if isinstance(val, list):
31
+ for item in val:
32
+ if isinstance(item, wandb.data_types.Image):
33
+ logged_images.append((key, item.url))
34
+ elif isinstance(val, wandb.data_types.Image):
35
+ logged_images.append((key, val.url))
36
+
37
+ # Handle scalars (numbers like loss, accuracy)
38
+ if isinstance(val, (int, float)):
39
+ logged_scalars.append((key, val))
40
+
41
+ # Debug: show what was found
42
+ print("Logged Images:", logged_images)
43
+ print("Logged Scalars:", logged_scalars)
44
+
45
+ # --------------------------------------
46
+ # 3. Prepare Dropdown Choices
47
+ # --------------------------------------
48
+
49
+ image_keys = [key for key, _ in logged_images]
50
+ scalar_keys = [key for key, _ in logged_scalars]
51
+
52
+ # --------------------------------------
53
+ # 4. Define viewer functions
54
+ # --------------------------------------
55
+
56
+ # View image by selected key
57
+ def view_image(selected_key):
58
+ for key, url in logged_images:
59
+ if key == selected_key:
60
+ response = requests.get(url)
61
+ if response.status_code == 200:
62
+ return Image.open(BytesIO(response.content))
63
+ else:
64
+ return None
65
+ return None
66
+
67
+ # View scalar (number) by selected key
68
+ def view_scalar(selected_key):
69
+ for key, value in logged_scalars:
70
+ if key == selected_key:
71
+ return f"{key}: {value}"
72
+ return "Not found"
73
+
74
+ # --------------------------------------
75
+ # 5. Build the Gradio App
76
+ # --------------------------------------
77
+
78
+ with gr.Blocks() as demo:
79
+ gr.Markdown("# 📈 WandB Run Viewer")
80
+ gr.Markdown("View images and metrics logged to a specific W&B run.")
81
+
82
+ with gr.Tab("Logged Images"):
83
+ img_selector = gr.Dropdown(choices=image_keys, label="Select an Image Key")
84
+ img_display = gr.Image()
85
+
86
+ img_selector.change(fn=view_image, inputs=img_selector, outputs=img_display)
87
+
88
+ with gr.Tab("Logged Scalars"):
89
+ scalar_selector = gr.Dropdown(choices=scalar_keys, label="Select a Scalar Metric")
90
+ scalar_display = gr.Textbox()
91
+
92
+ scalar_selector.change(fn=view_scalar, inputs=scalar_selector, outputs=scalar_display)
93
+
94
+ demo.launch(share=True)
old_apps/app_test_3.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # <-- this must come first, before any mujoco / gym imports
2
+ import os
3
+ os.environ["MUJOCO_GL"] = "osmesa"
4
+
5
+
6
+ import gradio as gr
7
+ import numpy as np
8
+ import torch
9
+ import imageio
10
+ from stable_baselines3 import SAC
11
+ from custom_env import create_env
12
+
13
+ # Define the function that runs the model and outputs a video
14
+ def run_model_episode():
15
+ # 1. Create environment with render_mode="rgb_array" (needed to capture frames)
16
+ # e.g. user inputs:
17
+ # Relative to center of table
18
+ x_start, y_start = 0.0, 0.0
19
+ x_targ, y_targ, z_targ = 0.1, 0.1, 0.1
20
+
21
+ env = create_env(render_mode="rgb_array",
22
+ block_xy=(x_start, y_start),
23
+ goal_xyz=(x_targ, y_targ, z_targ))
24
+
25
+ # 2. Load your trained model
26
+ checkpoint_path = os.path.join("model", "model.zip")
27
+ model = SAC.load(checkpoint_path, env=env, verbose=1)
28
+
29
+ # 3. Rollout the episode
30
+ frames = []
31
+ obs, info = env.reset()
32
+
33
+ for _ in range(200): # Shorter rollout to avoid giant videos
34
+ action, _ = model.predict(obs, deterministic=True)
35
+ obs, reward, done, trunc, info = env.step(action)
36
+
37
+ frame = env.render() # Get current frame as image (rgb_array)
38
+ frames.append(frame)
39
+
40
+ if done or trunc:
41
+ obs, info = env.reset()
42
+
43
+ env.close()
44
+
45
+ # TODO This will probably need to save into a unique directory
46
+ # so it doesnt override when multiple people are running the app
47
+
48
+ # 4. Save the frames into a video
49
+ video_path = "run_video_2.mp4"
50
+ imageio.mimsave(video_path, frames, fps=30)
51
+
52
+ # 5. Return path to Gradio to display
53
+ return video_path
54
+
55
+ # --------------------------------------
56
+ # Build the Gradio App
57
+ # --------------------------------------
58
+
59
+ with gr.Blocks() as demo:
60
+ gr.Markdown("Fetch Robot: Model Demo App")
61
+ gr.Markdown("Click 'Run Model' to watch the SAC agent interact with the FetchPickAndPlace environment.")
62
+
63
+ run_button = gr.Button("Run Model")
64
+ output_video = gr.Video()
65
+
66
+ run_button.click(fn=run_model_episode, inputs=[], outputs=output_video)
67
+
68
+ demo.launch(share=True)
old_apps/app_test_4.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # <-- this must come first, before any mujoco / gym imports
2
+ import os
3
+ os.environ["MUJOCO_GL"] = "osmesa"
4
+
5
+
6
+ import gradio as gr
7
+ import numpy as np
8
+ import torch
9
+ import imageio
10
+ import time
11
+ from stable_baselines3 import SAC
12
+ from custom_env import create_env
13
+
14
+ def stream_frames():
15
+ x_start, y_start = 0.0, 0.0
16
+ x_targ, y_targ, z_targ = 0.1, 0.1, 0.1
17
+
18
+ env = create_env(render_mode="rgb_array",
19
+ block_xy=(x_start, y_start),
20
+ goal_xyz=(x_targ, y_targ, z_targ))
21
+
22
+ checkpoint_path = os.path.join("App", "model", "model.zip")
23
+ model = SAC.load(checkpoint_path, env=env, verbose=1)
24
+
25
+ obs, info = env.reset()
26
+
27
+ while True:
28
+ action, _ = model.predict(obs, deterministic=True)
29
+ obs, reward, done, trunc, info = env.step(action)
30
+
31
+ frame = env.render() # Grab RGB frame
32
+ yield frame # Yield this frame to Gradio
33
+
34
+ if done or trunc:
35
+ obs, info = env.reset()
36
+
37
+ time.sleep(0.033) # ~30 FPS (1/30 seconds)
38
+
39
+ env.close()
40
+
41
+ # Build Gradio app
42
+ with gr.Blocks() as demo:
43
+ gr.Markdown("Fetch Robot: Live Model Demo App")
44
+ frame_output = gr.Image()
45
+ start_button = gr.Button("Start Streaming")
46
+
47
+ start_button.click(fn=stream_frames, inputs=[], outputs=frame_output)
48
+
49
+ demo.queue()
50
+ demo.launch(share=True)
requirements.txt ADDED
Binary file (3.9 kB). View file