Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
19 changes: 19 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright 2025 Enactic, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

---
AccessModifierOffset: -4
BasedOnStyle: Google
ColumnLimit: 100
IndentWidth: 4
19 changes: 19 additions & 0 deletions .cmake-format.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright 2025 Enactic, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

with section("format"):
command_case = "lower"

with section("markup"):
enable_markup = False
27 changes: 27 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright 2025 Enactic, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# https://editorconfig.org/

root = true

[*]
charset = utf-8
insert_final_newline = true
spelling_language = en
trim_trailing_whitespace = true

[*.sh]
indent_size = 4
indent_style = space
19 changes: 19 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,25 @@ concurrency:
group: ${{ github.head_ref || github.sha }}-${{ github.workflow }}
cancel-in-progress: true
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v5
with:
submodules: recursive
- name: Install pre-commit
run: |
python -m pip install pre-commit
- uses: actions/cache@v4
with:
path: ~/.cache/pre-commit
key: pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
- name: Run pre-commit
run: |
pre-commit run --show-diff-on-failure --color=always --all-files

build:
name: Build
runs-on: ${{ matrix.runs-on }}
Expand Down
42 changes: 42 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Copyright 2025 Enactic, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

repos:
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v20.1.7
hooks:
- id: clang-format
alias: cpp
- repo: https://github.com/cheshirekow/cmake-format-precommit
rev: v0.6.13
hooks:
- id: cmake-format
alias: cpp
- repo: https://github.com/koalaman/shellcheck-precommit
rev: v0.10.0
hooks:
- id: shellcheck
alias: shell
- repo: https://github.com/scop/pre-commit-shfmt
# v3.11.0-1 or later requires pre-commit 3.2.0 or later but Ubuntu
# 22.04 ships pre-commit 2.17.0. We can update this rev after
# Ubuntu 22.04 reached EOL (June 2027).
rev: v3.10.0-1
hooks:
- id: shfmt
alias: shell
args:
# The default args is "--write --simplify" but we don't use
# "--simplify". Because it's conflicted will ShellCheck.
- "--write"
16 changes: 16 additions & 0 deletions .shellcheckrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright 2025 Enactic, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

external-sources=true
source-path=SCRIPTDIR
30 changes: 10 additions & 20 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,28 +40,18 @@ endif()
# -----------------------------
# Create static library
# -----------------------------
add_library(openarm_teleop_lib STATIC
src/controller/dynamics.cpp
src/controller/control.cpp
src/openarm_port/openarm_init.cpp
src/openarm_port/joint_mapper.cpp
)
add_library(
openarm_teleop_lib STATIC
src/controller/dynamics.cpp src/controller/control.cpp
src/openarm_port/openarm_init.cpp src/openarm_port/joint_mapper.cpp)

target_include_directories(
openarm_teleop_lib
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)
target_include_directories(openarm_teleop_lib
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src)

target_link_libraries(openarm_teleop_lib
PUBLIC
OpenArmCAN::openarm_can
Eigen3::Eigen
${orocos_kdl_LIBRARIES}
${kdl_parser_LIBRARIES}
urdfdom::urdfdom_model
yaml-cpp::yaml-cpp
)
target_link_libraries(
openarm_teleop_lib
PUBLIC OpenArmCAN::openarm_can Eigen3::Eigen ${orocos_kdl_LIBRARIES}
${kdl_parser_LIBRARIES} urdfdom::urdfdom_model yaml-cpp::yaml-cpp)

# -----------------------------
# Executables
Expand Down
47 changes: 26 additions & 21 deletions control/gravity_compasation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,14 @@

#include <atomic>
#include <chrono>
#include <controller/dynamics.hpp>
#include <csignal>
#include <iostream>
#include <thread>
#include <csignal>
#include <atomic>
#include <filesystem>
#include <iostream>
#include <openarm/can/socket/openarm.hpp>
#include <openarm/damiao_motor/dm_motor_constants.hpp>
#include <controller/dynamics.hpp>
#include <openarm_port/openarm_init.hpp>
#include <thread>

std::atomic<bool> keep_running(true);

