Skip to content

Commit

Permalink
HAHAHAHA, boom, it works :)
Browse files Browse the repository at this point in the history
  • Loading branch information
AtomicGamer9523 committed Dec 16, 2023
1 parent 5d0e4d0 commit bbc66fe
Show file tree
Hide file tree
Showing 32 changed files with 1,477 additions and 79 deletions.
44 changes: 35 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,29 +1,55 @@
[workspace]
resolver = "2"
resolver = "2" # Resolver version (keep it 2)
members = [
# Main crates
"arc", # Client side of the robot (python)
"libs/robot", # Robot [Server] side of the robot (rust)
#################################
### Main crates ###
#################################
# Python interface implementation
"arc",
# ARC client (used to control the robot)
"libs/client",
# Code uploader (used to upload code to the robot)
"libs/uploader",
# Robot [Server] side of the robot (rust)
"libs/robot",

# Helper crates
#################################
### Helper crates ###
#################################
# Low level math functions
"libs/helper/l2math",
# "libs/libodo",
# "libs/libpath",
# "libs/libtrig",
# Core macros functions
"libs/helper/macros-core",
# Macros used to simplify code
"libs/helper/macros",
]

[workspace.package]
authors = ["Матвей Т <https://matveit.dev> AtomicGamer9523@github"]
# Contributors of team Draniki may add their name bellow
authors = [
"Матвей Т <https://matveit.dev> AtomicGamer9523@github"
]
# Github Repository
repository = "https://github.com/DranikiRobotics/arc"
version = "0.0.1-dev"
# Rust edition (keep it 2021)
edition = "2021"
# License of the entire workspace
license = "MIT"

# Version of the entire workspace
version = "0.0.1-dev"

[profile.release]
# Optimization level (keep it 3)
opt-level = 3
# debug = false

# Emit debug symbols
debug = true
# panic = "abort"
# debug = false

# What to do when a panic occurs
panic = "unwind"
# panic = "abort"
19 changes: 14 additions & 5 deletions arc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "arc"
description = "Advanced Robot Controller"
name = "arc-pylib"
description = "ARC python interface"
repository.workspace = true
version.workspace = true
edition.workspace = true
Expand All @@ -10,6 +10,15 @@ license.workspace = true
[lib]
path = "lib.rs"

[[bin]]
name = "arc"
path = "bin/main.rs"
[dependencies.hardware]
package = "arc-robot-hardware"
path = "../libs/robot/hardware"

[dependencies]
#!!! Important - DO NOT ENABLE extension-module FEATURE HERE!!!
pyo3 = "0.20.0"

[features]
# instead extension-module feature for pyo3 is enabled conditionally
# when we want to build a standalone extension module to test our plugins without "main" program
extension-module = ["pyo3/extension-module"]
File renamed without changes.
32 changes: 0 additions & 32 deletions arc/__init__.py

This file was deleted.

47 changes: 36 additions & 11 deletions arc/__init__.pyi
Original file line number Diff line number Diff line change
@@ -1,15 +1,40 @@
from typing import Callable
"""
### ARC: A complete framework for controlling robots
ARC is a feature complete framework for writing robot code.
It is designed to be easy to use, and easy to understand.
It is also designed to be modular, so that you can use only the parts you need.
Additionally, it is easy to extend, so that you can add your own functionality to it.
"""

from .hardware.gamepad import Gamepad as _Gamepad
from typing import Callable as _Callable

type RunResult = bool | int | str | None
class Gamepad(object):
pass


class Op(object):
gamepad: Gamepad
name: str
def __init__(self, name: str) -> None: ...
def __repr__(self) -> str: ...
"""Represents an operation that can be run on the robot."""

@property
def gamepad(self) -> _Gamepad:
"""The gamepad that you can use to control the robot."""
...

@property
def running(self) -> bool:
"""Whether or not the operation is running."""
...

def Auto(func: _Callable[[Op], RunResult]) -> _Callable[[Op], RunResult]:
"""Decorator for an autonomous operation."""
...

def Teleop(func: _Callable[[Op], RunResult]) -> _Callable[[Op], RunResult]:
"""Decorator for a teleop operation."""
...

def sleep(seconds: float) -> None:
"""Sleeps for the specified number of seconds."""
...

OK: RunResult = True
def OP(func: Callable[[Op], RunResult]) -> None: """
Run the given function as the main function of the program.
"""
195 changes: 195 additions & 0 deletions arc/__init__.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
use crate::threadsafe::{self, ThreadSafe};
use pyo3::prelude::*;

/// Hardware submodule
#[path = "hardware/__init__.rs"]
pub mod _hardware;

#[doc(hidden)]
fn make_err(e: &'static str) -> PyErr {
PyErr::new::<pyo3::exceptions::PyIOError, _>(e)
}

/// The struct that actually contains the necessary data for the op mode
/// to run.
///
/// This struct should only be used for mutating the data outside of the
/// op mode thread. For reading the up to date data, use the `Op` struct.
#[derive(Debug)]
pub struct OpHolder {
running: threadsafe::ThreadSafeBool,
gamepad: _hardware::gamepad::Gamepad,
}

