Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
ec2f739
wrote example code - not tested
Jun 25, 2025
5381fd0
wrote more untested code
Jun 25, 2025
e29cbeb
small edits
Jun 25, 2025
d8383e0
minor edits
eloisezeng Jun 25, 2025
c40e0b6
wrote d1_arm controller code
eloisezeng Jun 26, 2025
cd2f57e
figured out source of bug for g1_cpp.yaml; edited files for hardware …
eloisezeng Jun 27, 2025
523c9c0
hardware interface code in progress (untested)
eloisezeng Jun 28, 2025
80b2f9c
minor edit
eloisezeng Jun 28, 2025
dfe4326
d1 hardware interface almost builds
eloisezeng Jul 1, 2025
8ce30f3
code compiles, but crashes when run
eloisezeng Jul 1, 2025
a51176f
code runs
eloisezeng Jul 2, 2025
b0b5184
publishing encoder data
eloisezeng Jul 2, 2025
0b5a6ac
implemented struct for sending control message
eloisezeng Jul 3, 2025
1364cdd
worked on setting up foxglove visualization
eloisezeng Jul 3, 2025
8d95e17
configured fox glove, but need to fix units for gripper
eloisezeng Jul 3, 2025
46fb25d
fixed control input to joint6
eloisezeng Jul 3, 2025
37821cf
cleaned code
eloisezeng Jul 3, 2025
8e9f61d
added d1 estimator written in python
eloisezeng Jul 8, 2025
40b34ec
removed magic constants
eloisezeng Jul 8, 2025
022d078
cleaned code
eloisezeng Jul 9, 2025
c0ecaa0
added urdf parser dependencies
eloisezeng Jul 9, 2025
81d5fb4
added urdf-parser-py dependency
eloisezeng Jul 10, 2025
9c5e0d5
fixed gripper control code, set control limits, cleaned code
eloisezeng Jul 11, 2025
163242d
cleaned code
eloisezeng Jul 14, 2025
0d776c5
added d1 sim file
eloisezeng Jul 14, 2025
cb6fd6d
add log statements
eloisezeng Jul 14, 2025
0326cc2
added log statement
eloisezeng Jul 14, 2025
089e349
removed log statement
eloisezeng Jul 14, 2025
a9bc264
remove log statements
eloisezeng Jul 14, 2025
1eea695
no longer use deprecated mujoco py simulator
eloisezeng Jul 15, 2025
de8f1b9
increase precision
eloisezeng Jul 16, 2025
f17dfff
add pinocchio dependency
eloisezeng Jul 16, 2025
d9ea15f
added log statements and ensured obelisk_py is editable (might revert)
eloisezeng Jul 16, 2025
bfbfa3f
add log
eloisezeng Jul 16, 2025
80d5710
add log statement
eloisezeng Jul 16, 2025
f66837e
add debugging log statements
eloisezeng Jul 16, 2025
401f8df
changed node name for controller
eloisezeng Jul 17, 2025
d5cfca0
added debugging logs
eloisezeng Jul 17, 2025
51d6444
add debugging logs
eloisezeng Jul 17, 2025
c965110
add handlers before adding event emitter
eloisezeng Jul 17, 2025
4790d42
don't use global_state_node to trigger the activation of other nodes
eloisezeng Jul 17, 2025
744228b
log assertion error when key is not found in config file
eloisezeng Jul 17, 2025
de1d8d2
cleaned code
eloisezeng Jul 17, 2025
4f952f8
included option to use global_state_node
eloisezeng Jul 17, 2025
40dbe2e
cleaned code
eloisezeng Jul 17, 2025
679a605
removed debugging log statements
eloisezeng Jul 17, 2025
4fa3ca9
cleaned code
eloisezeng Jul 18, 2025
65573b4
removed debugging log statements
eloisezeng Jul 18, 2025
0d36b69
edit mode for smoother control
eloisezeng Jul 21, 2025
0fd0740
created config files for simulation and hardware on the d1 arm
eloisezeng Jul 21, 2025
8087fb9
added info logs for ease of debugging
eloisezeng Jul 21, 2025
72b7df7
attempted to make controller smoother
eloisezeng Jul 22, 2025
2374579
records joint commands/state; nodes shutdown more cleanly but occasio…
eloisezeng Jul 22, 2025
6fc9215
plots data
eloisezeng Jul 23, 2025
15d6fcb
debugging shakiness (mostly gave up on reducing shakiness)
eloisezeng Jul 24, 2025
b5f4261
cleaned code
eloisezeng Jul 25, 2025
dfb37f9
throw error if the obk joint encoders hasn't received a message from …
eloisezeng Jul 25, 2025
9a91971
removed print statement
eloisezeng Jul 25, 2025
50262e3
increase max time without update
eloisezeng Jul 25, 2025
291445d
tuned kp and kv gains, but simulated robot is still shaky at control …
eloisezeng Jul 25, 2025
b1c09ad
less aggressive kp for joint1
eloisezeng Jul 28, 2025
2fe10e3
try more aggressive kp again
eloisezeng Jul 28, 2025
29a349f
edit urdf revolute joint axis
eloisezeng Jul 29, 2025
6cdab9d
edit urdf revolute joint axis
eloisezeng Jul 29, 2025
9ed2dae
edit urdf revolute joint axis
eloisezeng Jul 29, 2025
2a7bacf
edit xml joint axes
eloisezeng Jul 29, 2025
0be8777
cleaned code
eloisezeng Jul 31, 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
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,5 +115,15 @@ obk-clean
```
This will delete cached build files associated with Obelisk. If you have tried building the Obelisk source code multiple times or from different environments/local filesystems, it may be corrupted, and cleaning the installation can help fix issues.

To run a ROS stack, run
```
obk-launch config_file_path=<config file> device_name=<device>
```

For the dummy examples this looks like:
```
obk-launch config_file_path=dummy_cpp.yaml device_name=onboard
```

## Building Docs
In the repository root, to build the docs locally, run `sphinx-build -M html docs/source/ docs/build/`.
1 change: 1 addition & 0 deletions docs/source/obelisk_terminal_aliases.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Configure all Obelisk nodes.
```
obk-configure <config_name>
```
For example, the config_name is `d1` for d1_py.yaml.

### `obk-activate`
Activate all Obelisk nodes.
Expand Down
19 changes: 12 additions & 7 deletions obelisk/cpp/obelisk_cpp/include/obelisk_mujoco_sim_robot.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,19 @@ namespace obelisk {
*/
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_configure(const rclcpp_lifecycle::State& prev_state) {
RCLCPP_INFO_STREAM(this->get_logger(), "Configuring the ObeliskSimRobot robot");
this->ObeliskSimRobot<ControlMessageT>::on_configure(prev_state);

// Read in the config string
RCLCPP_INFO_STREAM(this->get_logger(), "Reading in config stream");
std::string mujoco_setting = this->get_parameter("mujoco_setting").as_string();
auto mujoco_config_map = this->ParseConfigStr(mujoco_setting);

// Get config params
RCLCPP_INFO_STREAM(this->get_logger(), "Getting config params");
xml_path_ = GetXMLPath(mujoco_config_map); // Required
std::string robot_pkg = GetRobotPackage(mujoco_config_map); // Optional

// Search for the model
if (!std::filesystem::exists(xml_path_)) {
if (robot_pkg != "None" && robot_pkg != "none") {
Expand Down Expand Up @@ -84,7 +88,7 @@ namespace obelisk {
} catch (const std::exception& e) {
RCLCPP_INFO_STREAM(this->get_logger(), "No geoms to visualize in the simulator.");
}

RCLCPP_INFO_STREAM(this->get_logger(), "Configured Obelisk mujoco sim robot");
return rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn::SUCCESS;
}

Expand All @@ -95,10 +99,11 @@ namespace obelisk {
*/
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_activate(const rclcpp_lifecycle::State& prev_state) {
RCLCPP_INFO_STREAM(this->get_logger(), "Activating the ObeliskSimRobot robot");
this->ObeliskSimRobot<ControlMessageT>::on_activate(prev_state);

activation_complete_ = true;

RCLCPP_INFO_STREAM(this->get_logger(), "Activated the mujoco robot");
return rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn::SUCCESS;
}

Expand Down Expand Up @@ -180,7 +185,6 @@ namespace obelisk {
nu_ = model_->nu;
RCLCPP_INFO_STREAM(this->get_logger(), "Mujoco model loaded with " << nu_ << " inputs.");
shared_data_.resize(nu_);

if (!model_) {
throw std::runtime_error("Could not load Mujoco model from the XML!");
}
Expand Down Expand Up @@ -210,9 +214,10 @@ namespace obelisk {
shared_data_tmp.push_back(data_->ctrl[i]);
}
SetSharedData(shared_data_tmp);
break;
}
}

while (!this->stop_thread_) {
auto start_time = this->now();
{
Expand All @@ -222,9 +227,11 @@ namespace obelisk {
data_->ctrl[i] = shared_data_.at(i);
}
}

{
// RCLCPP_INFO_STREAM(this->get_logger(), "1 shared_data_.size()" << shared_data_.size());
std::lock_guard<std::mutex> lock(sensor_data_mut_);
// RCLCPP_INFO_STREAM(this->get_logger(), "2 shared_data_.size()" << shared_data_.size());
mj_step(model_, data_);
}

Expand All @@ -233,12 +240,10 @@ namespace obelisk {
while ((this->now() - start_time).nanoseconds() < time_step_ * 1e9) {
}
}

RCLCPP_WARN_STREAM(this->get_logger(), "Cleaning up simulation data and model...");
// free MuJoCo model and data
mj_deleteData(data_);
mj_deleteModel(model_);

rendering_thread_.join();
}

Expand Down
4 changes: 2 additions & 2 deletions obelisk/cpp/obelisk_cpp/include/obelisk_robot.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ namespace obelisk {
}

/**
* @brief Configures all the required ROS components. Specifcially this
* registers the control_subscriver_. Also makes a call to ObeliskNode on configure
* @brief Configures all the required ROS components. Specifically this
* registers the control_subscriber_. Also makes a call to ObeliskNode on configure
* to parse and create the callback group map.
*/
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn virtual on_configure(
Expand Down
31 changes: 25 additions & 6 deletions obelisk/cpp/obelisk_cpp/include/obelisk_ros_utils.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <string>
#include <stdexcept>

#include "rclcpp/rclcpp.hpp"

Expand All @@ -15,14 +16,32 @@ namespace obelisk::utils {
* @param name the name to give to the node
*/
template <typename NodeT, typename ExecutorT> void SpinObelisk(int argc, char* argv[], const std::string& name) {
rclcpp::init(argc, argv);

if (!rclcpp::ok()) { // check if rclpy is not initialized
rclcpp::init(argc, argv);
}
auto node = std::make_shared<NodeT>(name);

ExecutorT executor;
RCLCPP_INFO(node->get_logger(), "Initializing node: %s", name.c_str());
ExecutorT executor;
executor.add_node(node->get_node_base_interface());
executor.spin();
try {
executor.spin();
}
catch (const std::exception& e) {
// Catch standard exceptions
RCLCPP_ERROR(node->get_logger(), "Exception during spin: %s", e.what());
}
catch (...) {
// Catch any other unexpected exceptions
RCLCPP_ERROR(node->get_logger(), "Unknown exception during spin");
}

// Cleanup
executor.remove_node(node->get_node_base_interface());
rclcpp::shutdown();
node.reset(); // destroy the node

// Shutdown rclcpp if context is still valid
if (rclcpp::ok()) {
rclcpp::shutdown();
}
}
} // namespace obelisk::utils
55 changes: 49 additions & 6 deletions obelisk/cpp/zoo/hardware/robots/unitree/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,70 @@ message(STATUS "Configuring Unitree Interface")
find_package(ament_cmake REQUIRED)

include(FetchContent)

# Let `unitree_sdk` refer to the content fetched from the git repo.
FetchContent_Declare(
unitree_sdk
GIT_REPOSITORY https://github.com/unitreerobotics/unitree_sdk2.git
GIT_TAG 3a4680ae9b00df59e60f7e63cfb0fcc432a9d08d) # main # TODO: Fix the issue here

set(UNITREE_SDK_BUILD_EXAMPLES OFF CACHE BOOL "Disable building examples")
GIT_TAG 7b00ca4b766272d137cf7ff751d4a067bc99ca85) # Most recent commit includes the Write()
# member function in channel_publisher.hpp

# GIT_TAG 3a4680ae9b00df59e60f7e63cfb0fcc432a9d08d # This commit doesn't include the aforementioned
# member function, however, it has the SwitchGait() member function which enables go2_interface.h to compile.

# Couldn't find `UNITREE_SDK_BUILD_EXAMPLES` being defined in unitree_sdk2.
# set(UNITREE_SDK_BUILD_EXAMPLES OFF CACHE BOOL "Disable building examples")
# `BUILD_EXAMPLES` is declared in unitree_sdk2 repo's CMakeLists.txt
set(BUILD_EXAMPLES OFF CACHE BOOL "Disable building examples")

FetchContent_MakeAvailable(unitree_sdk)

# Get the .cpp files in msg and store it into the `UNITREE_ARM_MSGS`. A library should include
# solely .cpp files.
set(UNITREE_ARM_MSGS
d1/msg/ArmString_.cpp
)

# Creates a library called `unitree_arm_msgs` containing all files in `UNITREE_ARM_MSGS`
add_library(unitree_arm_msgs SHARED ${UNITREE_ARM_MSGS})

target_include_directories(unitree_arm_msgs PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/msg # The compiler needs ${CMAKE_CURRENT_SOURCE_DIR}/msg
# in the include path to find ArmString_.hpp when compiling ArmString_.cpp
/usr/local/include/ddscxx
/usr/local/include/iceoryx/v2.0.2 # FIXME: not sure if this is necessary.
# It's in d1_sdk's CMakeLists.txt, but I can't find the folder on the computer.
)

# Link `unitree_arm_msgs` to other libraries that d1_sdk depends on. These other libraries
# are listed in d1_sdk's CMakeLists.txt.
target_link_libraries(unitree_arm_msgs PUBLIC
unitree_sdk2 ddsc ddscxx rt pthread
)

# Adds an Object Library to compile source files without linking their
# object files into a library
add_library(UnitreeInterface INTERFACE)
target_include_directories(UnitreeInterface INTERFACE .)

target_link_libraries(UnitreeInterface INTERFACE Obelisk::Core unitree_sdk2)
# Adds the current directory (.) to the include path for the UnitreeInterface library
target_include_directories(UnitreeInterface INTERFACE .
${CMAKE_CURRENT_SOURCE_DIR}/msg
)

# Specifies that UnitreeInterface depends on two libraries: Obelisk::Core and unitree_sdk2.
# unitree_sdk2 is the CMake target name defined by unitree_sdk2 repo's CMakeLists.txt.
target_link_libraries(UnitreeInterface INTERFACE
Obelisk::Core
unitree_sdk2
unitree_arm_msgs
)

# Adds ROS 2 dependencies to UnitreeInterface
ament_target_dependencies(UnitreeInterface INTERFACE
rclcpp
rclcpp_lifecycle
sensor_msgs)


# add_executable(unitree_test unitree_test.cpp)
# target_link_libraries(unitree_test unitree_sdk2)

Expand Down
53 changes: 53 additions & 0 deletions obelisk/cpp/zoo/hardware/robots/unitree/d1/msg/ArmString_.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/****************************************************************

Generated by Eclipse Cyclone DDS IDL to CXX Translator
File name: ArmString_.idl
Source: ArmString_.cpp
Cyclone DDS: v0.10.2

*****************************************************************/
#include "ArmString_.hpp"

namespace org{
namespace eclipse{
namespace cyclonedds{
namespace core{
namespace cdr{

template<>
propvec &get_type_props<::unitree_arm::msg::dds_::ArmString_>() {
static thread_local std::mutex mtx;
static thread_local propvec props;
static thread_local entity_properties_t *props_end = nullptr;
static thread_local std::atomic_bool initialized {false};
key_endpoint keylist;
if (initialized.load(std::memory_order_relaxed)) {
auto ptr = props.data();
while (ptr < props_end)
(ptr++)->is_present = false;
return props;
}
std::lock_guard<std::mutex> lock(mtx);
if (initialized.load(std::memory_order_relaxed)) {
auto ptr = props.data();
while (ptr < props_end)
(ptr++)->is_present = false;
return props;
}
props.clear();

props.push_back(entity_properties_t(0, 0, false, bb_unset, extensibility::ext_final)); //root
props.push_back(entity_properties_t(1, 0, false, bb_unset, extensibility::ext_final, false)); //::data_

entity_properties_t::finish(props, keylist);
props_end = props.data() + props.size();
initialized.store(true, std::memory_order_release);
return props;
}

} //namespace cdr
} //namespace core
} //namespace cyclonedds
} //namespace eclipse
} //namespace org

Loading