Expand All @@ -41,10 +39,11 @@ int main(int argc, char** argv) {
std::string arm_side = "right_arm";
std::string can_interface = "can0";


if (argc < 4) {
std::cerr << "Usage: " << argv[0] << " <arm_side> <can_interface> <urdf_path>" << std::endl;
std::cerr << "Example: " << argv[0] << " right_arm can0 /tmp/v10_bimanual.urdf" << std::endl;
std::cerr << "Usage: " << argv[0] << " <arm_side> <can_interface> <urdf_path>"
<< std::endl;
std::cerr << "Example: " << argv[0] << " right_arm can0 /tmp/v10_bimanual.urdf"
<< std::endl;
return 1;
}

Expand All @@ -53,7 +52,8 @@ int main(int argc, char** argv) {
std::string urdf_path = argv[3];

if (arm_side != "left_arm" && arm_side != "right_arm") {
std::cerr << "[ERROR] Invalid arm_side: " << arm_side << ". Must be 'left_arm' or 'right_arm'." << std::endl;
std::cerr << "[ERROR] Invalid arm_side: " << arm_side
<< ". Must be 'left_arm' or 'right_arm'." << std::endl;
return 1;
}

Expand All @@ -68,13 +68,14 @@ int main(int argc, char** argv) {
std::cout << "URDF path : " << urdf_path << std::endl;

std::string root_link = "openarm_body_link0";
std::string leaf_link = (arm_side == "left_arm") ? "openarm_left_hand" : "openarm_right_hand";
std::string leaf_link =
(arm_side == "left_arm") ? "openarm_left_hand" : "openarm_right_hand";

Dynamics arm_dynamics(urdf_path, root_link, leaf_link);
arm_dynamics.Init();

std::cout << "=== Initializing Leader OpenArm ===" << std::endl;
openarm::can::socket::OpenArm *openarm =
openarm::can::socket::OpenArm* openarm =
openarm_init::OpenArmInitializer::initialize_openarm(can_interface, true);

std::this_thread::sleep_for(std::chrono::milliseconds(100));
Expand All @@ -85,20 +86,25 @@ int main(int argc, char** argv) {
std::vector<double> arm_joint_positions(openarm->get_arm().get_motors().size(), 0.0);
std::vector<double> arm_joint_velocities(openarm->get_arm().get_motors().size(), 0.0);

std::vector<double> gripper_joint_positions(openarm->get_gripper().get_motors().size(), 0.0);
std::vector<double> gripper_joint_velocities(openarm->get_gripper().get_motors().size(), 0.0);
std::vector<double> gripper_joint_positions(openarm->get_gripper().get_motors().size(),
0.0);
std::vector<double> gripper_joint_velocities(openarm->get_gripper().get_motors().size(),
0.0);

std::vector<double> grav_torques(openarm->get_arm().get_motors().size(), 0.0);

while(keep_running){

while (keep_running) {
frame_count++;
auto current_time = std::chrono::high_resolution_clock::now();

// Calculate and display Hz every second
auto time_since_last_display = std::chrono::duration_cast<std::chrono::milliseconds>(current_time - last_hz_display).count();
if (time_since_last_display >= 1000) { // Every 1000ms (1 second)
auto total_time = std::chrono::duration_cast<std::chrono::milliseconds>(current_time - start_time).count();
auto time_since_last_display = std::chrono::duration_cast<std::chrono::milliseconds>(
current_time - last_hz_display)
.count();
if (time_since_last_display >= 1000) { // Every 1000ms (1 second)
auto total_time =
std::chrono::duration_cast<std::chrono::milliseconds>(current_time - start_time)
.count();
double hz = (frame_count * 1000.0) / total_time;
std::cout << "=== Loop Frequency: " << hz << " Hz ===" << std::endl;
last_hz_display = current_time;
Expand All @@ -112,20 +118,19 @@ int main(int argc, char** argv) {

arm_dynamics.GetGravity(arm_joint_positions.data(), grav_torques.data());

for(size_t i = 0; i < openarm->get_arm().get_motors().size(); ++i){
for (size_t i = 0; i < openarm->get_arm().get_motors().size(); ++i) {
// std::cout << "grav_torques[" << i << "] = " << grav_torques[i] << std::endl;
}

std::vector<openarm::damiao_motor::MITParam> cmds;
cmds.reserve(grav_torques.size());

std::transform(grav_torques.begin(), grav_torques.end(), std::back_inserter(cmds),
[](double t) { return openarm::damiao_motor::MITParam{0, 0, 0, 0, t}; });
[](double t) { return openarm::damiao_motor::MITParam{0, 0, 0, 0, t}; });

openarm->get_arm().mit_control_all(cmds);

openarm->recv_all();

}

std::this_thread::sleep_for(std::chrono::milliseconds(100));
Expand Down
Loading