/** * @file inspire_hand.cpp * @brief This is an example of how to control the Unitree H1 (Inspire) Hand using unitree_sdk2. */ // Inspire Hand Topic IDL Types #include #include // DDS Channel #include #include #include #include #include /** * @brief Unitree H1 Hand Controller * The user can subscribe to "rt/inspire/state" to get the current state of the hand and publish to "rt/inspire/cmd" to control the hand. * * IDL Types * user ---(unitree_go::msg::dds_::MotorCmds_)---> "rt/inspire/cmd" * user <--(unitree_go::msg::dds_::MotorStates_)-- "rt/inspire/state" * * @attention Currently the hand only supports position control, which means only the `q` field in idl is used. */ class H1HandController { public: H1HandController() { this->InitDDS_(); } /** * @brief Control the hand to a specific label */ void ctrl(std::string label) { if(labels.find(label) != labels.end()) { this->ctrl(labels[label], labels[label]); } else { std::cout << "Invalid label: " << label << std::endl; } } /** * @brief Move the fingers to the specified angles * * @note The angles should be in the range [0, 1] * 0: close 1: open */ void ctrl( const Eigen::Matrix& right_angles, const Eigen::Matrix& left_angles) { for(size_t i(0); i<6; i++) { cmd.cmds()[i].q() = right_angles(i); cmd.cmds()[i+6].q() = left_angles(i); } handcmd->Write(cmd); } /** * @brief Get the right hand angles * * Joint order: [pinky, ring, middle, index, thumb_bend, thumb_rotation] */ Eigen::Matrix getRightQ() { std::lock_guard lock(mtx); Eigen::Matrix q; for(size_t i(0); i<6; i++) { q(i) = state.states()[i].q(); } return q; } /** * @brief Get the left hand angles * * Joint order: [pinky, ring, middle, index, thumb_bend, thumb_rotation] */ Eigen::Matrix getLeftQ() { std::lock_guard lock(mtx); Eigen::Matrix q; for(size_t i(0); i<6; i++) { q(i) = state.states()[i+6].q(); } return q; } unitree_go::msg::dds_::MotorCmds_ cmd; unitree_go::msg::dds_::MotorStates_ state; private: void InitDDS_() { handcmd = std::make_shared>( "rt/inspire/cmd"); handcmd->InitChannel(); cmd.cmds().resize(12); handstate = std::make_shared>( "rt/inspire/state"); handstate->InitChannel([this](const void *message){ std::lock_guard lock(mtx); state = *(unitree_go::msg::dds_::MotorStates_*)message; }); state.states().resize(12); } // DDS parameters std::mutex mtx; unitree::robot::ChannelPublisherPtr handcmd; unitree::robot::ChannelSubscriberPtr handstate; // Saved labels std::unordered_map> labels = { {"open", Eigen::Matrix::Ones()}, {"close", Eigen::Matrix::Zero()}, {"half", Eigen::Matrix::Constant(0.5)}, }; }; /** * Main Function */ int main(int argc, char** argv) { std::cout << " --- Unitree Robotics --- \n"; std::cout << " H1 Hand Example \n\n"; // Target label std::string label = "close"; // You change this value to other labels // Initialize the DDS Channel std::string networkInterface = argc > 1 ? argv[1] : ""; unitree::robot::ChannelFactory::Instance()->Init(0, networkInterface); // Create the H1 Hand Controller auto h1hand = std::make_shared(); int cnt = 0; while (true) { usleep(100000); if(cnt++ % 10 == 0) label = label == "close" ? "open" : "close"; h1hand->ctrl(label); // Control the hand std::cout << "-- Hand State --\n"; std::cout << " R: " << h1hand->getRightQ().transpose() << std::endl; std::cout << " L: " << h1hand->getLeftQ().transpose() << std::endl; std::cout << "\033[3A"; // Move cursor up 3 lines } return 0; }