feat:完善了自动标定车间的环境
This commit is contained in:
@@ -0,0 +1,49 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.8)
|
||||||
|
project(agv_calib_brain)
|
||||||
|
|
||||||
|
# 1. 寻找 ROS 2 依赖
|
||||||
|
find_package(ament_cmake REQUIRED)
|
||||||
|
find_package(rclcpp REQUIRED)
|
||||||
|
|
||||||
|
# 2. 寻找 gRPC 和 Protobuf 依赖
|
||||||
|
find_package(Protobuf REQUIRED)
|
||||||
|
find_package(gRPC REQUIRED)
|
||||||
|
|
||||||
|
# 3. 设置 Proto 文件路径与自动生成的源码输出路径
|
||||||
|
set(PROTO_DIR "${CMAKE_CURRENT_SOURCE_DIR}/proto")
|
||||||
|
set(PROTO_FILE "${PROTO_DIR}/agv_calib_control.proto")
|
||||||
|
set(PROTO_OUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/grpc_gen")
|
||||||
|
file(MAKE_DIRECTORY ${PROTO_OUT_DIR})
|
||||||
|
|
||||||
|
# 4. 自动生成 gRPC C++ 源码 (每次 colcon build 自动执行)
|
||||||
|
find_program(GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin)
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT "${PROTO_OUT_DIR}/agv_calib_control.pb.cc"
|
||||||
|
"${PROTO_OUT_DIR}/agv_calib_control.pb.h"
|
||||||
|
"${PROTO_OUT_DIR}/agv_calib_control.grpc.pb.cc"
|
||||||
|
"${PROTO_OUT_DIR}/agv_calib_control.grpc.pb.h"
|
||||||
|
COMMAND protoc
|
||||||
|
ARGS --proto_path="${PROTO_DIR}"
|
||||||
|
--cpp_out="${PROTO_OUT_DIR}"
|
||||||
|
--grpc_out="${PROTO_OUT_DIR}"
|
||||||
|
--plugin=protoc-gen-grpc="${GRPC_CPP_PLUGIN_EXECUTABLE}"
|
||||||
|
"${PROTO_FILE}"
|
||||||
|
DEPENDS "${PROTO_FILE}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 5. 将生成的网络源码打包成独立的 C++ 库
|
||||||
|
add_library(agv_grpc_proto_lib SHARED
|
||||||
|
"${PROTO_OUT_DIR}/agv_calib_control.pb.cc"
|
||||||
|
"${PROTO_OUT_DIR}/agv_calib_control.grpc.pb.cc"
|
||||||
|
)
|
||||||
|
target_include_directories(agv_grpc_proto_lib PUBLIC "${PROTO_OUT_DIR}")
|
||||||
|
target_link_libraries(agv_grpc_proto_lib gRPC::grpc++ protobuf::libprotobuf)
|
||||||
|
|
||||||
|
# 6. 编译您的 ROS 2 节点主程序
|
||||||
|
add_executable(brain_node src/brain_node.cpp)
|
||||||
|
ament_target_dependencies(brain_node rclcpp)
|
||||||
|
# 🚨 必须链接刚才生成的 gRPC 库
|
||||||
|
target_link_libraries(brain_node agv_grpc_proto_lib)
|
||||||
|
|
||||||
|
install(TARGETS brain_node DESTINATION lib/${PROJECT_NAME})
|
||||||
|
ament_package()
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||||
|
<package format="3">
|
||||||
|
<name>agv_calib_brain</name>
|
||||||
|
<version>0.0.0</version>
|
||||||
|
<description>TODO: Package description</description>
|
||||||
|
<maintainer email="2469171725@qq.com">nvidia</maintainer>
|
||||||
|
<license>TODO: License declaration</license>
|
||||||
|
|
||||||
|
<buildtool_depend>ament_cmake</buildtool_depend>
|
||||||
|
|
||||||
|
<test_depend>ament_lint_auto</test_depend>
|
||||||
|
<test_depend>ament_lint_common</test_depend>
|
||||||
|
|
||||||
|
<export>
|
||||||
|
<build_type>ament_cmake</build_type>
|
||||||
|
</export>
|
||||||
|
</package>
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
#include <rclcpp/rclcpp.hpp>
|
||||||
|
#include <grpcpp/grpcpp.h>
|
||||||
|
// 包含刚才 CMake 自动生成的头文件
|
||||||
|
#include "agv_calib_control.grpc.pb.h"
|
||||||
|
|
||||||
|
using namespace agv::calibration::control;
|
||||||
|
|
||||||
|
class BrainNode : public rclcpp::Node {
|
||||||
|
public:
|
||||||
|
BrainNode() : Node("calib_brain_node") {
|
||||||
|
// 1. 拨号连接到 Windows 车端 (请替换为车端在 Wi-Fi 6 下的真实 IP)
|
||||||
|
std::string target_ip = "192.168.1.100:50051";
|
||||||
|
|
||||||
|
// 🚨 Wi-Fi 防断联核心:强制开启 gRPC 保活机制 (KeepAlive)
|
||||||
|
grpc::ChannelArguments args;
|
||||||
|
args.SetInt(GRPC_ARG_KEEPALIVE_TIME_MS, 2000); // 每 2 秒发一次 TCP 心跳探活
|
||||||
|
args.SetInt(GRPC_ARG_KEEPALIVE_TIMEOUT_MS, 1000); // 1 秒没回音即认为掉线
|
||||||
|
args.SetInt(GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS, 1);
|
||||||
|
|
||||||
|
auto channel = grpc::CreateCustomChannel(target_ip, grpc::InsecureChannelCredentials(), args);
|
||||||
|
stub_ = AgvCalibControlService::NewStub(channel);
|
||||||
|
|
||||||
|
RCLCPP_INFO(this->get_logger(), "连接车端 %s 中...", target_ip.c_str());
|
||||||
|
|
||||||
|
// 2. 发起夺权指令测试
|
||||||
|
send_control_mode_request();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<AgvCalibControlService::Stub> stub_;
|
||||||
|
|
||||||
|
void send_control_mode_request() {
|
||||||
|
ModeRequest request;
|
||||||
|
request.set_target_mode(ModeRequest::OPEN_LOOP_MODE); // 下发开环提线木偶模式
|
||||||
|
|
||||||
|
StandardResponse response;
|
||||||
|
grpc::ClientContext context;
|
||||||
|
|
||||||
|
// 【网络防卡死】设置单次通信的超时时间为 2 秒,防止死锁 ROS 2 主线程
|
||||||
|
context.set_deadline(std::chrono::system_clock::now() + std::chrono::seconds(2));
|
||||||
|
|
||||||
|
grpc::Status status = stub_->SetControlMode(&context, request, &response);
|
||||||
|
|
||||||
|
if (status.ok() && response.success()) {
|
||||||
|
RCLCPP_INFO(this->get_logger(), "✅ 夺权成功!车端回复: %s", response.message().c_str());
|
||||||
|
} else {
|
||||||
|
RCLCPP_ERROR(this->get_logger(), "❌ 调用失败: %d - %s", status.error_code(), status.error_message().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
rclcpp::init(argc, argv);
|
||||||
|
rclcpp::spin(std::make_shared<BrainNode>());
|
||||||
|
rclcpp::shutdown();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <grpcpp/grpcpp.h>
|
||||||
|
// 包含刚才手动翻译出的头文件
|
||||||
|
#include "agv_calib_control.grpc.pb.h"
|
||||||
|
|
||||||
|
using namespace agv::calibration::control;
|
||||||
|
|
||||||
|
// 继承并实现定义在 .proto 里的服务契约
|
||||||
|
class AgvCalibServiceImpl final : public AgvCalibControlService::Service {
|
||||||
|
|
||||||
|
// 覆盖接管控制权的方法
|
||||||
|
grpc::Status SetControlMode(grpc::ServerContext* context,
|
||||||
|
const ModeRequest* request,
|
||||||
|
StandardResponse* reply) override {
|
||||||
|
|
||||||
|
if (request->target_mode() == ModeRequest::OPEN_LOOP_MODE) {
|
||||||
|
std::cout << "\n[Windows底层] 收到 Linux 指令: 进入开环提线木偶模式" << std::endl;
|
||||||
|
// TODO: 在这里调用 Windows 原有的底盘驱动 DLL 或 CAN 接口,切断避障算法
|
||||||
|
|
||||||
|
reply->set_success(true);
|
||||||
|
reply->set_message("Windows 已交出控制权,避障与运动学逆解已关闭");
|
||||||
|
}
|
||||||
|
return grpc::Status::OK;
|
||||||
|
}
|
||||||
|
// TODO: 接着 override 实现 ExecuteOpenLoopCmd 等其他函数...
|
||||||
|
};
|
||||||
|
|
||||||
|
void RunServer() {
|
||||||
|
// 🚨 关键排雷:必须绑定 0.0.0.0,千万不要写 localhost 或 127.0.0.1,否则 ROS2 连不上!
|
||||||
|
std::string server_address("0.0.0.0:50051");
|
||||||
|
AgvCalibServiceImpl service;
|
||||||
|
|
||||||
|
grpc::ServerBuilder builder;
|
||||||
|
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
|
||||||
|
builder.RegisterService(&service);
|
||||||
|
|
||||||
|
std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
|
||||||
|
std::cout << "🚀 Windows 车端 gRPC 代理已启动,监听外部请求: " << server_address << std::endl;
|
||||||
|
server->Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
RunServer();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user