|
|
|
|
@@ -125,7 +125,7 @@ void CerebellumNode::ConfigureArmHooks()
|
|
|
|
|
return goal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RCLCPP_INFO(this->get_logger(), "[%s]Received Arm goal: body_id=%d, data_type=%d, data_length=%d, command_id=%ld, frame_time_stamp=%ld, data_array=",
|
|
|
|
|
RCLCPP_INFO(this->get_logger(), "[%s]Received Parse Arm goal: body_id=%d, data_type=%d, data_length=%d, command_id=%ld, frame_time_stamp=%ld",
|
|
|
|
|
skill_name.c_str(), goal.body_id, goal.data_type, goal.data_length, goal.command_id, goal.frame_time_stamp);
|
|
|
|
|
|
|
|
|
|
goal.body_id = (tls_arm_body_id == LEFT_ARM ||
|
|
|
|
|
@@ -389,6 +389,9 @@ void CerebellumNode::ConfigureMoveWheelHooks()
|
|
|
|
|
return goal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RCLCPP_INFO(this->get_logger(), "[%s] move_distance=%f, move_angle=%f",
|
|
|
|
|
skill_name.c_str(), goal.move_distance, goal.move_angle);
|
|
|
|
|
|
|
|
|
|
return goal;
|
|
|
|
|
};
|
|
|
|
|
hooks.on_feedback = [this](
|
|
|
|
|
@@ -514,15 +517,18 @@ void CerebellumNode::ConfigureVisionObjectRecognitionHooks()
|
|
|
|
|
hooks.make_request = [this](const std::string & skill_name) {
|
|
|
|
|
auto req = std::make_shared<VisionSrv::Request>();
|
|
|
|
|
// Prefer payload_yaml from calls
|
|
|
|
|
if (TryParseCallPayload<VisionSrv::Request>(skill_name, *req)) {
|
|
|
|
|
if (!TryParseCallPayload<VisionSrv::Request>(skill_name, *req)) {
|
|
|
|
|
RCLCPP_ERROR(this->get_logger(), "[%s] Payload Parse failed", skill_name.c_str());
|
|
|
|
|
return req;
|
|
|
|
|
}
|
|
|
|
|
// fallback to parameter
|
|
|
|
|
const std::string param = "vision_object_recognition.camera_position";
|
|
|
|
|
if (!this->has_parameter(param)) {
|
|
|
|
|
this->declare_parameter<std::string>(param, std::string("left"));
|
|
|
|
|
}
|
|
|
|
|
req->camera_position = this->get_parameter(param).as_string();
|
|
|
|
|
// const std::string param = "vision_object_recognition.camera_position";
|
|
|
|
|
// if (!this->has_parameter(param)) {
|
|
|
|
|
// this->declare_parameter<std::string>(param, std::string("right"));
|
|
|
|
|
// }
|
|
|
|
|
// req->camera_position = this->get_parameter(param).as_string();
|
|
|
|
|
RCLCPP_INFO(this->get_logger(), "[%s] camera_position: %s", skill_name.c_str(), req->camera_position.c_str());
|
|
|
|
|
|
|
|
|
|
return req;
|
|
|
|
|
};
|
|
|
|
|
hooks.on_response = [this](
|
|
|
|
|
@@ -538,36 +544,79 @@ void CerebellumNode::ConfigureVisionObjectRecognitionHooks()
|
|
|
|
|
}
|
|
|
|
|
detail = resp->info.empty() ? std::string("success pose") : resp->info;
|
|
|
|
|
const auto stamp_sec = rclcpp::Time(resp->header.stamp).seconds();
|
|
|
|
|
RCLCPP_INFO(
|
|
|
|
|
this->get_logger(),
|
|
|
|
|
"[%s] success=%d classes=%zu frame_id=%s stamp=%.3f info=%s",
|
|
|
|
|
skill_name.c_str(), resp->success, resp->objects.size(), resp->header.frame_id.c_str(),
|
|
|
|
|
stamp_sec, resp->info.c_str());
|
|
|
|
|
|
|
|
|
|
RCLCPP_INFO(this->get_logger(), "[%s] success=%d classes=%zu frame_id=%s stamp=%.3f info=%s",
|
|
|
|
|
skill_name.c_str(), resp->success, resp->objects.size(),
|
|
|
|
|
resp->header.frame_id.c_str(), stamp_sec, resp->info.c_str());
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < resp->objects.size(); ++i) {
|
|
|
|
|
const auto & obj = resp->objects[i];
|
|
|
|
|
|
|
|
|
|
if (target_frame_ == obj.class_name) {
|
|
|
|
|
target_pose_[target_frame_].header = resp->header;
|
|
|
|
|
target_pose_[target_frame_].pose = obj.pose_list[0];
|
|
|
|
|
target_pose_[target_frame_].header.frame_id = "RightLink6";
|
|
|
|
|
target_pose_[target_frame_].pose = obj.pose;
|
|
|
|
|
target_pose_[target_frame_].pose.position.z -= 0.21;
|
|
|
|
|
grab_width_ = obj.grab_width;
|
|
|
|
|
RCLCPP_INFO(this->get_logger(), "target_frame_: %s, updated target_pose", target_frame_.c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RCLCPP_INFO(
|
|
|
|
|
this->get_logger(), " [%zu] class='%s' id=%d poses=%zu", i,
|
|
|
|
|
obj.class_name.c_str(), obj.class_id, obj.pose_list.size());
|
|
|
|
|
for (size_t j = 0; j < obj.pose_list.size() && j < 2; ++j) {
|
|
|
|
|
const auto & p = obj.pose_list[j];
|
|
|
|
|
RCLCPP_INFO(
|
|
|
|
|
this->get_logger(),
|
|
|
|
|
" pose[%zu]: pos(%.3f, %.3f, %.3f) quat(%.3f, %.3f, %.3f, %.3f)", j,
|
|
|
|
|
p.position.x, p.position.y, p.position.z,
|
|
|
|
|
p.orientation.x, p.orientation.y, p.orientation.z, p.orientation.w);
|
|
|
|
|
}
|
|
|
|
|
if (obj.pose_list.size() > 2) {
|
|
|
|
|
RCLCPP_INFO(
|
|
|
|
|
this->get_logger(), " ... (%zu more poses omitted)", obj.pose_list.size() - 2);
|
|
|
|
|
RCLCPP_INFO(this->get_logger(), " [%zu] class='%s' id=%d", i,
|
|
|
|
|
obj.class_name.c_str(), obj.class_id);
|
|
|
|
|
|
|
|
|
|
const auto & p = obj.pose;
|
|
|
|
|
RCLCPP_INFO(this->get_logger(),
|
|
|
|
|
" pos(%.4f, %.4f, %.4f) quat(%.4f, %.4f, %.4f, %.4f)",
|
|
|
|
|
p.position.x, p.position.y, p.position.z,
|
|
|
|
|
p.orientation.x, p.orientation.y, p.orientation.z, p.orientation.w);
|
|
|
|
|
|
|
|
|
|
geometry_msgs::msg::PoseStamped pose_in_arm;
|
|
|
|
|
const bool transformed = TransformPoseToArmFrame(target_pose_[target_frame_], pose_in_arm);
|
|
|
|
|
if (!transformed) {
|
|
|
|
|
RCLCPP_WARN(this->get_logger(), "[%s] 坐标系转换失败,继续使用 %s 坐标系数据",
|
|
|
|
|
skill_name.c_str(), pose_in_arm.header.frame_id.c_str());
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
RCLCPP_INFO(this->get_logger(), "[%s] 目标姿态已转换到 %s 坐标系",
|
|
|
|
|
skill_name.c_str(), arm_target_frame_.c_str());
|
|
|
|
|
|
|
|
|
|
RCLCPP_INFO(this->get_logger(),
|
|
|
|
|
" pos(%.4f, %.4f, %.4f) quat(%.4f, %.4f, %.4f, %.4f)",
|
|
|
|
|
pose_in_arm.pose.position.x,
|
|
|
|
|
pose_in_arm.pose.position.y,
|
|
|
|
|
pose_in_arm.pose.position.z,
|
|
|
|
|
pose_in_arm.pose.orientation.x,
|
|
|
|
|
pose_in_arm.pose.orientation.y,
|
|
|
|
|
pose_in_arm.pose.orientation.z,
|
|
|
|
|
pose_in_arm.pose.orientation.w);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// const auto pose_it = target_pose_.find(target_frame_);
|
|
|
|
|
// if (pose_it != target_pose_.end()) {
|
|
|
|
|
// geometry_msgs::msg::PoseStamped pose_in_arm;
|
|
|
|
|
// const bool transformed = TransformPoseToArmFrame(pose_it->second, pose_in_arm);
|
|
|
|
|
// const auto & pose_ref = transformed ? pose_in_arm : pose_it->second;
|
|
|
|
|
// if (!transformed) {
|
|
|
|
|
// RCLCPP_WARN(this->get_logger(), "[%s] 坐标系转换失败,继续使用 %s 坐标系数据",
|
|
|
|
|
// skill_name.c_str(), pose_ref.header.frame_id.c_str());
|
|
|
|
|
// } else {
|
|
|
|
|
// RCLCPP_INFO(this->get_logger(), "[%s] 目标姿态已转换到 %s 坐标系",
|
|
|
|
|
// skill_name.c_str(), arm_target_frame_.c_str());
|
|
|
|
|
|
|
|
|
|
// RCLCPP_INFO(this->get_logger(),
|
|
|
|
|
// " pos(%.4f, %.4f, %.4f) quat(%.4f, %.4f, %.4f, %.4f)",
|
|
|
|
|
// pose_ref.pose.position.x,
|
|
|
|
|
// pose_ref.pose.position.y,
|
|
|
|
|
// pose_ref.pose.position.z,
|
|
|
|
|
// pose_ref.pose.orientation.x,
|
|
|
|
|
// pose_ref.pose.orientation.y,
|
|
|
|
|
// pose_ref.pose.orientation.z,
|
|
|
|
|
// pose_ref.pose.orientation.w);
|
|
|
|
|
// }
|
|
|
|
|
// } else {
|
|
|
|
|
// RCLCPP_WARN(this->get_logger(), "[%s] 未找到目标 %s 的姿态缓存,使用默认坐标",
|
|
|
|
|
// skill_name.c_str(), target_frame_.c_str());
|
|
|
|
|
// }
|
|
|
|
|
return true;
|
|
|
|
|
};
|
|
|
|
|
skill_manager_->configure_service_hooks<VisionSrv>("VisionObjectRecognition", std::move(hooks));
|
|
|
|
|
@@ -620,7 +669,7 @@ void CerebellumNode::ConfigureMapLoadHooks()
|
|
|
|
|
hooks.call_timeout = [](const std::string &) { return std::chrono::seconds(5); };
|
|
|
|
|
hooks.make_request = [this](const std::string & skill_name) {
|
|
|
|
|
auto req = std::make_shared<MapLoadSrv::Request>();
|
|
|
|
|
if (TryParseCallPayload<MapLoadSrv::Request>(skill_name, *req)) { return req; }
|
|
|
|
|
if (!TryParseCallPayload<MapLoadSrv::Request>(skill_name, *req)) { return req; }
|
|
|
|
|
// Fallback to parameter
|
|
|
|
|
if (!this->has_parameter("map_load_url")) {
|
|
|
|
|
this->declare_parameter<std::string>("map_load_url", std::string(""));
|
|
|
|
|
@@ -653,7 +702,7 @@ void CerebellumNode::ConfigureMapSaveHooks()
|
|
|
|
|
hooks.call_timeout = [](const std::string &) { return std::chrono::seconds(5); };
|
|
|
|
|
hooks.make_request = [this](const std::string & skill_name) {
|
|
|
|
|
auto req = std::make_shared<MapSaveSrv::Request>();
|
|
|
|
|
if (TryParseCallPayload<MapSaveSrv::Request>(skill_name, *req)) { return req; }
|
|
|
|
|
if (!TryParseCallPayload<MapSaveSrv::Request>(skill_name, *req)) { return req; }
|
|
|
|
|
// Fallback to parameter group
|
|
|
|
|
if (!this->has_parameter("map_save_url")) {
|
|
|
|
|
this->declare_parameter<std::string>("map_save_url", std::string("/tmp/humanoid_map"));
|
|
|
|
|
@@ -1275,15 +1324,14 @@ bool CerebellumNode::ExecuteBilateralArmAction(
|
|
|
|
|
RCLCPP_INFO(this->get_logger(), "[Arm] send two goals: body_id=1 and body_id=0, index=%d, total_skills=%d", index, total_skills);
|
|
|
|
|
RCLCPP_INFO(this->get_logger(), "[Arm] instance='%s' timeout=%ld ms", instance_name.c_str(), static_cast<long>(timeout_ms_override));
|
|
|
|
|
|
|
|
|
|
std::atomic<bool> finished1{false}, finished2{false};
|
|
|
|
|
bool ok1 = false, ok2 = false;
|
|
|
|
|
std::string d1, d2;
|
|
|
|
|
|
|
|
|
|
std::atomic<bool> right_arm_finished{false}, left_arm_finished{false};
|
|
|
|
|
bool right_arm_ok = false, left_arm_ok = false;
|
|
|
|
|
std::string right_arm_d, left_arm_d;
|
|
|
|
|
auto left_arm_time_steady = std::chrono::steady_clock::now();
|
|
|
|
|
auto right_arm_time_steady = std::chrono::steady_clock::now();
|
|
|
|
|
|
|
|
|
|
auto worker = [this, &ok_out = ok1, &done_flag = finished1, &d_out = d1,
|
|
|
|
|
skill, topic, timeout, &goal_handle, &time_steady = left_arm_time_steady](int body_id) {
|
|
|
|
|
auto left_arm_worker = [this, &ok_out = left_arm_ok, &done_flag = left_arm_finished, &d_out = left_arm_d,
|
|
|
|
|
skill, topic, timeout, &goal_handle, &time_steady = left_arm_time_steady](int body_id) {
|
|
|
|
|
tls_arm_body_id = body_id;
|
|
|
|
|
const auto * prev_calls = CerebellumNode::tls_current_calls_;
|
|
|
|
|
CerebellumNode::tls_current_calls_ = &goal_handle->get_goal()->calls;
|
|
|
|
|
@@ -1294,10 +1342,10 @@ bool CerebellumNode::ExecuteBilateralArmAction(
|
|
|
|
|
time_steady = std::chrono::steady_clock::now();
|
|
|
|
|
RCLCPP_WARN(this->get_logger(), "left_arm_time_steady2");
|
|
|
|
|
};
|
|
|
|
|
std::thread left_arm_thread(left_arm_worker, LEFT_ARM); // LEFT_ARM=0
|
|
|
|
|
|
|
|
|
|
std::thread t1(worker, RIGHT_ARM); // RIGHT_ARM=1
|
|
|
|
|
auto worker2 = [this, &ok_out = ok2, &done_flag = finished2, &d_out = d2,
|
|
|
|
|
skill, topic, timeout, &goal_handle, &time_steady = right_arm_time_steady](int body_id) {
|
|
|
|
|
auto right_arm_worker = [this, &ok_out = right_arm_ok, &done_flag = right_arm_finished, &d_out = right_arm_d,
|
|
|
|
|
skill, topic, timeout, &goal_handle, &time_steady = right_arm_time_steady](int body_id) {
|
|
|
|
|
tls_arm_body_id = body_id;
|
|
|
|
|
const auto * prev_calls = CerebellumNode::tls_current_calls_;
|
|
|
|
|
CerebellumNode::tls_current_calls_ = &goal_handle->get_goal()->calls;
|
|
|
|
|
@@ -1308,11 +1356,11 @@ bool CerebellumNode::ExecuteBilateralArmAction(
|
|
|
|
|
time_steady = std::chrono::steady_clock::now();
|
|
|
|
|
RCLCPP_WARN(this->get_logger(), "right_arm_time_steady2");
|
|
|
|
|
};
|
|
|
|
|
std::thread t2(worker2, LEFT_ARM); // LEFT_ARM=0
|
|
|
|
|
std::thread right_arm_thread(right_arm_worker, RIGHT_ARM); // RIGHT_ARM=1
|
|
|
|
|
|
|
|
|
|
const auto start_steady = std::chrono::steady_clock::now();
|
|
|
|
|
|
|
|
|
|
while (!(finished1.load(std::memory_order_acquire) && finished2.load(std::memory_order_acquire))) {
|
|
|
|
|
while (!(right_arm_finished.load(std::memory_order_acquire) && left_arm_finished.load(std::memory_order_acquire))) {
|
|
|
|
|
double elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start_steady).count();
|
|
|
|
|
PublishFeedbackStage(goal_handle, "RUN", skill, elapsed_ms, "");
|
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
|
|
|
@@ -1322,30 +1370,30 @@ bool CerebellumNode::ExecuteBilateralArmAction(
|
|
|
|
|
RCLCPP_WARN(this->get_logger(), "arm_exe_bias: %f", arm_exe_bias);
|
|
|
|
|
|
|
|
|
|
if (timeout_ms_override > 0 && std::abs(arm_exe_bias) > timeout_ms_override) {
|
|
|
|
|
ok1 = false;
|
|
|
|
|
ok2 = false;
|
|
|
|
|
right_arm_ok = false;
|
|
|
|
|
left_arm_ok = false;
|
|
|
|
|
RCLCPP_ERROR(this->get_logger(), "Fail in Arm arm_exe_bias: %f, timeout_ms_override=%ld", arm_exe_bias, static_cast<long>(timeout_ms_override));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (t1.joinable()) {
|
|
|
|
|
if (right_arm_thread.joinable()) {
|
|
|
|
|
try {
|
|
|
|
|
t1.join();
|
|
|
|
|
right_arm_thread.join();
|
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
RCLCPP_ERROR(this->get_logger(), "Exception in Arm thread 1 join: %s", e.what());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (t2.joinable()) {
|
|
|
|
|
if (left_arm_thread.joinable()) {
|
|
|
|
|
try {
|
|
|
|
|
t2.join();
|
|
|
|
|
left_arm_thread.join();
|
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
RCLCPP_ERROR(this->get_logger(), "Exception in Arm thread 2 join: %s", e.what());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ok1 || !ok2) {
|
|
|
|
|
if (!right_arm_ok || !left_arm_ok) {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
if (!ok1) { oss << "Arm(body_id=1) failed"; if (!d1.empty()) oss << ": " << d1; }
|
|
|
|
|
if (!ok2) { if (!oss.str().empty()) oss << "; "; oss << "Arm(body_id=0) failed"; if (!d2.empty()) oss << ": " << d2; }
|
|
|
|
|
if (!right_arm_ok) { oss << "Arm(body_id=1) failed"; if (!right_arm_d.empty()) oss << ": " << right_arm_d; }
|
|
|
|
|
if (!left_arm_ok) { if (!oss.str().empty()) oss << "; "; oss << "Arm(body_id=0) failed"; if (!left_arm_d.empty()) oss << ": " << left_arm_d; }
|
|
|
|
|
detail = oss.str();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
@@ -1383,7 +1431,7 @@ bool CerebellumNode::ExecuteServiceSkill(
|
|
|
|
|
for (const auto & iface : spec.interfaces) {
|
|
|
|
|
const auto pos = iface.rfind('.');
|
|
|
|
|
if (pos == std::string::npos || pos + 1 >= iface.size()) {continue;}
|
|
|
|
|
if (to_lower_str(iface.substr(pos + 1)) == "service") {
|
|
|
|
|
if (to_lower_str(iface.substr(pos + 1)) == "srv") {
|
|
|
|
|
service_base = iface.substr(0, pos);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|