Add navigation functionality to CustomRobot and Controller classes. Introduced Navigation class for handling mapping and pose navigation commands. Updated CustomRobot to process navigation commands and manage Navigation instance. Enhanced Controller with motion switching capabilities, improving overall robot control and navigation features.
This commit is contained in:
@@ -34,6 +34,7 @@ set(SOURCES
|
|||||||
src/config.cpp
|
src/config.cpp
|
||||||
src/logger.cpp
|
src/logger.cpp
|
||||||
src/mqtt.cpp
|
src/mqtt.cpp
|
||||||
|
src/navigation.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create executable with simple name
|
# Create executable with simple name
|
||||||
|
|||||||
@@ -6,10 +6,12 @@
|
|||||||
|
|
||||||
#include <unitree/robot/go2/sport/sport_client.hpp>
|
#include <unitree/robot/go2/sport/sport_client.hpp>
|
||||||
#include <unitree/robot/go2/obstacles_avoid/obstacles_avoid_client.hpp>
|
#include <unitree/robot/go2/obstacles_avoid/obstacles_avoid_client.hpp>
|
||||||
|
#include <unitree/robot/go2/motion_switcher/motion_switcher_client.hpp>
|
||||||
#include <unitree/robot/go2/video/video_client.hpp>
|
#include <unitree/robot/go2/video/video_client.hpp>
|
||||||
#include <unitree/robot/go2/vui/vui_client.hpp>
|
#include <unitree/robot/go2/vui/vui_client.hpp>
|
||||||
#include <unitree/robot/channel/channel_subscriber.hpp>
|
#include <unitree/robot/channel/channel_subscriber.hpp>
|
||||||
#include <unitree/idl/go2/SportModeState_.hpp>
|
#include <unitree/idl/go2/SportModeState_.hpp>
|
||||||
|
#include "logger.hpp"
|
||||||
|
|
||||||
namespace custom {
|
namespace custom {
|
||||||
|
|
||||||
@@ -45,10 +47,24 @@ public:
|
|||||||
bool MoveToAbsolutePosition(float x, float y, float yaw);
|
bool MoveToAbsolutePosition(float x, float y, float yaw);
|
||||||
bool MoveToIncrementPosition(float x, float y, float yaw);
|
bool MoveToIncrementPosition(float x, float y, float yaw);
|
||||||
|
|
||||||
|
// MotionSwitcher
|
||||||
|
bool CheckMode(std::string& form, std::string& name);
|
||||||
|
bool SelectMode(const std::string& nameOrAlias);
|
||||||
|
bool ReleaseMode();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
template<typename Func>
|
||||||
|
bool ExecuteSportCmd(Func&& func);
|
||||||
|
|
||||||
|
template<typename Func>
|
||||||
|
bool ExecuteObstacleCmd(Func&& func);
|
||||||
|
|
||||||
|
template<typename Func>
|
||||||
|
bool ExecuteMotionSwitchCmd(Func&& func);
|
||||||
|
|
||||||
std::unique_ptr<unitree::robot::go2::SportClient> sc_;
|
std::unique_ptr<unitree::robot::go2::SportClient> sc_;
|
||||||
std::unique_ptr<unitree::robot::go2::ObstaclesAvoidClient> oac_;
|
std::unique_ptr<unitree::robot::go2::ObstaclesAvoidClient> oac_;
|
||||||
|
std::unique_ptr<unitree::robot::go2::MotionSwitcherClient> msc_;
|
||||||
|
|
||||||
std::atomic<bool> running_;
|
std::atomic<bool> running_;
|
||||||
std::atomic<bool> initialized_;
|
std::atomic<bool> initialized_;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
#include "logger.hpp"
|
#include "logger.hpp"
|
||||||
#include "mqtt.hpp"
|
#include "mqtt.hpp"
|
||||||
|
#include "navigation.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
@@ -23,6 +24,7 @@ public:
|
|||||||
bool start();
|
bool start();
|
||||||
|
|
||||||
Controller* getController() const { return controller_.get(); }
|
Controller* getController() const { return controller_.get(); }
|
||||||
|
Navigation* getNavigation() const { return navigation_.get(); }
|
||||||
|
|
||||||
bool GetServiceList(std::vector<unitree::robot::go2::ServiceState>& serviceList);
|
bool GetServiceList(std::vector<unitree::robot::go2::ServiceState>& serviceList);
|
||||||
bool SwitchService(const std::string& serviceName, bool enable);
|
bool SwitchService(const std::string& serviceName, bool enable);
|
||||||
@@ -37,11 +39,13 @@ public:
|
|||||||
bool processOacCmd(const std::string& cmd, const nlohmann::json& message);
|
bool processOacCmd(const std::string& cmd, const nlohmann::json& message);
|
||||||
bool processSportCmd(const std::string& cmd, const nlohmann::json& message);
|
bool processSportCmd(const std::string& cmd, const nlohmann::json& message);
|
||||||
bool processRscCmd(const std::string& cmd, const nlohmann::json& message);
|
bool processRscCmd(const std::string& cmd, const nlohmann::json& message);
|
||||||
|
bool processNavCmd(const std::string& cmd, const nlohmann::json& message);
|
||||||
void printServiceList(const std::vector<unitree::robot::go2::ServiceState>& serviceList, int filterStatus = -1);
|
void printServiceList(const std::vector<unitree::robot::go2::ServiceState>& serviceList, int filterStatus = -1);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string generateRandomClientId() const;
|
std::string generateRandomClientId() const;
|
||||||
std::unique_ptr<Controller> controller_;
|
std::unique_ptr<Controller> controller_;
|
||||||
|
std::unique_ptr<Navigation> navigation_;
|
||||||
std::unique_ptr<unitree::robot::go2::RobotStateClient> rsc_;
|
std::unique_ptr<unitree::robot::go2::RobotStateClient> rsc_;
|
||||||
std::unique_ptr<MqttClient> mqttClient_;
|
std::unique_ptr<MqttClient> mqttClient_;
|
||||||
|
|
||||||
|
|||||||
29
include/navigation.hpp
Normal file
29
include/navigation.hpp
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#ifndef NAVIGATION_HPP
|
||||||
|
#define NAVIGATION_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
#include "unitree/robot/client/client.hpp"
|
||||||
|
|
||||||
|
class Navigation {
|
||||||
|
public:
|
||||||
|
Navigation();
|
||||||
|
~Navigation();
|
||||||
|
|
||||||
|
void Init();
|
||||||
|
|
||||||
|
bool startMapping();
|
||||||
|
bool endMapping(const std::string& address);
|
||||||
|
bool initializePose(double x, double y, double z, double q_x, double q_y, double q_z, double q_w, const std::string& address);
|
||||||
|
bool poseNavigation(double x, double y, double z, double q_x, double q_y, double q_z, double q_w, int mode, double speed);
|
||||||
|
bool pauseNavigation();
|
||||||
|
bool resumeNavigation();
|
||||||
|
bool closeSlam();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<unitree::robot::Client> client_;
|
||||||
|
bool callSlamService(int api_id, const nlohmann::json& data);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // NAVIGATION_HPP
|
||||||
@@ -2,6 +2,9 @@
|
|||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
#include "logger.hpp"
|
#include "logger.hpp"
|
||||||
#include <unitree/common/thread/thread.hpp>
|
#include <unitree/common/thread/thread.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
namespace custom {
|
namespace custom {
|
||||||
|
|
||||||
@@ -17,6 +20,7 @@ Controller::~Controller() {
|
|||||||
LOG_INFO("Shutting down robot controller");
|
LOG_INFO("Shutting down robot controller");
|
||||||
sc_.reset();
|
sc_.reset();
|
||||||
oac_.reset();
|
oac_.reset();
|
||||||
|
msc_.reset();
|
||||||
initialized_ = false;
|
initialized_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,6 +34,9 @@ bool Controller::initialize() {
|
|||||||
oac_->SetTimeout(3.0f);
|
oac_->SetTimeout(3.0f);
|
||||||
oac_->Init();
|
oac_->Init();
|
||||||
|
|
||||||
|
msc_ = std::make_unique<unitree::robot::go2::MotionSwitcherClient>();
|
||||||
|
msc_->SetTimeout(10.0f);
|
||||||
|
msc_->Init();
|
||||||
|
|
||||||
initialized_ = true;
|
initialized_ = true;
|
||||||
return true;
|
return true;
|
||||||
@@ -67,236 +74,188 @@ bool Controller::stop() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Func>
|
||||||
|
bool Controller::ExecuteSportCmd(Func&& func) {
|
||||||
|
if (!initialized_) {
|
||||||
|
LOG_ERROR("Controller not initialized");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sc_) {
|
||||||
|
LOG_ERROR("SportClient not available");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
int32_t result = func(sc_.get());
|
||||||
|
return result == 0;
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
LOG_ERROR("Command failed with exception: " + std::string(e.what()));
|
||||||
|
return false;
|
||||||
|
} catch (...) {
|
||||||
|
LOG_ERROR("Command failed with unknown exception");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Func>
|
||||||
|
bool Controller::ExecuteObstacleCmd(Func&& func) {
|
||||||
|
if (!initialized_) {
|
||||||
|
LOG_ERROR("Controller not initialized");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!oac_) {
|
||||||
|
LOG_ERROR("ObstaclesAvoidClient not available");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
int32_t result = func(oac_.get());
|
||||||
|
return result == 0;
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
LOG_ERROR("Command failed with exception: " + std::string(e.what()));
|
||||||
|
return false;
|
||||||
|
} catch (...) {
|
||||||
|
LOG_ERROR("Command failed with unknown exception");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Func>
|
||||||
|
bool Controller::ExecuteMotionSwitchCmd(Func&& func) {
|
||||||
|
if (!initialized_) {
|
||||||
|
LOG_ERROR("Controller not initialized");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!msc_) {
|
||||||
|
LOG_ERROR("MotionSwitcherClient not available");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
int32_t result = func(msc_.get());
|
||||||
|
return result == 0;
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
LOG_ERROR("Command failed with exception: " + std::string(e.what()));
|
||||||
|
return false;
|
||||||
|
} catch (...) {
|
||||||
|
LOG_ERROR("Command failed with unknown exception");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Controller::StandUp() {
|
bool Controller::StandUp() {
|
||||||
LOG_INFO("Standing up");
|
return ExecuteSportCmd([](auto* sc) {
|
||||||
try {
|
return sc->StandUp();
|
||||||
if (!sc_) {
|
});
|
||||||
LOG_ERROR("SportClient not initialized");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t result = sc_->StandUp();
|
|
||||||
LOG_INFO("StandUp API returned: " + std::to_string(result));
|
|
||||||
return result == 0;
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
LOG_ERROR("Stand up failed: " + std::string(e.what()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Controller::StandDown() {
|
bool Controller::StandDown() {
|
||||||
LOG_INFO("Standing down");
|
return ExecuteSportCmd([](auto* sc) {
|
||||||
try {
|
return sc->StandDown();
|
||||||
if (!sc_) {
|
});
|
||||||
LOG_ERROR("SportClient not initialized");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t result = sc_->StandDown();
|
|
||||||
LOG_INFO("StandDown API returned: " + std::to_string(result));
|
|
||||||
return result == 0;
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
LOG_ERROR("Stand down failed: " + std::string(e.what()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Controller::Sit() {
|
bool Controller::Sit() {
|
||||||
LOG_INFO("Sitting");
|
return ExecuteSportCmd([](auto* sc) {
|
||||||
try {
|
return sc->Sit();
|
||||||
if (!sc_) {
|
});
|
||||||
LOG_ERROR("SportClient not initialized");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t result = sc_->Sit();
|
|
||||||
LOG_INFO("Sit API returned: " + std::to_string(result));
|
|
||||||
return result == 0;
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
LOG_ERROR("Sit failed: " + std::string(e.what()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Controller::Damp() {
|
bool Controller::Damp() {
|
||||||
LOG_INFO("Damping");
|
return ExecuteSportCmd([](auto* sc) {
|
||||||
try {
|
return sc->Damp();
|
||||||
if (!sc_) {
|
});
|
||||||
LOG_ERROR("SportClient not initialized");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t result = sc_->Damp();
|
|
||||||
LOG_INFO("Damp API returned: " + std::to_string(result));
|
|
||||||
return result == 0;
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
LOG_ERROR("Damp failed: " + std::string(e.what()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Controller::RecoveryStand() {
|
bool Controller::RecoveryStand() {
|
||||||
LOG_INFO("Executing recovery stand");
|
return ExecuteSportCmd([](auto* sc) {
|
||||||
|
return sc->RecoveryStand();
|
||||||
try {
|
});
|
||||||
if (!sc_) {
|
|
||||||
LOG_ERROR("SportClient not initialized");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t result = sc_->RecoveryStand();
|
|
||||||
LOG_INFO("RecoveryStand API returned: " + std::to_string(result));
|
|
||||||
return result == 0;
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
LOG_ERROR("Recovery stand failed: " + std::string(e.what()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Controller::StopMove() {
|
bool Controller::StopMove() {
|
||||||
try {
|
return ExecuteSportCmd([](auto* sc) {
|
||||||
if (!sc_) {
|
return sc->StopMove();
|
||||||
LOG_ERROR("SportClient not initialized");
|
});
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t result = sc_->StopMove();
|
|
||||||
LOG_INFO("StopMove API returned: " + std::to_string(result));
|
|
||||||
return result == 0;
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
LOG_ERROR("Stop move failed: " + std::string(e.what()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Controller::BalanceStand() {
|
bool Controller::BalanceStand() {
|
||||||
try {
|
return ExecuteSportCmd([](auto* sc) {
|
||||||
if (!sc_) {
|
return sc->BalanceStand();
|
||||||
LOG_ERROR("SportClient not initialized");
|
});
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t result = sc_->BalanceStand();
|
|
||||||
LOG_INFO("BalanceStand API returned: " + std::to_string(result));
|
|
||||||
return result == 0;
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
LOG_ERROR("Balance stand failed: " + std::string(e.what()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Controller::Dance1() {
|
bool Controller::Dance1() {
|
||||||
try {
|
return ExecuteSportCmd([](auto* sc) {
|
||||||
if (!sc_) {
|
return sc->Dance1();
|
||||||
LOG_ERROR("SportClient not initialized");
|
});
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t result = sc_->Dance1();
|
|
||||||
LOG_INFO("Dance1 API returned: " + std::to_string(result));
|
|
||||||
return result == 0;
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
LOG_ERROR("Dance1 failed: " + std::string(e.what()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Controller::Dance2() {
|
bool Controller::Dance2() {
|
||||||
try {
|
return ExecuteSportCmd([](auto* sc) {
|
||||||
if (!sc_) {
|
return sc->Dance2();
|
||||||
LOG_ERROR("SportClient not initialized");
|
});
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t result = sc_->Dance2();
|
|
||||||
LOG_INFO("Dance2 API returned: " + std::to_string(result));
|
|
||||||
return result == 0;
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
LOG_ERROR("Dance2 failed: " + std::string(e.what()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Controller::Hello() {
|
bool Controller::Hello() {
|
||||||
try {
|
return ExecuteSportCmd([](auto* sc) {
|
||||||
if (!sc_) {
|
return sc->Hello();
|
||||||
LOG_ERROR("SportClient not initialized");
|
});
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t result = sc_->Hello();
|
|
||||||
LOG_INFO("Hello API returned: " + std::to_string(result));
|
|
||||||
return result == 0;
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
LOG_ERROR("Hello failed: " + std::string(e.what()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool Controller::SwitchSet(bool enable) {
|
bool Controller::SwitchSet(bool enable) {
|
||||||
try {
|
return ExecuteObstacleCmd([enable](auto* oac) {
|
||||||
if (!oac_) {
|
return oac->SwitchSet(enable);
|
||||||
LOG_ERROR("ObstaclesAvoidClient not initialized");
|
});
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t result = oac_->SwitchSet(enable);
|
|
||||||
LOG_INFO("SwitchSet API returned: " + std::to_string(result));
|
|
||||||
return result == 0;
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
LOG_ERROR("Switch set failed: " + std::string(e.what()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Controller::SwitchGet(bool& enable) {
|
bool Controller::SwitchGet(bool& enable) {
|
||||||
try {
|
return ExecuteObstacleCmd([&enable](auto* oac) {
|
||||||
if (!oac_) {
|
return oac->SwitchGet(enable);
|
||||||
LOG_ERROR("ObstaclesAvoidClient not initialized");
|
});
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t result = oac_->SwitchGet(enable);
|
|
||||||
LOG_INFO("SwitchGet API returned: " + std::to_string(result) +
|
|
||||||
", enable: " + std::string(enable ? "true" : "false"));
|
|
||||||
return result == 0;
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
LOG_ERROR("Switch get failed: " + std::string(e.what()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Controller::UseRemoteCommandFromApi(bool isRemoteCommandsFromApi) {
|
bool Controller::UseRemoteCommandFromApi(bool isRemoteCommandsFromApi) {
|
||||||
try {
|
return ExecuteObstacleCmd([isRemoteCommandsFromApi](auto* oac) {
|
||||||
return oac_ && oac_->UseRemoteCommandFromApi(isRemoteCommandsFromApi) == 0;
|
return oac->UseRemoteCommandFromApi(isRemoteCommandsFromApi);
|
||||||
} catch (const std::exception& e) {
|
});
|
||||||
LOG_ERROR("Use remote command from api failed: " + std::string(e.what()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Controller::MoveToAbsolutePosition(float x, float y, float yaw) {
|
bool Controller::MoveToAbsolutePosition(float x, float y, float yaw) {
|
||||||
try {
|
return ExecuteObstacleCmd([x, y, yaw](auto* oac) {
|
||||||
return oac_ && oac_->MoveToAbsolutePosition(x, y, yaw) == 0;
|
return oac->MoveToAbsolutePosition(x, y, yaw);
|
||||||
} catch (const std::exception& e) {
|
});
|
||||||
LOG_ERROR("Move to absolute position failed: " + std::string(e.what()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Controller::MoveToIncrementPosition(float x, float y, float yaw) {
|
bool Controller::MoveToIncrementPosition(float x, float y, float yaw) {
|
||||||
try {
|
return ExecuteObstacleCmd([x, y, yaw](auto* oac) {
|
||||||
return oac_ && oac_->MoveToIncrementPosition(x, y, yaw) == 0;
|
return oac->MoveToIncrementPosition(x, y, yaw);
|
||||||
} catch (const std::exception& e) {
|
});
|
||||||
LOG_ERROR("Move to increment position failed: " + std::string(e.what()));
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Controller::CheckMode(std::string& form, std::string& name) {
|
||||||
|
return ExecuteMotionSwitchCmd([&](auto* msc) {
|
||||||
|
return msc->CheckMode(form, name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Controller::SelectMode(const std::string& nameOrAlias) {
|
||||||
|
return ExecuteMotionSwitchCmd([&](auto* msc) {
|
||||||
|
return msc->SelectMode(nameOrAlias);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Controller::ReleaseMode() {
|
||||||
|
return ExecuteMotionSwitchCmd([&](auto* msc) {
|
||||||
|
return msc->ReleaseMode();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace custom
|
} // namespace custom
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
namespace custom {
|
namespace custom {
|
||||||
|
|
||||||
CustomRobot::CustomRobot()
|
CustomRobot::CustomRobot()
|
||||||
: initialized_(false), running_(false) {
|
: initialized_(false), running_(false), controller_(nullptr), navigation_(nullptr), rsc_(nullptr), mqttClient_(nullptr) {
|
||||||
config_.loadDefaults();
|
config_.loadDefaults();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -42,6 +42,10 @@ CustomRobot::~CustomRobot() {
|
|||||||
rsc_.reset();
|
rsc_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (navigation_) {
|
||||||
|
navigation_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
unitree::robot::ChannelFactory::Instance()->Release();
|
unitree::robot::ChannelFactory::Instance()->Release();
|
||||||
LOG_INFO("ChannelFactory released");
|
LOG_INFO("ChannelFactory released");
|
||||||
@@ -57,6 +61,9 @@ bool CustomRobot::initialize() {
|
|||||||
controller_ = std::make_unique<Controller>();
|
controller_ = std::make_unique<Controller>();
|
||||||
controller_->initialize();
|
controller_->initialize();
|
||||||
|
|
||||||
|
navigation_ = std::make_unique<Navigation>();
|
||||||
|
navigation_->Init();
|
||||||
|
|
||||||
rsc_ = std::make_unique<unitree::robot::go2::RobotStateClient>();
|
rsc_ = std::make_unique<unitree::robot::go2::RobotStateClient>();
|
||||||
rsc_->SetTimeout(3.0f);
|
rsc_->SetTimeout(3.0f);
|
||||||
rsc_->Init();
|
rsc_->Init();
|
||||||
@@ -244,6 +251,8 @@ void CustomRobot::processCmd(const nlohmann::json& message) {
|
|||||||
success = processSportCmd(cmd, message);
|
success = processSportCmd(cmd, message);
|
||||||
} else if (type == "rsc") {
|
} else if (type == "rsc") {
|
||||||
success = processRscCmd(cmd, message);
|
success = processRscCmd(cmd, message);
|
||||||
|
} else if (type == "nav") {
|
||||||
|
success = processNavCmd(cmd, message);
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR("Unknown command type: " + type);
|
LOG_ERROR("Unknown command type: " + type);
|
||||||
return;
|
return;
|
||||||
@@ -330,6 +339,71 @@ bool CustomRobot::processOacCmd(const std::string& cmd, const nlohmann::json& me
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CustomRobot::processNavCmd(const std::string& cmd, const nlohmann::json& message) {
|
||||||
|
if (!navigation_) {
|
||||||
|
LOG_ERROR("Navigation not initialized");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (cmd == "start_mapping") {
|
||||||
|
return navigation_->startMapping();
|
||||||
|
} else if (cmd == "end_mapping") {
|
||||||
|
if (!message.contains("param") || !message["param"].contains("address")) {
|
||||||
|
LOG_ERROR("end_mapping cmd missing 'address' parameter");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::string address = message["param"]["address"];
|
||||||
|
return navigation_->endMapping(address);
|
||||||
|
} else if (cmd == "initialize_pose") {
|
||||||
|
if (!message.contains("param")) {
|
||||||
|
LOG_ERROR("initialize_pose cmd missing 'param'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto& param = message["param"];
|
||||||
|
const std::vector<std::string> keys = {"x", "y", "z", "q_x", "q_y", "q_z", "q_w", "address"};
|
||||||
|
for (const auto& key : keys) {
|
||||||
|
if (!param.contains(key)) {
|
||||||
|
LOG_ERROR("initialize_pose missing parameter: " + key);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return navigation_->initializePose(param["x"], param["y"], param["z"], param["q_x"], param["q_y"], param["q_z"], param["q_w"], param["address"]);
|
||||||
|
} else if (cmd == "pose_navigation") {
|
||||||
|
if (!message.contains("param")) {
|
||||||
|
LOG_ERROR("pose_navigation cmd missing 'param'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto& param = message["param"];
|
||||||
|
if (!param.contains("targetPose") || !param.contains("mode") || !param.contains("speed")) {
|
||||||
|
LOG_ERROR("pose_navigation missing 'targetPose', 'mode', or 'speed'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto& targetPose = param["targetPose"];
|
||||||
|
const std::vector<std::string> pose_keys = {"x", "y", "z", "q_x", "q_y", "q_z", "q_w"};
|
||||||
|
for (const auto& key : pose_keys) {
|
||||||
|
if (!targetPose.contains(key)) {
|
||||||
|
LOG_ERROR("pose_navigation.targetPose missing parameter: " + key);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return navigation_->poseNavigation(targetPose["x"], targetPose["y"], targetPose["z"], targetPose["q_x"], targetPose["q_y"], targetPose["q_z"], targetPose["q_w"], param["mode"], param["speed"]);
|
||||||
|
} else if (cmd == "pause_navigation") {
|
||||||
|
return navigation_->pauseNavigation();
|
||||||
|
} else if (cmd == "resume_navigation") {
|
||||||
|
return navigation_->resumeNavigation();
|
||||||
|
} else if (cmd == "close_slam") {
|
||||||
|
return navigation_->closeSlam();
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("Unknown Nav command: " + cmd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
LOG_ERROR("Error executing Nav command " + cmd + ": " + std::string(e.what()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool CustomRobot::processRscCmd(const std::string& cmd, const nlohmann::json& message) {
|
bool CustomRobot::processRscCmd(const std::string& cmd, const nlohmann::json& message) {
|
||||||
try {
|
try {
|
||||||
if (cmd == "list") {
|
if (cmd == "list") {
|
||||||
@@ -417,27 +491,99 @@ bool CustomRobot::processSportCmd(const std::string& cmd, const nlohmann::json&
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (cmd == "StandUp") {
|
if (cmd == "Damp") {
|
||||||
|
return controller_->Damp();
|
||||||
|
} else if (cmd == "BalanceStand") {
|
||||||
|
return controller_->BalanceStand();
|
||||||
|
} else if (cmd == "StopMove") {
|
||||||
|
return controller_->StopMove();
|
||||||
|
} else if (cmd == "StandUp") {
|
||||||
return controller_->StandUp();
|
return controller_->StandUp();
|
||||||
} else if (cmd == "StandDown") {
|
} else if (cmd == "StandDown") {
|
||||||
return controller_->StandDown();
|
return controller_->StandDown();
|
||||||
} else if (cmd == "Sit") {
|
|
||||||
return controller_->Sit();
|
|
||||||
} else if (cmd == "Damp") {
|
|
||||||
return controller_->Damp();
|
|
||||||
} else if (cmd == "RecoveryStand") {
|
} else if (cmd == "RecoveryStand") {
|
||||||
return controller_->RecoveryStand();
|
return controller_->RecoveryStand();
|
||||||
} else if (cmd == "StopMove") {
|
} else if (cmd == "Euler") {
|
||||||
return controller_->StopMove();
|
return controller_->Euler(message["param"]["roll"], message["param"]["pitch"], message["param"]["yaw"]);
|
||||||
} else if (cmd == "BalanceStand") {
|
} else if (cmd == "Move") {
|
||||||
return controller_->BalanceStand();
|
return controller_->Move(message["param"]["vx"], message["param"]["vy"], message["param"]["vyaw"]);
|
||||||
|
} else if (cmd == "Sit") {
|
||||||
|
return controller_->Sit();
|
||||||
|
} else if (cmd == "RiseSit") {
|
||||||
|
return controller_->RiseSit();
|
||||||
|
} else if (cmd == "SpeedLevel") {
|
||||||
|
return controller_->SpeedLevel(message["param"]["level"]);
|
||||||
|
} else if (cmd == "Hello") {
|
||||||
|
return controller_->Hello();
|
||||||
|
} else if (cmd == "Stretch") {
|
||||||
|
return controller_->Stretch();
|
||||||
|
} else if (cmd == "SwitchJoystick") {
|
||||||
|
return controller_->SwitchJoystick(message["param"]["flag"]);
|
||||||
|
} else if (cmd == "Content") {
|
||||||
|
return controller_->Content();
|
||||||
|
} else if (cmd == "Heart") {
|
||||||
|
return controller_->Heart();
|
||||||
|
} else if (cmd == "Pose") {
|
||||||
|
return controller_->Pose(message["param"]["flag"]);
|
||||||
|
} else if (cmd == "Scrape") {
|
||||||
|
return controller_->Scrape();
|
||||||
|
} else if (cmd == "FrontFlip") {
|
||||||
|
return controller_->FrontFlip();
|
||||||
|
} else if (cmd == "FrontJump") {
|
||||||
|
return controller_->FrontJump();
|
||||||
|
} else if (cmd == "FrontPounce") {
|
||||||
|
return controller_->FrontPounce();
|
||||||
} else if (cmd == "Dance1") {
|
} else if (cmd == "Dance1") {
|
||||||
return controller_->Dance1();
|
return controller_->Dance1();
|
||||||
} else if (cmd == "Dance2") {
|
} else if (cmd == "Dance2") {
|
||||||
return controller_->Dance2();
|
return controller_->Dance2();
|
||||||
} else if (cmd == "Hello") {
|
} else if (cmd == "LeftFlip") {
|
||||||
return controller_->Hello();
|
return controller_->LeftFlip();
|
||||||
} else {
|
} else if (cmd == "BackFlip") {
|
||||||
|
return controller_->BackFlip();
|
||||||
|
} else if (cmd == "HandStand") {
|
||||||
|
return controller_->HandStand(message["param"]["flag"]);
|
||||||
|
} else if (cmd == "FreeWalk") {
|
||||||
|
return controller_->FreeWalk();
|
||||||
|
} else if (cmd == "FreeBound") {
|
||||||
|
return controller_->FreeBound(message["param"]["flag"]);
|
||||||
|
} else if (cmd == "FreeJump") {
|
||||||
|
return controller_->FreeJump(message["param"]["flag"]);
|
||||||
|
} else if (cmd == "FreeAvoid") {
|
||||||
|
return controller_->FreeAvoid(message["param"]["flag"]);
|
||||||
|
} else if (cmd == "ClassicWalk") {
|
||||||
|
return controller_->ClassicWalk(message["param"]["flag"]);
|
||||||
|
} else if (cmd == "WalkUpright") {
|
||||||
|
return controller_->WalkUpright(message["param"]["flag"]);
|
||||||
|
} else if (cmd == "CrossStep") {
|
||||||
|
return controller_->CrossStep(message["param"]["flag"]);
|
||||||
|
} else if (cmd == "AutoRecoverSet") {
|
||||||
|
return controller_->AutoRecoverSet(message["param"]["flag"]);
|
||||||
|
} else if (cmd == "StaticWalk") {
|
||||||
|
return controller_->StaticWalk();
|
||||||
|
} else if (cmd == "TrotRun") {
|
||||||
|
return controller_->TrotRun();
|
||||||
|
} else if (cmd == "EconomicGait") {
|
||||||
|
return controller_->EconomicGait();
|
||||||
|
} else if (cmd == "SwitchAvoidMode") {
|
||||||
|
return controller_->SwitchAvoidMode();
|
||||||
|
}
|
||||||
|
else if (cmd == "BodyHeight") {
|
||||||
|
return controller_->BodyHeight(message["param"]["height"]);
|
||||||
|
} else if (cmd == "SwitchGait") {
|
||||||
|
return controller_->SwitchGait(message["param"]["gait"]);
|
||||||
|
} else if (cmd == "TrajectoryFollow") {
|
||||||
|
return controller_->TrajectoryFollow(message["param"]["path"]);
|
||||||
|
} else if (cmd == "ContinuousGait") {
|
||||||
|
return controller_->ContinuousGait(message["param"]["flag"]);
|
||||||
|
} else if (cmd == "MoveToPos") {
|
||||||
|
return controller_->MoveToPos(message["param"]["x"], message["param"]["y"], message["param"]["yaw"]);
|
||||||
|
} else if (cmd == "FastWalk") {
|
||||||
|
return controller_->FastWalk(message["param"]["flag"]);
|
||||||
|
} else if (cmd == "FootRaiseHeight") {
|
||||||
|
return controller_->FootRaiseHeight(message["param"]["height"]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
LOG_ERROR("Unknown Sport command: " + cmd);
|
LOG_ERROR("Unknown Sport command: " + cmd);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
112
src/navigation.cpp
Normal file
112
src/navigation.cpp
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
#include "navigation.hpp"
|
||||||
|
#include "logger.hpp"
|
||||||
|
#include "unitree/robot/channel/channel_factory.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
const std::string SLAM_SERVICE_NAME = "slam_operate";
|
||||||
|
|
||||||
|
Navigation::Navigation() : client_(nullptr) {}
|
||||||
|
|
||||||
|
Navigation::~Navigation() {}
|
||||||
|
|
||||||
|
void Navigation::Init() {
|
||||||
|
try {
|
||||||
|
client_ = std::make_unique<unitree::robot::Client>(SLAM_SERVICE_NAME);
|
||||||
|
client_->Init();
|
||||||
|
LOG_INFO("Navigation client for service '{}' initialized.", SLAM_SERVICE_NAME);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
LOG_ERROR("Failed to initialize navigation client: {}", e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Navigation::callSlamService(int api_id, const nlohmann::json& data) {
|
||||||
|
if (!client_) {
|
||||||
|
LOG_ERROR("Navigation client not initialized.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
nlohmann::json request_json;
|
||||||
|
request_json["data"] = data;
|
||||||
|
std::string request_str = request_json.dump();
|
||||||
|
std::string response_str;
|
||||||
|
|
||||||
|
LOG_INFO("Calling slam service api_id: {}, request: {}", api_id, request_str);
|
||||||
|
|
||||||
|
int ret = client_->Call(api_id, request_str, response_str);
|
||||||
|
|
||||||
|
if (ret != 0) {
|
||||||
|
LOG_ERROR("Slam service request failed with SDK error code: {}", ret);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO("Slam service response: {}", response_str);
|
||||||
|
|
||||||
|
try {
|
||||||
|
nlohmann::json response_json = nlohmann::json::parse(response_str);
|
||||||
|
if (response_json.contains("succeed") && response_json["succeed"].get<bool>()) {
|
||||||
|
LOG_INFO("Slam service call for api_id {} succeeded. Info: {}", api_id, response_json.value("info", ""));
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("Slam service call for api_id {} failed. Error code: {}, Info: {}",
|
||||||
|
api_id, response_json.value("errorCode", -1), response_json.value("info", ""));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (const nlohmann::json::parse_error& e) {
|
||||||
|
LOG_ERROR("Failed to parse slam service response: {}", e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Navigation::startMapping() {
|
||||||
|
nlohmann::json data;
|
||||||
|
data["slam_type"] = "indoor";
|
||||||
|
return callSlamService(1801, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Navigation::endMapping(const std::string& address) {
|
||||||
|
nlohmann::json data;
|
||||||
|
data["address"] = address;
|
||||||
|
return callSlamService(1802, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Navigation::initializePose(double x, double y, double z, double q_x, double q_y, double q_z, double q_w, const std::string& address) {
|
||||||
|
nlohmann::json data;
|
||||||
|
data["x"] = x;
|
||||||
|
data["y"] = y;
|
||||||
|
data["z"] = z;
|
||||||
|
data["q_x"] = q_x;
|
||||||
|
data["q_y"] = q_y;
|
||||||
|
data["q_z"] = q_z;
|
||||||
|
data["q_w"] = q_w;
|
||||||
|
data["address"] = address;
|
||||||
|
return callSlamService(1804, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Navigation::poseNavigation(double x, double y, double z, double q_x, double q_y, double q_z, double q_w, int mode, double speed) {
|
||||||
|
nlohmann::json data;
|
||||||
|
data["targetPose"]["x"] = x;
|
||||||
|
data["targetPose"]["y"] = y;
|
||||||
|
data["targetPose"]["z"] = z;
|
||||||
|
data["targetPose"]["q_x"] = q_x;
|
||||||
|
data["targetPose"]["q_y"] = q_y;
|
||||||
|
data["targetPose"]["q_z"] = q_z;
|
||||||
|
data["targetPose"]["q_w"] = q_w;
|
||||||
|
data["mode"] = mode;
|
||||||
|
data["speed"] = speed;
|
||||||
|
return callSlamService(1102, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Navigation::pauseNavigation() {
|
||||||
|
nlohmann::json data;
|
||||||
|
return callSlamService(1201, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Navigation::resumeNavigation() {
|
||||||
|
nlohmann::json data;
|
||||||
|
return callSlamService(1202, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Navigation::closeSlam() {
|
||||||
|
nlohmann::json data;
|
||||||
|
return callSlamService(1901, data);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user