impl OpHolder {
/// Returns whether the op mode is running
///
/// This call aquires a lock on the data
pub fn running(&self) -> bool {
match self.running.get() {
Ok(r) => **r,
Err(_) => false,
}
}
/// Returns a reference to the gamepad
///
/// This call aquires a lock on the data
pub fn gamepad(&self) -> &_hardware::gamepad::Gamepad {
&self.gamepad
}
/// Stops the op mode
///
/// DO NOT CALL THIS FROM THE OP MODE THREAD
pub fn stop(&self) {
self.running.get_mut().unwrap().set(false);
}
}

unsafe impl Send for OpHolder {}
unsafe impl Sync for OpHolder {}

/// The struct that is used to access the data in the op mode
///
/// This struct internally uses a `ThreadSafe` to access the data.
/// So feel free to clone it. It is also `Send` and `Sync`.
///
/// This struct should be used for reading the data in the op mode thread.
/// For mutating the data outside of the op mode thread, use the `OpHolder`
/// struct.
///
/// # Example
///
/// ```rust,no_run,ignore
/// let op = pylib::Op::new(gamepad_wrapper);
/// let op_wrapper = pylib::Op::wrap(&op);
///
/// // IO Thread
/// op.get_mut()?
/// ```
#[pyclass]
#[derive(Debug, Clone)]
pub struct Op(ThreadSafe<OpHolder>);

impl Op {
/// This creates a new `ThreadSafe<OpHolder>` struct. NOT a `Op` struct.
///
/// You then need to wrap it in a `Op` struct using the [`Op::wrap()`] method.
pub fn new(gamepad: _hardware::gamepad::Gamepad) -> ThreadSafe<OpHolder> {
ThreadSafe::new(OpHolder {
running: true.into(),
gamepad,
})
}
/// Wraps a `ThreadSafe<OpHolder>` in a `Op` struct.
pub fn wrap(op: &ThreadSafe<OpHolder>) -> Self {
Self(op.clone())
}
/// Returns a new [`Gamepad`] struct that is a clone of the one in the op mode.
///
/// (It's an `Arc` so it's cheap to clone)
///
/// [`Gamepad`]: _hardware/gamepad/struct.Gamepad.html
pub fn get_gamepad(&self) -> threadsafe::TSResult<_hardware::gamepad::Gamepad> {
self.0.get().map(|g| g.gamepad().clone())
}
/// Returns whether the op mode is running
///
/// This call aquires a lock on the data
pub fn is_running(&self) -> threadsafe::TSResult<bool> {
self.0.get().map(|g| g.running())
}

}

#[pymethods]
#[doc(hidden)]
impl Op {
#[getter]
#[doc(hidden)]
fn running(&self) -> PyResult<bool> {
self.is_running().map_err(make_err)
}
#[getter]
#[doc(hidden)]
fn gamepad(&self) -> PyResult<_hardware::gamepad::Gamepad> {
self.get_gamepad().map_err(make_err)
}
}

/// Sleeps for a certain amount of seconds
///
/// THIS BLOCKS THE CURRENT THREAD
#[pyfunction]
#[doc(hidden)]
fn sleep(seconds: f64) -> PyResult<()> {
std::thread::sleep(std::time::Duration::from_secs_f64(seconds));
Ok(())
}

/// An Autonomous Annotation (Decorator) for Python
///
/// This annotation is used to mark a function as an autonomous function.
#[pyclass]
#[doc(hidden)]
struct Auto(Py<PyAny>);
#[pymethods]
impl Auto {
#[new]
#[doc(hidden)]
fn __new__(wraps: Py<PyAny>) -> Self {
Self(wraps)
}
#[doc(hidden)]
#[pyo3(signature = (*args, **kwargs))]
fn __call__(
&self,
py: Python<'_>,
args: &pyo3::types::PyTuple,
kwargs: Option<&pyo3::types::PyDict>,
) -> PyResult<Py<PyAny>> {
self.0.call(py, args, kwargs)
}
}

/// A Teleop Annotation (Decorator) for Python
///
/// This annotation is used to mark a function as a teleop function.
#[pyclass]
#[doc(hidden)]
struct Teleop(Py<PyAny>);
#[pymethods]
impl Teleop {
#[new]
#[doc(hidden)]
fn __new__(wraps: Py<PyAny>) -> Self {
Self(wraps)
}
#[doc(hidden)]
#[pyo3(signature = (*args, **kwargs))]
fn __call__(
&self,
py: Python<'_>,
args: &pyo3::types::PyTuple,
kwargs: Option<&pyo3::types::PyDict>,
) -> PyResult<Py<PyAny>> {
self.0.call(py, args, kwargs)
}
}

/// Constructs the Python module
///
/// This function is called by the Python interpreter when the module is imported.
#[pymodule]
#[doc(hidden)]
pub fn arc(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(sleep, m)?)?;
m.add_class::<Teleop>()?;
m.add_class::<Auto>()?;
m.add_class::<Op>()?;
m.add("OK", true)?;

// Modules
m.add_wrapped(pyo3::wrap_pymodule!(_hardware::hardware))?;

Ok(())
}
5 changes: 0 additions & 5 deletions arc/bin/main.rs

This file was deleted.

12 changes: 12 additions & 0 deletions arc/hardware/__init__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"""
ARC Hardware module
This module contains the hardware classes for ARC.
This module includes:
- Gamepads
- Motors
- Sensors
- Servos
"""

from .gamepad import *
Loading

0 comments on commit bbc66fe

Please sign in to comment.