Skip to content
Merged

V0 #1

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
f0769bd
init physics
kanarus Jun 20, 2025
66fa86d
mod mujoco
kanarus Jun 20, 2025
def3474
init struct Physics
kanarus Jun 26, 2025
b3df84a
init environment
kanarus Jun 26, 2025
3293fd3
init environment::Composer
kanarus Jun 26, 2025
452bcf2
TODO: action <-> control / 'agent' idea implecitly included in `Envir…
kanarus Jun 26, 2025
e1649da
init design.md
kanarus Jun 26, 2025
cd5d767
I'll have dinner
kanarus Jun 26, 2025
57bd9f2
core interfaces
kanarus Jun 26, 2025
2dbd4b7
struct Environment
kanarus Jun 26, 2025
548eafd
todo: actuator
kanarus Jun 26, 2025
09342e2
init Acturators
kanarus Jun 26, 2025
0ab478e
refactor
kanarus Jun 26, 2025
3816cca
refactor
kanarus Jun 26, 2025
f18c54b
to examples
kanarus Jun 27, 2025
c8a3eb4
remove target git
kanarus Jun 27, 2025
33b4cc2
start impl Task
kanarus Jun 27, 2025
6b1ec83
init_episode
kanarus Jun 27, 2025
a25d189
velocity?
kanarus Jun 27, 2025
04d480a
TODOs
kanarus Jun 27, 2025
6ba2970
elbow, shoulder
kanarus Jun 27, 2025
bbd0b2f
2025-07-03 18:06+9:00
kanarus Jul 3, 2025
b1b399c
make `should_finish_episode` and `get_reward` to also use `onservation`
kanarus Jul 4, 2025
1979d62
todo: impl wrapper {Data, Model} to provide properly typed way to acc…
kanarus Jul 4, 2025
124bdf0
2025-07-08 01:28+9:00
kanarus Jul 7, 2025
84d10d2
model
kanarus Jul 9, 2025
70b09e1
TODO: Physics layer <- `buffer_slices!`
kanarus Jul 9, 2025
c48cf99
Physics/user-touchable-buffers
kanarus Jul 9, 2025
77522b7
TODO: acrobot
kanarus Jul 9, 2025
88d5c2c
TODO: should_finish)episode
kanarus Jul 9, 2025
2abef35
2025-07-11 05:44+9:00
kanarus Jul 10, 2025
804b280
bin/qtable.rs
kanarus Jul 10, 2025
71f5e92
`LD_LIBRARY_PATH="$MUJOCO_HOME/lib" cargo run --bin train`
kanarus Jul 11, 2025
cf1be9e
2025-07-11 11:25+9:00
kanarus Jul 11, 2025
8da41de
git ignore logs
kanarus Jul 11, 2025
49067c2
fix should_finish_episode
kanarus Jul 11, 2025
c119844
`WARNING: Nan, Inf or huge value in Q{VEL, ACC, POS} at DOF 0`
kanarus Jul 11, 2025
380bb87
where's 'Nan, Inf or huge value'???
kanarus Jul 11, 2025
0d87627
update reward and timestep
kanarus Jul 11, 2025
cf2324d
debug_{qpos, qvel}()
kanarus Jul 11, 2025
5f99db7
2025-07-12 08:11+9:00
kanarus Jul 11, 2025
d2f0687
2025-07-12 10:01+9:00
kanarus Jul 12, 2025
dcf76fa
2025-07-12 10:04+9:00
kanarus Jul 12, 2025
f09baa7
simulate worked
kanarus Jul 12, 2025
b6438ea
good camera 0
kanarus Jul 12, 2025
14beb61
2025-07-12 11:21+9:00
kanarus Jul 12, 2025
181f964
2025-07-16 23:03+9:00
kanarus Jul 16, 2025
c37df13
update reward function
kanarus Jul 16, 2025
def605f
rename `{balance => task}: &AcrobotBalanceTask` arg of `get_reward`
kanarus Jul 16, 2025
136d8bc
update rustfmt.toml
kanarus Jul 16, 2025
029bd35
update reward function
kanarus Jul 17, 2025
4314231
update init_episode and digitzed_state
kanarus Jul 17, 2025
f5d824e
try improving train.rs experiment
kanarus Jul 17, 2025
f272065
origanize train log output
kanarus Jul 17, 2025
228df50
more improve train log
kanarus Jul 17, 2025
22901d1
fix typo
kanarus Jul 17, 2025
76bf078
use emojis
kanarus Jul 17, 2025
ae0e5a1
train: not warm up if it's restored
kanarus Jul 17, 2025
4af2ea8
refactor around trained agent
kanarus Jul 17, 2025
330cde5
move current example to personal area
kanarus Jul 19, 2025
9afb5ba
update following rusty_mujoco
kanarus Jul 21, 2025
3eff546
update following rusty_mujoco
kanarus Jul 21, 2025
fc022da
fix around unused import
kanarus Jul 21, 2025
7834e4e
update following rusty_mujoco
kanarus Jul 26, 2025
1803564
update following rusty_mujoco & update README
kanarus Jul 28, 2025
604944b
update Cargo.toml
kanarus Jul 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/workflows/AutoApprove.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# will be removed when this project has more than one maintainers

name: AutoApprove

on:
pull_request:
types: [opened, reopened, synchronize, ready_for_review]

jobs:
approve:
if: |
github.event.pull_request.user.login == 'kanarus' &&
!github.event.pull_request.draft
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: actions/checkout@v4
- name: approve
env:
GH_TOKEN: ${{ github.token }}
run: |
gh pr review ${{ github.event.number }} --approve
20 changes: 16 additions & 4 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
branches: [main, v*]

jobs:
CI:
build:
runs-on: ubuntu-latest

strategy:
Expand All @@ -16,6 +16,18 @@ jobs:
steps:
- uses: actions/checkout@v4

- run: rustup update && rustup default ${{ matrix.toolchain }}

- run: cargo test
- run: |
rustup update
rustup default ${{ matrix.toolchain }}
rustup component add rustfmt ### required for rusty_mujoco to build ###

- name: install mujoco and set MUJOCO_DIR
run: |
mkdir -p $HOME/.mujoco
cd $HOME/.mujoco
wget https://github.com/google-deepmind/mujoco/releases/download/3.3.2/mujoco-3.3.2-linux-x86_64.tar.gz
tar -xzf mujoco-3.3.2-linux-x86_64.tar.gz
echo "MUJOCO_DIR=$HOME/.mujoco/mujoco-3.3.2" >> $GITHUB_ENV
echo "LD_LIBRARY_PATH=$HOME/.mujoco/mujoco-3.3.2/lib:$LD_LIBRARY_PATH" >> $GITHUB_ENV

- run: cargo build
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
/target
Cargo.lock
**/target
**/Cargo.lock
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ homepage = "https://crates.io/crates/oxide_control"
repository = "https://github.com/rust-control/oxide_control"
readme = "README.md"
license = "MIT"
description = ""
description = "Rust software stack for physics-based simulation and Reinforcement Learning environments, using MuJoCo"
keywords = ["mujoco", "rl", "ml", "physics", "robotics"]
categories = ["science::robotics", "simulation"]

[dependencies]
rusty_mujoco = { path = "../rusty_mujoco" }
rusty_mujoco = "0.1.0"
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<div align="center">
<h1><code>oxide_control</code>: The <a href="https://github.com/google-deepmind/dm_control"><code>dm_control</code></a> layer for Rust</h1>
</div>

`oxide_control` is a Rust software stack for
physics-based simulation and Reinforcement Learning environments, using MuJoCo.

This is built up on [rusty_mujoco](https://github.com/rust-control/rusty_mujoco) binding,
and provides a high-level interface similar to [dm_control](https://github.com/google-deepmind/dm_control) in Python.

## Features


1 change: 1 addition & 0 deletions rustfmt.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
max_width = 160
82 changes: 82 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use rusty_mujoco::{obj, ObjectId};

pub enum Error {
Mujoco(::rusty_mujoco::MjError),
Mjs(String),
NameNotFound(&'static str),
PhysicsDiverged,
JointTypeNotMatch {
expected: ::rusty_mujoco::bindgen::mjtJoint,
found: ::rusty_mujoco::bindgen::mjtJoint,
},
ActuatorStateless(ObjectId<obj::Actuator>),
PluginStateless(ObjectId<obj::Plugin>),
BodyNotMocap(ObjectId<obj::Body>),
}

impl From<::rusty_mujoco::MjError> for Error {
fn from(e: ::rusty_mujoco::MjError) -> Self {
Error::Mujoco(e)
}
}

impl std::fmt::Debug for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::Mujoco(e) => write!(f, "Error::MuJoCo({e:?})"),
Error::Mjs(msg) => write!(f, "Error::Mjs({msg})"),
Error::NameNotFound(name) => write!(f, "Error::NameNotFound({name})"),
Error::PhysicsDiverged => write!(f, "Error::PhysicsDiverged"),
Error::JointTypeNotMatch { expected, found } => {
write!(f, "Error::JointTypeNotMatch(expected: {expected:?}, found: {found:?})")
}
Error::ActuatorStateless(actuator_id) => {
write!(f, "Error::ActuatorStateless({actuator_id:?})")
}
Error::PluginStateless(plugin_id) => {
write!(f, "Error::PluginStateless({plugin_id:?})")
}
Error::BodyNotMocap(body_id) => {
write!(f, "Error::BodyNotMocap({body_id:?})")
}
}
}
}

impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::Mujoco(e) => write!(f, "MuJoCo error: {e}"),
Error::Mjs(msg) => write!(f, "MuJoCo error: {msg}"),
Error::NameNotFound(name) => write!(f, "Given name not found: `{name}`"),
Error::PhysicsDiverged => write!(f, "Physics simulation diverged"),
Error::JointTypeNotMatch { expected, found } => {
write!(f, "Joint type mismatch: expected {expected:?}, found {found:?}")
}
Error::ActuatorStateless(actuator_id) => {
write!(f, "Actuator with ID {actuator_id:?} is stateless unexpectedly")
}
Error::PluginStateless(plugin_id) => {
write!(f, "Plugin with ID {plugin_id:?} is stateless unexpectedly")
}
Error::BodyNotMocap(body_id) => {
write!(f, "Body with ID {body_id:?} is not a mocap body")
}
}
}
}

impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Error::Mujoco(e) => Some(e),
Error::Mjs(_) => None,
Error::NameNotFound(_) => None,
Error::PhysicsDiverged => None,
Error::JointTypeNotMatch { .. } => None,
Error::ActuatorStateless(_) => None,
Error::PluginStateless(_) => None,
Error::BodyNotMocap(_) => None,
}
}
}
92 changes: 83 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,88 @@
pub fn add(left: u64, right: u64) -> u64 {
left + right
pub mod error;
pub mod physics;

pub use physics::Physics as RawPhysics;

pub trait Physics: std::ops::DerefMut<Target = RawPhysics> {}

pub trait Task {
type Physics: Physics;
type Observation: Observation<Physics = Self::Physics>;
type Action: Action<Physics = Self::Physics>;
fn discount(&self) -> f64;
fn init_episode(&self, physics: &mut Self::Physics);
fn should_finish_episode(&self, observation: &Self::Observation) -> bool;
fn get_reward(&self, observation: &Self::Observation, action: &Self::Action) -> f64;
}

pub trait Observation {
type Physics: Physics;
fn generate(physics: &Self::Physics) -> Self;
}

pub trait Action {
type Physics: Physics;
fn apply(&self, actuators: &mut physics::Actuators<'_>);
}

pub struct Environment<T: Task> {
task: T,
physics: T::Physics,
}

impl<T: Task> Environment<T> {
pub fn new(physics: T::Physics, task: T) -> Self {
Self { task, physics }
}

pub fn task(&self) -> &T {
&self.task
}

pub fn physics(&self) -> &T::Physics {
&self.physics
}
pub fn physics_mut(&mut self) -> &mut T::Physics {
&mut self.physics
}
}

#[cfg(test)]
mod tests {
use super::*;
pub enum TimeStep<O> {
Step {
observation: O,
reward: f64,
discount: f64,
},
Finish {
observation: O,
reward: f64,
},
}

impl<T: Task> Environment<T> {
pub fn reset(&mut self) -> T::Observation {
self.task.init_episode(&mut self.physics);
T::Observation::generate(&self.physics)
}

pub fn step(&mut self, action: T::Action) -> TimeStep<T::Observation> {
action.apply(&mut self.physics.actuators());
self.physics.step();

let observation = T::Observation::generate(&self.physics);
let reward = self.task.get_reward(&observation, &action);

#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
if self.task.should_finish_episode(&observation) {
TimeStep::Finish {
observation,
reward,
}
} else {
TimeStep::Step {
observation,
reward,
discount: self.task.discount(),
}
}
}
}
Loading