控制器待完善
This commit is contained in:
commit
98f4de74d2
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/.cache
|
||||||
|
/.vscode
|
||||||
|
/bin
|
||||||
|
/build
|
||||||
|
/unused
|
||||||
|
/log
|
||||||
|
/packages
|
||||||
|
/crs
|
||||||
|
/.xmake
|
||||||
|
/compile_commands.json
|
||||||
|
|
||||||
1
AbilitySDK
Submodule
1
AbilitySDK
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit e20893b78a520157efeb28aeadb5914c5435d8f8
|
||||||
31
ConveyorBeltAbility/include/ConveyorBeltAbility.h.old
Normal file
31
ConveyorBeltAbility/include/ConveyorBeltAbility.h.old
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
#include "ability_sdk/AbilityStub.hpp"
|
||||||
|
#include "conveyorBeltGrpcServer.h"
|
||||||
|
|
||||||
|
|
||||||
|
class ConveyorBeltAbility : public ability_sdk::AbilityStub<ConveyorBeltStatus> {
|
||||||
|
public:
|
||||||
|
using AbilityTemplate::AbilityTemplate;
|
||||||
|
|
||||||
|
void create_ability_server() {
|
||||||
|
ConveyorBeltServer service_ability;
|
||||||
|
ServerBuilder builder;
|
||||||
|
builder.AddListeningPort("0.0.0.0:0", grpc::InsecureServerCredentials(), &g_abilityPort);
|
||||||
|
cout << "add listening port" << endl;
|
||||||
|
builder.RegisterService(&service_ability);
|
||||||
|
cout << "register service" << endl;
|
||||||
|
ability_cq = builder.AddCompletionQueue();
|
||||||
|
ability_server = builder.BuildAndStart();
|
||||||
|
std::cout << "Server listening on port: " << g_abilityPort << std::endl;
|
||||||
|
sendStateMsg();
|
||||||
|
ability_server->Wait();
|
||||||
|
std::cout << "finish ipc server" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void runServer() {
|
||||||
|
g_GLOBAL_STATUS = STATUS_INIT;
|
||||||
|
std::cout << "NOW GLOBAL STATUS IS: " << global2string(g_GLOBAL_STATUS) << std::endl;
|
||||||
|
std::thread heartbeat_thread(&ConveyorBeltAbility::heartbeat_loop, this);
|
||||||
|
heartbeat_thread.detach();
|
||||||
|
}
|
||||||
|
};
|
||||||
64
ConveyorBeltAbility/include/conveyorBeltAbility.hpp
Normal file
64
ConveyorBeltAbility/include/conveyorBeltAbility.hpp
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#include "ability_sdk/AbilityStub.hpp"
|
||||||
|
#include "conveyorBeltGrpcServer.h"
|
||||||
|
#include <thread>
|
||||||
|
#include <grpcpp/grpcpp.h>
|
||||||
|
|
||||||
|
|
||||||
|
class ConveyorBeltAbility : public ability_sdk::AbilityInterface {
|
||||||
|
public:
|
||||||
|
|
||||||
|
int g_abilityPort = 0;
|
||||||
|
std::unique_ptr<Server> ability_server;
|
||||||
|
std::unique_ptr<grpc::ServerCompletionQueue> ability_cq;
|
||||||
|
|
||||||
|
// GRPC 服务端
|
||||||
|
void create_ability_server();
|
||||||
|
|
||||||
|
void onStart() override{
|
||||||
|
|
||||||
|
LOG(WARNING) << "OnStart";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void onConnect() override {
|
||||||
|
|
||||||
|
LOG(WARNING) << "OnConnect";
|
||||||
|
std::thread t_abilityserver(&ConveyorBeltAbility::create_ability_server, this);
|
||||||
|
t_abilityserver.detach();
|
||||||
|
|
||||||
|
// 主线程轮询等待端口号更新
|
||||||
|
while (g_abilityPort == 0) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(2));
|
||||||
|
}
|
||||||
|
LOG(WARNING) << "GRPC Server listening on port: "<< g_abilityPort;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void onDisconnect() override {
|
||||||
|
|
||||||
|
LOG(WARNING) << "OnDisconnect";
|
||||||
|
ability_server->Shutdown();
|
||||||
|
ability_cq->Shutdown();
|
||||||
|
g_abilityPort = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void onTerminate() override {
|
||||||
|
|
||||||
|
LOG(WARNING) << "OnTerminate";
|
||||||
|
onDisconnect();
|
||||||
|
exit(0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取端口
|
||||||
|
int abilityPort() const override {
|
||||||
|
return g_abilityPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
void onSubabilityError(const ability_sdk::SubabilityErrorParam& param) override {
|
||||||
|
LOG(INFO) << "onSubabilityError called in ConveyorBeltAbility";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
57
ConveyorBeltAbility/include/conveyorBeltGrpcServer.h
Normal file
57
ConveyorBeltAbility/include/conveyorBeltGrpcServer.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#ifndef CONVEYOR_BELT_GRPC_SERVER_H_
|
||||||
|
#define CONVEYOR_BELT_GRPC_SERVER_H_
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include "conveyorBelt.grpc.pb.h"
|
||||||
|
#include "conveyorBelt.pb.h"
|
||||||
|
#include "conveyorBeltControlUnit.h"
|
||||||
|
#include <glog/logging.h>
|
||||||
|
#include <grpcpp/grpcpp.h>
|
||||||
|
|
||||||
|
using grpc::Server;
|
||||||
|
using grpc::ServerBuilder;
|
||||||
|
using grpc::ServerContext;
|
||||||
|
using grpc::Status;
|
||||||
|
|
||||||
|
using ConveyorBelt::ConveyorBeltService;
|
||||||
|
|
||||||
|
typedef int RunningState;
|
||||||
|
|
||||||
|
class ConveyorBeltServer : public ConveyorBeltService::Service {
|
||||||
|
private:
|
||||||
|
/* data */
|
||||||
|
public:
|
||||||
|
::grpc::Status open(
|
||||||
|
::grpc::ServerContext* context,
|
||||||
|
const ::ConveyorBelt::SpeedInfo* request,
|
||||||
|
::ConveyorBelt::Response* response
|
||||||
|
) override;
|
||||||
|
::grpc::Status close(
|
||||||
|
::grpc::ServerContext* context,
|
||||||
|
const ::ConveyorBelt::DeviceID* request,
|
||||||
|
::ConveyorBelt::Response* response
|
||||||
|
) override;
|
||||||
|
::grpc::Status setSpeed(
|
||||||
|
::grpc::ServerContext* context,
|
||||||
|
const ::ConveyorBelt::SpeedInfo* request,
|
||||||
|
::ConveyorBelt::Response* response
|
||||||
|
) override;
|
||||||
|
::grpc::Status setDirection(
|
||||||
|
::grpc::ServerContext* context,
|
||||||
|
const ::ConveyorBelt::DirectionInfo* request,
|
||||||
|
::ConveyorBelt::Response* response
|
||||||
|
) override;
|
||||||
|
::grpc::Status getWorkState(
|
||||||
|
::grpc::ServerContext* context,
|
||||||
|
const ::ConveyorBelt::DeviceID* request,
|
||||||
|
::ConveyorBelt::Response* response
|
||||||
|
) override;
|
||||||
|
ConveyorBeltServer();
|
||||||
|
~ConveyorBeltServer();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
17
ConveyorBeltAbility/src/conveyorBeltAbility.cpp
Normal file
17
ConveyorBeltAbility/src/conveyorBeltAbility.cpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#include "conveyorBeltAbility.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
// GRPC 服务端
|
||||||
|
void ConveyorBeltAbility::create_ability_server() {
|
||||||
|
ConveyorBeltServer service_ability;
|
||||||
|
ServerBuilder builder;
|
||||||
|
builder.AddListeningPort("0.0.0.0:0", grpc::InsecureServerCredentials(), &g_abilityPort);
|
||||||
|
builder.RegisterService(&service_ability);
|
||||||
|
LOG(WARNING) << "GRPC Server register service";
|
||||||
|
ability_cq = builder.AddCompletionQueue();
|
||||||
|
ability_server = builder.BuildAndStart();
|
||||||
|
//LOG(WARNING) << "GRPC Server add listening port"<< g_abilityPort;
|
||||||
|
ability_server->Wait();
|
||||||
|
LOG(WARNING) << "finish ipc server";
|
||||||
|
}
|
||||||
|
|
||||||
97
ConveyorBeltAbility/src/conveyorGrpcServer.cpp
Normal file
97
ConveyorBeltAbility/src/conveyorGrpcServer.cpp
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
#include "conveyorBeltGrpcServer.h"
|
||||||
|
|
||||||
|
ConveyorBeltControlUnit controlUnit;
|
||||||
|
|
||||||
|
::grpc::Status ConveyorBeltServer::open(
|
||||||
|
::grpc::ServerContext* context,
|
||||||
|
const ::ConveyorBelt::SpeedInfo* request,
|
||||||
|
::ConveyorBelt::Response* response
|
||||||
|
) {
|
||||||
|
std::cout << "grpc call open start" << std::endl;
|
||||||
|
if (controlUnit.getWorkState() == 0) {
|
||||||
|
response->set_code(-1);
|
||||||
|
return ::grpc::Status::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
float speed = request->speed();
|
||||||
|
if (speed > 0.16) {
|
||||||
|
response->set_code(-1);
|
||||||
|
return ::grpc::Status::OK;
|
||||||
|
}
|
||||||
|
controlUnit.init();
|
||||||
|
int ret = controlUnit.setSpeed(speed);
|
||||||
|
if (ret < 0) {
|
||||||
|
response->set_code(-1);
|
||||||
|
return ::grpc::Status::OK;
|
||||||
|
}
|
||||||
|
controlUnit.startConveyorBelt();
|
||||||
|
std::thread workThread(&ConveyorBeltControlUnit::conveyorBeltWorkingProcess, &controlUnit);
|
||||||
|
workThread.detach();
|
||||||
|
std::cout << "grpc call open finish" << std::endl;
|
||||||
|
response->set_code(0);
|
||||||
|
return ::grpc::Status::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
::grpc::Status ConveyorBeltServer::close(
|
||||||
|
::grpc::ServerContext* context,
|
||||||
|
const ::ConveyorBelt::DeviceID* request,
|
||||||
|
::ConveyorBelt::Response* response
|
||||||
|
) {
|
||||||
|
std::cout << "grpc call close start" << std::endl;
|
||||||
|
if (controlUnit.getWorkState() < 0) {
|
||||||
|
response->set_code(-1);
|
||||||
|
return ::grpc::Status::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
controlUnit.stopConveyorBelt();
|
||||||
|
std::cout << "grpc call close finish" << std::endl;
|
||||||
|
response->set_code(0);
|
||||||
|
return ::grpc::Status::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
::grpc::Status ConveyorBeltServer::setSpeed(
|
||||||
|
::grpc::ServerContext* context,
|
||||||
|
const ::ConveyorBelt::SpeedInfo* request,
|
||||||
|
::ConveyorBelt::Response* response
|
||||||
|
) {
|
||||||
|
std::cout << "grpc call set speed start" << std::endl;
|
||||||
|
int ret = controlUnit.setSpeed(request->speed());
|
||||||
|
if (ret < 0) {
|
||||||
|
response->set_code(-1);
|
||||||
|
::grpc::Status::OK;
|
||||||
|
}
|
||||||
|
std::cout << "grpc call set speed finish" << std::endl;
|
||||||
|
response->set_code(0);
|
||||||
|
return ::grpc::Status::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
::grpc::Status ConveyorBeltServer::setDirection(
|
||||||
|
::grpc::ServerContext* context,
|
||||||
|
const ::ConveyorBelt::DirectionInfo* request,
|
||||||
|
::ConveyorBelt::Response* response
|
||||||
|
) {
|
||||||
|
std::cout << "grpc call set direction start" << std::endl;
|
||||||
|
int ret = controlUnit.setDirection(request->direction());
|
||||||
|
if (ret < 0) {
|
||||||
|
response->set_code(-1);
|
||||||
|
::grpc::Status::OK;
|
||||||
|
}
|
||||||
|
std::cout << "grpc call set direction finish" << std::endl;
|
||||||
|
response->set_code(0);
|
||||||
|
return ::grpc::Status::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
::grpc::Status ConveyorBeltServer::getWorkState(
|
||||||
|
::grpc::ServerContext* context,
|
||||||
|
const ::ConveyorBelt::DeviceID* request,
|
||||||
|
::ConveyorBelt::Response* response
|
||||||
|
) {
|
||||||
|
std::cout << "grpc call get state start" << std::endl;
|
||||||
|
response->set_code(controlUnit.getWorkState());
|
||||||
|
std::cout << "grpc call get state finish" << std::endl;
|
||||||
|
return ::grpc::Status::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConveyorBeltServer::ConveyorBeltServer() {}
|
||||||
|
|
||||||
|
ConveyorBeltServer::~ConveyorBeltServer() {}
|
||||||
28
ConveyorBeltAbility/src/main.cpp
Normal file
28
ConveyorBeltAbility/src/main.cpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#include "conveyorBeltAbility.hpp"
|
||||||
|
#include "ability_sdk/AbilityStub.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, const char** argv) {
|
||||||
|
|
||||||
|
ability_sdk::configure_glog(argv[0]);
|
||||||
|
ConveyorBeltAbility ability1;
|
||||||
|
ability_sdk::IpcServerHandle handle(&ability1);
|
||||||
|
handle.init(argc, argv);
|
||||||
|
handle.run();
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Init 阶段
|
||||||
|
通过环境变量,尝试设置目录路径,启动glog
|
||||||
|
启动 redis 客户端
|
||||||
|
向框架读取,获取能力CR,填充ability_info, 并设置 heartbeater
|
||||||
|
设置生命周期ipc服务器
|
||||||
|
启动心跳包
|
||||||
|
|
||||||
|
Start 阶段
|
||||||
|
|
||||||
|
如果有子能力,则初始化SubabilityMgr,并读取子能力cr
|
||||||
|
如果有子能力,尝试启动子能力
|
||||||
|
启动状态同步机制 */
|
||||||
29
ConveyorBeltControlUnit/include/color.h
Normal file
29
ConveyorBeltControlUnit/include/color.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef UTILS_COLOR_H_
|
||||||
|
#define UTILS_COLOR_H_
|
||||||
|
|
||||||
|
#define EMPTY "\e[0m"
|
||||||
|
#define BLACK "\e[0;30m"
|
||||||
|
#define L_BLACK "\e[1;30m"
|
||||||
|
#define RED "\e[0;31m"
|
||||||
|
#define L_RED "\e[1;31m"
|
||||||
|
#define GREEN "\e[0;32m"
|
||||||
|
#define L_GREEN "\e[1;32m"
|
||||||
|
#define BROWN "\e[0;33m"
|
||||||
|
#define YELLOW "\e[1;33m"
|
||||||
|
#define BLUE "\e[0;34m"
|
||||||
|
#define L_BLUE "\e[1;34m"
|
||||||
|
#define PURPLE "\e[0;35m"
|
||||||
|
#define L_PURPLE "\e[1;35m"
|
||||||
|
#define CYAN "\e[0;36m"
|
||||||
|
#define L_CYAN "\e[1;36m"
|
||||||
|
#define GRAY "\e[0;37m"
|
||||||
|
#define WHITE "\e[1;37m"
|
||||||
|
#define BOLD "\e[1m"
|
||||||
|
#define UNDERLINE "\e[4m"
|
||||||
|
#define BLINK "\e[5m"
|
||||||
|
#define REVERSE "\e[7m"
|
||||||
|
#define HIDE "\e[8m"
|
||||||
|
#define CLEAR "\e[2J"
|
||||||
|
#define CLRLINE "\r\e[K"
|
||||||
|
|
||||||
|
#endif // UTILS_COLOR_H_
|
||||||
74
ConveyorBeltControlUnit/include/conveyorBeltControlUnit.h
Normal file
74
ConveyorBeltControlUnit/include/conveyorBeltControlUnit.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#include "color.h"
|
||||||
|
#include <glog/logging.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
#include <queue>
|
||||||
|
#include <shared_mutex>
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
#include <time.h>
|
||||||
|
extern "C" {
|
||||||
|
#include <modbus/modbus.h>
|
||||||
|
//#include <wiringPi.h> // 树莓派GPIO库
|
||||||
|
// src中202行记得修改
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConveyorBeltControlUnit {
|
||||||
|
private:
|
||||||
|
// 所有的输入端口配置为内部上拉,低有效
|
||||||
|
// 悬空时为高,视为逻辑0
|
||||||
|
// 外部拉低时,视为逻辑1
|
||||||
|
const int IN_LOGIC_0 = 1;
|
||||||
|
const int IN_LOGIC_1 = 0;
|
||||||
|
|
||||||
|
// 输出端口为Push-Pull模式
|
||||||
|
// 逻辑开时输出高电平
|
||||||
|
// 逻辑低时输出低电平
|
||||||
|
const int OUT_ON = 1;
|
||||||
|
const int OUT_OFF = 0;
|
||||||
|
|
||||||
|
const int BTN_DIRSWITCH = 26; // 运行方向切换按钮
|
||||||
|
const int BTN_START = 23; // 启动按钮
|
||||||
|
const int BTN_STOP = 24; // 停止按钮
|
||||||
|
const int BTN_ESTOP = 11; // 急停
|
||||||
|
|
||||||
|
int INPUT_FSENSOR = 28; // 正转边沿传感器
|
||||||
|
int INPUT_RSENSOR = 29; // 反转边沿传感器
|
||||||
|
int OUT_FRUN = 14; // 正向运行输出
|
||||||
|
int OUT_RRUN = 10; // 反向运行输出
|
||||||
|
|
||||||
|
// 定义事件
|
||||||
|
const int EVENT_ESTOP_PUSH = 0; // 急停按下(电平触发)
|
||||||
|
const int EVENT_STOP_PUSH = 1; // 停止按下(电平触发)
|
||||||
|
const int EVENT_FSENSOR_OBSTRUCT = 2; // 正转传感器触发(电平触发)
|
||||||
|
const int EVENT_RSENSOR_OBSTRUCT = 3; // 反转传感器触发(电平触发)
|
||||||
|
const int EVENT_DIRSWITCH_RISING = 4; // 切换运转方向(逻辑上升沿触发)
|
||||||
|
const int EVENT_START_RISING = 5; // 开始运行(逻辑上升沿触发)
|
||||||
|
|
||||||
|
// 定义unit工作状态
|
||||||
|
const int RUNNING = 1;
|
||||||
|
const int STANDBY = 0;
|
||||||
|
|
||||||
|
int current_start_signal;
|
||||||
|
int current_stop_signal;
|
||||||
|
int currentMode;
|
||||||
|
float speed;
|
||||||
|
int workState;
|
||||||
|
std::map<int, std::map<int, int>> modeSwitchMap;
|
||||||
|
void action(int event);
|
||||||
|
std::string modeToString();
|
||||||
|
int getWaitCount();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void conveyorBeltWorkingProcess();
|
||||||
|
int init();
|
||||||
|
int setSpeed(float speed);
|
||||||
|
int setDirection(int direction);
|
||||||
|
int startConveyorBelt();
|
||||||
|
int stopConveyorBelt();
|
||||||
|
int getWorkState();
|
||||||
|
ConveyorBeltControlUnit(/* args */);
|
||||||
|
~ConveyorBeltControlUnit();
|
||||||
|
};
|
||||||
223
ConveyorBeltControlUnit/src/conveyorBeltControlUnit.cpp
Normal file
223
ConveyorBeltControlUnit/src/conveyorBeltControlUnit.cpp
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
#include "conveyorBeltControlUnit.h"
|
||||||
|
|
||||||
|
// 202行记得修改
|
||||||
|
// x86 无法运行
|
||||||
|
|
||||||
|
// 定义状态
|
||||||
|
const int MODE_INIT = 0; // 初始状态
|
||||||
|
const int MODE_FRUN = 1; // 正转运行状态
|
||||||
|
const int MODE_RRUN = 2; // 反转运行状态
|
||||||
|
const int MODE_CLOSING_STEP1 = 3; // 进入关闭状态步骤1
|
||||||
|
const int MODE_CLOSING_STEP2 = 4; // 进入关闭状态步骤2
|
||||||
|
const int MODE_STOP = 5;
|
||||||
|
int ConveyorBeltControlUnit::getWaitCount() {
|
||||||
|
return 2 * (0.8 / speed) / 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ConveyorBeltControlUnit::modeToString() {
|
||||||
|
switch (currentMode) {
|
||||||
|
case MODE_INIT: return "MODE_INIT";
|
||||||
|
case MODE_FRUN: return "MODE_FRUN";
|
||||||
|
case MODE_RRUN: return "MODE_RRUN";
|
||||||
|
case MODE_CLOSING_STEP1: return "MODE_CLOSING_STEP1";
|
||||||
|
case MODE_CLOSING_STEP2: return "MODE_CLOSING_STEP2";
|
||||||
|
case MODE_STOP: return "MODE_STOP";
|
||||||
|
default: return "INVALID";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConveyorBeltControlUnit::action(int event) {
|
||||||
|
/* int destMode = modeSwitchMap[currentMode][event];
|
||||||
|
if (destMode == currentMode) { return; }
|
||||||
|
|
||||||
|
switch (destMode) {
|
||||||
|
case MODE_INIT:
|
||||||
|
digitalWrite(OUT_FRUN, OUT_OFF);
|
||||||
|
digitalWrite(OUT_RRUN, OUT_OFF);
|
||||||
|
break;
|
||||||
|
case MODE_FRUN:
|
||||||
|
digitalWrite(OUT_FRUN, OUT_ON);
|
||||||
|
digitalWrite(OUT_RRUN, OUT_OFF);
|
||||||
|
break;
|
||||||
|
case MODE_RRUN:
|
||||||
|
digitalWrite(OUT_FRUN, OUT_OFF);
|
||||||
|
digitalWrite(OUT_RRUN, OUT_ON);
|
||||||
|
break;
|
||||||
|
case MODE_CLOSING_STEP1: break;
|
||||||
|
case MODE_CLOSING_STEP2:
|
||||||
|
digitalWrite(OUT_FRUN, OUT_OFF);
|
||||||
|
digitalWrite(OUT_RRUN, OUT_ON);
|
||||||
|
break;
|
||||||
|
case MODE_STOP:
|
||||||
|
digitalWrite(OUT_FRUN, OUT_OFF);
|
||||||
|
digitalWrite(OUT_RRUN, OUT_OFF);
|
||||||
|
workState = STANDBY;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
currentMode = destMode;
|
||||||
|
LOG(INFO) << GREEN << "now mode is " << modeToString() << EMPTY; */
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConveyorBeltControlUnit::conveyorBeltWorkingProcess() {
|
||||||
|
/* workState = RUNNING;
|
||||||
|
int waitCount = 0;
|
||||||
|
int count = 0;
|
||||||
|
while (workState == RUNNING) {
|
||||||
|
waitCount = getWaitCount();
|
||||||
|
if (currentMode == MODE_CLOSING_STEP1 || currentMode == MODE_CLOSING_STEP2) {
|
||||||
|
count--;
|
||||||
|
if (count < 0) { action(EVENT_RSENSOR_OBSTRUCT); }
|
||||||
|
}
|
||||||
|
else { count = waitCount; }
|
||||||
|
|
||||||
|
if (current_start_signal == 1) {
|
||||||
|
LOG(INFO) << YELLOW << "find a start signal" << EMPTY;
|
||||||
|
current_start_signal = 0;
|
||||||
|
action(EVENT_START_RISING);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (digitalRead(INPUT_FSENSOR) == IN_LOGIC_1) {
|
||||||
|
// LOG(INFO) << YELLOW << "find a Fsensor signal" << EMPTY;
|
||||||
|
action(EVENT_FSENSOR_OBSTRUCT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (digitalRead(INPUT_RSENSOR) == IN_LOGIC_1) {
|
||||||
|
// LOG(INFO) << YELLOW << "find a Rsensor signal" << EMPTY;
|
||||||
|
action(EVENT_RSENSOR_OBSTRUCT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_stop_signal == 1) {
|
||||||
|
LOG(INFO) << YELLOW << "find a stop signal" << EMPTY;
|
||||||
|
LOG(INFO) << YELLOW << "wait count is " << waitCount << " last wait count left "
|
||||||
|
<< count << EMPTY;
|
||||||
|
current_stop_signal = 0;
|
||||||
|
action(EVENT_STOP_PUSH);
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
|
} */
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConveyorBeltControlUnit::init() {
|
||||||
|
current_start_signal = 0;
|
||||||
|
current_stop_signal = 0;
|
||||||
|
currentMode = MODE_INIT;
|
||||||
|
speed = 0;
|
||||||
|
workState = STANDBY;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConveyorBeltControlUnit::setSpeed(float speed) {
|
||||||
|
// if (workState == RUNNING)
|
||||||
|
// {
|
||||||
|
// return -1;
|
||||||
|
// }
|
||||||
|
// 原本已经有的注释
|
||||||
|
|
||||||
|
/* int regValue = speed * 62500;
|
||||||
|
modbus_t* ctx = modbus_new_rtu("/dev/ttyUSB0", 9600, 'N', 8, 2);
|
||||||
|
modbus_set_slave(ctx, 1);
|
||||||
|
if (modbus_connect(ctx) == -1) {
|
||||||
|
fprintf(stderr, "Connection failed:%s\n", modbus_strerror(errno));
|
||||||
|
modbus_free(ctx);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
LOG(INFO) << YELLOW << "set speed:" << speed << " set register:" << regValue << EMPTY;
|
||||||
|
int result = modbus_write_register(ctx, 4096, regValue);
|
||||||
|
if (result == -1) {
|
||||||
|
fprintf(stderr, "write failed:%s\n", modbus_strerror(errno));
|
||||||
|
modbus_free(ctx);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
LOG(INFO) << YELLOW << "get result from com" << ":" << result << EMPTY;
|
||||||
|
uint16_t* speedBuffer = (uint16_t*)malloc(sizeof(uint16_t));
|
||||||
|
int getBytes = modbus_read_registers(ctx, 4096, 2, speedBuffer);
|
||||||
|
LOG(INFO) << YELLOW << "get result from com : " << getBytes << " register:" << *speedBuffer
|
||||||
|
<< EMPTY;
|
||||||
|
this->speed = speed;
|
||||||
|
modbus_free(ctx); */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConveyorBeltControlUnit::setDirection(int direction) {
|
||||||
|
if (workState == RUNNING) { return -1; }
|
||||||
|
|
||||||
|
if (direction == 0) {
|
||||||
|
LOG(INFO) << YELLOW << "set direction to foreward" << EMPTY;
|
||||||
|
INPUT_FSENSOR = 28;
|
||||||
|
INPUT_RSENSOR = 29;
|
||||||
|
OUT_FRUN = 14;
|
||||||
|
OUT_RRUN = 10;
|
||||||
|
}
|
||||||
|
else if (direction == 1) {
|
||||||
|
LOG(INFO) << YELLOW << "set direction to reversal" << EMPTY;
|
||||||
|
INPUT_FSENSOR = 29;
|
||||||
|
INPUT_RSENSOR = 28;
|
||||||
|
OUT_FRUN = 10;
|
||||||
|
OUT_RRUN = 14;
|
||||||
|
}
|
||||||
|
else { return -1; }
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConveyorBeltControlUnit::startConveyorBelt() {
|
||||||
|
current_start_signal = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConveyorBeltControlUnit::stopConveyorBelt() {
|
||||||
|
current_stop_signal = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConveyorBeltControlUnit::getWorkState() {
|
||||||
|
if (workState == RUNNING) { return 0; }
|
||||||
|
else { return -1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
ConveyorBeltControlUnit::ConveyorBeltControlUnit(/* args */) {
|
||||||
|
modeSwitchMap[MODE_INIT]
|
||||||
|
= {{EVENT_START_RISING, MODE_FRUN},
|
||||||
|
{EVENT_FSENSOR_OBSTRUCT, MODE_INIT},
|
||||||
|
{EVENT_RSENSOR_OBSTRUCT, MODE_INIT},
|
||||||
|
{EVENT_STOP_PUSH, MODE_INIT}};
|
||||||
|
modeSwitchMap[MODE_FRUN]
|
||||||
|
= {{EVENT_START_RISING, MODE_FRUN},
|
||||||
|
{EVENT_FSENSOR_OBSTRUCT, MODE_RRUN},
|
||||||
|
{EVENT_RSENSOR_OBSTRUCT, MODE_FRUN},
|
||||||
|
{EVENT_STOP_PUSH, MODE_CLOSING_STEP1}};
|
||||||
|
modeSwitchMap[MODE_RRUN]
|
||||||
|
= {{EVENT_START_RISING, MODE_RRUN},
|
||||||
|
{EVENT_FSENSOR_OBSTRUCT, MODE_RRUN},
|
||||||
|
{EVENT_RSENSOR_OBSTRUCT, MODE_FRUN},
|
||||||
|
{EVENT_STOP_PUSH, MODE_CLOSING_STEP2}};
|
||||||
|
modeSwitchMap[MODE_CLOSING_STEP1]
|
||||||
|
= {{EVENT_START_RISING, MODE_CLOSING_STEP1},
|
||||||
|
{EVENT_FSENSOR_OBSTRUCT, MODE_CLOSING_STEP2},
|
||||||
|
{EVENT_RSENSOR_OBSTRUCT, MODE_STOP},
|
||||||
|
{EVENT_STOP_PUSH, MODE_CLOSING_STEP1}};
|
||||||
|
modeSwitchMap[MODE_CLOSING_STEP2]
|
||||||
|
= {{EVENT_START_RISING, MODE_CLOSING_STEP2},
|
||||||
|
{EVENT_FSENSOR_OBSTRUCT, MODE_CLOSING_STEP2},
|
||||||
|
{EVENT_RSENSOR_OBSTRUCT, MODE_STOP},
|
||||||
|
{EVENT_STOP_PUSH, MODE_CLOSING_STEP2}};
|
||||||
|
// x86 无法运行
|
||||||
|
/* wiringPiSetup();
|
||||||
|
pinMode(BTN_START, INPUT);
|
||||||
|
pinMode(BTN_DIRSWITCH, INPUT);
|
||||||
|
pinMode(BTN_STOP, INPUT);
|
||||||
|
pinMode(INPUT_FSENSOR, INPUT);
|
||||||
|
pinMode(INPUT_RSENSOR, INPUT);
|
||||||
|
pullUpDnControl(BTN_START, PUD_UP);
|
||||||
|
pullUpDnControl(BTN_DIRSWITCH, PUD_UP);
|
||||||
|
pullUpDnControl(BTN_STOP, PUD_UP);
|
||||||
|
pullUpDnControl(INPUT_FSENSOR, PUD_UP);
|
||||||
|
pullUpDnControl(INPUT_RSENSOR, PUD_UP);
|
||||||
|
pinMode(OUT_RRUN, OUTPUT);
|
||||||
|
pinMode(OUT_FRUN, OUTPUT);
|
||||||
|
digitalWrite(OUT_FRUN, OUT_OFF);
|
||||||
|
digitalWrite(OUT_RRUN, OUT_OFF); */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ConveyorBeltControlUnit::~ConveyorBeltControlUnit() {}
|
||||||
84
ConveyorBeltController/include/conveyorBeltController.hpp
Normal file
84
ConveyorBeltController/include/conveyorBeltController.hpp
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
#ifndef BELT_CONTROLLER_H_
|
||||||
|
#define BELT_CONTROLLER_H_
|
||||||
|
#include "color.h"
|
||||||
|
#include "conveyorBeltGrpcClient.hpp"
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <glog/logging.h>
|
||||||
|
#include <httplib.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <shared_mutex>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string>
|
||||||
|
#include "ability_sdk/ControllerHeartbeat.hpp"
|
||||||
|
#include "ability_sdk/Heartbeat.hpp"
|
||||||
|
|
||||||
|
//#include <json/json.h>
|
||||||
|
|
||||||
|
//#include "http_server.h"
|
||||||
|
// 前向声明 HttpServer 类,避免循环依赖
|
||||||
|
//class HttpServer;
|
||||||
|
|
||||||
|
|
||||||
|
typedef int ConveyorBeltStatus;
|
||||||
|
|
||||||
|
|
||||||
|
// 控制器类
|
||||||
|
class ConveyorBeltController {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
httplib::Server http_server;
|
||||||
|
void configure_http_server();
|
||||||
|
std::map<int, int> directionMap;
|
||||||
|
//std::map<int, std::string> ipMap;
|
||||||
|
int port;
|
||||||
|
|
||||||
|
// 控制器心跳包
|
||||||
|
ability_sdk::ControllerHeartbeat heartbeat_pack;
|
||||||
|
|
||||||
|
// 能力心跳获取
|
||||||
|
std::map<uuids::uuid, ability_sdk::Heartbeat> ability_heartbeats;
|
||||||
|
bool gather_abilities();
|
||||||
|
bool check_ability_status();
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void Run();
|
||||||
|
|
||||||
|
// 控制器心跳线程
|
||||||
|
std::thread th_heartbeat;
|
||||||
|
void routine_heartbeat();
|
||||||
|
|
||||||
|
int handleOpen(float speed, int direction);
|
||||||
|
int handleClose();
|
||||||
|
int handleCheck();
|
||||||
|
void setServerIp(std::string serverIp);
|
||||||
|
ConveyorBeltStatus getCurrentStatus();
|
||||||
|
ConveyorBeltController();
|
||||||
|
~ConveyorBeltController();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string ip;
|
||||||
|
ConveyorBeltStatus status;
|
||||||
|
std::shared_mutex mutex_;
|
||||||
|
int IPCPort;
|
||||||
|
int abilityPort;
|
||||||
|
std::map<int, std::string> ipMap;
|
||||||
|
// 状态转换
|
||||||
|
int stateSwitch(ConveyorBeltStatus destState, std::string cmd);
|
||||||
|
// grpc连接
|
||||||
|
int grpcConnect(float speed, int direction);
|
||||||
|
// grpc断开
|
||||||
|
int grpcDisconnect();
|
||||||
|
// grpc检查
|
||||||
|
int grpcCheck();
|
||||||
|
// 同步状态
|
||||||
|
int synchState(std::string json);
|
||||||
|
// 简单状态检查
|
||||||
|
bool simpleStateCheck();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
85
ConveyorBeltController/include/conveyorBeltGrpcClient.hpp
Normal file
85
ConveyorBeltController/include/conveyorBeltGrpcClient.hpp
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#ifndef CONVEYOR_BELT_GRPC_CLIENT_H_
|
||||||
|
#define CONVEYOR_BELT_GRPC_CLIENT_H_
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include "conveyorBelt.grpc.pb.h"
|
||||||
|
#include "conveyorBelt.pb.h"
|
||||||
|
#include "conveyorBeltControlUnit.h"
|
||||||
|
|
||||||
|
#include <glog/logging.h>
|
||||||
|
#include <grpc/grpc.h>
|
||||||
|
#include <grpcpp/channel.h>
|
||||||
|
#include <grpcpp/client_context.h>
|
||||||
|
#include <grpcpp/create_channel.h>
|
||||||
|
#include <grpcpp/grpcpp.h>
|
||||||
|
#include <grpcpp/security/credentials.h>
|
||||||
|
|
||||||
|
using grpc::Channel;
|
||||||
|
using grpc::ClientContext;
|
||||||
|
using grpc::ClientReader;
|
||||||
|
using grpc::ClientWriter;
|
||||||
|
using grpc::Status;
|
||||||
|
|
||||||
|
class ConveyorBeltGrpcClient {
|
||||||
|
private:
|
||||||
|
std::unique_ptr<ConveyorBelt::ConveyorBeltService::Stub> stub_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// 启动带速度和方向的传送带
|
||||||
|
int startWithSpeedAndDirection(float speed, int direction) {
|
||||||
|
LOG(INFO) << GRAY << "start connect to belt" << EMPTY;
|
||||||
|
ConveyorBelt::SpeedInfo speedInfo;
|
||||||
|
speedInfo.set_speed(speed);
|
||||||
|
ConveyorBelt::DirectionInfo directionInfo;
|
||||||
|
directionInfo.set_direction(direction);
|
||||||
|
ConveyorBelt::Response response;
|
||||||
|
ClientContext context_direction;
|
||||||
|
grpc::Status ret = stub_->setDirection(&context_direction, directionInfo, &response);
|
||||||
|
if (!ret.ok()) {
|
||||||
|
LOG(INFO) << GRAY << "grpc server cannot connect" << EMPTY;
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
if (response.code() < 0) { return -1; }
|
||||||
|
ClientContext context_start;
|
||||||
|
stub_->open(&context_start, speedInfo, &response);
|
||||||
|
if (response.code() < 0) { return -1; }
|
||||||
|
LOG(INFO) << GRAY << "finish connect to belt" << EMPTY;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭传送带
|
||||||
|
int close() {
|
||||||
|
LOG(INFO) << GRAY << "start connect to belt" << EMPTY;
|
||||||
|
ConveyorBelt::DeviceID id;
|
||||||
|
id.set_conveyorbeltid(0);
|
||||||
|
ClientContext context_close;
|
||||||
|
ConveyorBelt::Response response;
|
||||||
|
stub_->close(&context_close, id, &response);
|
||||||
|
if (response.code() < 0) { return -1; }
|
||||||
|
LOG(INFO) << GRAY << "start connect to belt" << EMPTY;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取传送带状态
|
||||||
|
int getWorkState() {
|
||||||
|
LOG(INFO) << GRAY << "start connect to belt" << EMPTY;
|
||||||
|
ConveyorBelt::DeviceID id;
|
||||||
|
id.set_conveyorbeltid(0);
|
||||||
|
ClientContext context_get;
|
||||||
|
ConveyorBelt::Response response;
|
||||||
|
stub_->getWorkState(&context_get, id, &response);
|
||||||
|
LOG(INFO) << GRAY << "start connect to belt" << EMPTY;
|
||||||
|
return response.code();
|
||||||
|
}
|
||||||
|
|
||||||
|
ConveyorBeltGrpcClient(std::shared_ptr<Channel> channel)
|
||||||
|
: stub_(ConveyorBelt::ConveyorBeltService::NewStub(channel)) {}
|
||||||
|
|
||||||
|
~ConveyorBeltGrpcClient() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
36
ConveyorBeltController/include/http_server.h.txt
Normal file
36
ConveyorBeltController/include/http_server.h.txt
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#ifndef HTTP_SERVER_H_
|
||||||
|
#define HTTP_SERVER_H_
|
||||||
|
|
||||||
|
#include <httplib.h>
|
||||||
|
#include "color.h"
|
||||||
|
#include "conveyorBeltController.hpp"
|
||||||
|
#include <glog/logging.h>
|
||||||
|
#include <json/json.h>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
class HttpServer {
|
||||||
|
public:
|
||||||
|
|
||||||
|
// 构造函数,接收 ConveyorBeltController 的引用
|
||||||
|
explicit HttpServer(ConveyorBeltController& controller);
|
||||||
|
|
||||||
|
void Init();
|
||||||
|
void Run();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// http服务器
|
||||||
|
std::shared_ptr<httplib::Server> server;
|
||||||
|
|
||||||
|
// 控制器
|
||||||
|
//std::shared_ptr<ConveyorBeltController> controller;
|
||||||
|
|
||||||
|
std::map<int, int> directionMap;
|
||||||
|
std::map<int, std::string> ipMap;
|
||||||
|
|
||||||
|
// 引用 ConveyorBeltController 实例
|
||||||
|
ConveyorBeltController& controller;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // HTTP_SERVER_H_
|
||||||
549
ConveyorBeltController/src/conveyorBeltController.cpp
Normal file
549
ConveyorBeltController/src/conveyorBeltController.cpp
Normal file
@ -0,0 +1,549 @@
|
|||||||
|
#include "conveyorBeltController.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
const ConveyorBeltStatus OFFLINE = 0;
|
||||||
|
const ConveyorBeltStatus READY = 1;
|
||||||
|
const ConveyorBeltStatus RUNNING = 2;
|
||||||
|
|
||||||
|
ConveyorBeltController::ConveyorBeltController(/* args */) {}
|
||||||
|
ConveyorBeltController::~ConveyorBeltController() {
|
||||||
|
if (th_heartbeat.joinable()) {
|
||||||
|
th_heartbeat.join(); // 等待线程结束
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 配置http服务器
|
||||||
|
void ConveyorBeltController::configure_http_server(){
|
||||||
|
FLAGS_logtostderr = 1;
|
||||||
|
LOG(INFO) << L_GREEN << "init http server" << EMPTY;
|
||||||
|
|
||||||
|
ipMap[108] = "192.168.1.217";
|
||||||
|
ipMap[109] = "192.168.1.218";
|
||||||
|
directionMap[108] = 0;
|
||||||
|
directionMap[109] = 0;
|
||||||
|
|
||||||
|
// GET 请求 /api/processGet 处理函数,通过id参数获取状态
|
||||||
|
http_server.Get(
|
||||||
|
"/api/processGet",
|
||||||
|
[this](const httplib::Request& req, httplib::Response& res) {
|
||||||
|
LOG(INFO) << L_BLUE << "httpserver receive: method: GET URL: /api/processGet"
|
||||||
|
<< EMPTY;
|
||||||
|
std::string conveyorBeltId;
|
||||||
|
int result = 200;
|
||||||
|
//Json::Value response;
|
||||||
|
nlohmann::json response;
|
||||||
|
try {
|
||||||
|
conveyorBeltId = req.get_param_value("id");
|
||||||
|
LOG(INFO) << YELLOW << "GET param id:" << conveyorBeltId << EMPTY;
|
||||||
|
}
|
||||||
|
catch (const std::exception&) {
|
||||||
|
res.status = 400; // Bad Request
|
||||||
|
response["status"] = 400;
|
||||||
|
response["processStatus"] = this->getCurrentStatus();
|
||||||
|
res.set_content(response.dump(4), "application/json");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::map<int, std::string>::iterator it = ipMap.find(std::stoi(conveyorBeltId));
|
||||||
|
if (it != ipMap.end()) { this->setServerIp(it->second); }
|
||||||
|
else {
|
||||||
|
response["status"] = 400;
|
||||||
|
response["processStatus"] = this->getCurrentStatus();
|
||||||
|
res.set_content(response.dump(4), "application/json");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this->handleCheck() < 0) { result = 400; }
|
||||||
|
|
||||||
|
// status = 200
|
||||||
|
response["status"] = result;
|
||||||
|
response["processStatus"] = this->getCurrentStatus();
|
||||||
|
res.set_content(response.dump(4), "application/json");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// POST 请求 /api/processPost 处理函数
|
||||||
|
http_server.Post(
|
||||||
|
"/api/processPost",
|
||||||
|
[this](const httplib::Request& req, httplib::Response& res) {
|
||||||
|
LOG(INFO) << L_BLUE << "httpserver receive: method: POST URL: /api/processPost"
|
||||||
|
<< EMPTY;
|
||||||
|
LOG(INFO) << YELLOW << req.get_header_value("Content-Type") << EMPTY;
|
||||||
|
//Json::Value root;
|
||||||
|
nlohmann::json root;
|
||||||
|
int status = 200;
|
||||||
|
if (req.get_header_value("Content-Type").find("application/json")!= std::string::npos) {
|
||||||
|
//Json::Reader reader;
|
||||||
|
/* nlohmann::json reader;
|
||||||
|
bool success = reader.parse(req.body, root);
|
||||||
|
if (!success) {
|
||||||
|
LOG(ERROR) << "json parse error";
|
||||||
|
res.status = 400;
|
||||||
|
status = 400;
|
||||||
|
} */
|
||||||
|
|
||||||
|
try {
|
||||||
|
root = nlohmann::json::parse(req.body); // 使用静态方法解析 JSON
|
||||||
|
} catch (const nlohmann::json::parse_error& e) {
|
||||||
|
// json解析错误
|
||||||
|
LOG(ERROR) << "json parse error: " << e.what();
|
||||||
|
res.status = 400;
|
||||||
|
status = 400;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 以下缩进需要调整
|
||||||
|
//else {
|
||||||
|
LOG(INFO) << YELLOW << "id:" << root["id"].get<int>()
|
||||||
|
<< " action:" << root["action"].get<int>()
|
||||||
|
<< " speed:" << root["speed"].get<int>() << EMPTY;
|
||||||
|
//Json::Value result;
|
||||||
|
nlohmann::json result;
|
||||||
|
std::map<int, std::string>::iterator it = ipMap.find(root["id"].get<int>());
|
||||||
|
|
||||||
|
// 根据传送带id,检查该id是否存在于ipMap中
|
||||||
|
// it->first 为传送带id
|
||||||
|
// it->second 为传送带对应的ip地址
|
||||||
|
if (it != ipMap.end()) { this->setServerIp(it->second); }
|
||||||
|
else {
|
||||||
|
result["status"] = 400;
|
||||||
|
result["processStatus"] = this->getCurrentStatus();
|
||||||
|
res.set_content(result.dump(4), "application/json");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 启动
|
||||||
|
if (root["action"].get<int>() == 1) {
|
||||||
|
LOG(INFO) << YELLOW << "http server try to handle open" << EMPTY;
|
||||||
|
std::thread openThread(
|
||||||
|
&ConveyorBeltController::handleOpen,
|
||||||
|
this,
|
||||||
|
root["speed"].get<int>(),
|
||||||
|
directionMap[root["id"].get<int>()]
|
||||||
|
);
|
||||||
|
openThread.detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭
|
||||||
|
else if (root["action"].get<int>() == 0) {
|
||||||
|
LOG(INFO) << YELLOW << "http server try to handle close" << EMPTY;
|
||||||
|
std::thread closeThread(
|
||||||
|
&ConveyorBeltController::handleClose, this
|
||||||
|
);
|
||||||
|
closeThread.detach();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG(INFO) << YELLOW << "invalid action code" << EMPTY;
|
||||||
|
status = 400;
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
else { status = 400; }
|
||||||
|
//Json::Value result;
|
||||||
|
nlohmann::json result;
|
||||||
|
result["status"] = status;
|
||||||
|
result["processStatus"] = this->getCurrentStatus();
|
||||||
|
res.set_content(result.dump(4), "application/json");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 设置服务器ip
|
||||||
|
void ConveyorBeltController::setServerIp(std::string conveyorBeltIp) {
|
||||||
|
this->ip = conveyorBeltIp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
void ConveyorBeltController::init() {
|
||||||
|
|
||||||
|
std::unique_lock<std::shared_mutex> w_lock(mutex_);
|
||||||
|
LOG(INFO) << WHITE << "init controller state" << EMPTY;
|
||||||
|
status = OFFLINE;
|
||||||
|
abilityPort = 0;
|
||||||
|
IPCPort = 0;
|
||||||
|
//configure_http_server();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
void send_one_heartbeat(const ability_sdk::ControllerHeartbeat& heartbeat_pack) {
|
||||||
|
try {
|
||||||
|
httplib::Client cli("127.0.0.1", 8080); // 连接到框架
|
||||||
|
// 生成 JSON 格式的心跳包
|
||||||
|
nlohmann::json hb_json;
|
||||||
|
try {
|
||||||
|
hb_json = nlohmann::json(heartbeat_pack);
|
||||||
|
//LOG(INFO) << "heartbeat_pack to json success";
|
||||||
|
} catch (const nlohmann::json::exception& e) {
|
||||||
|
LOG(ERROR) << "JSON serialization error: " << e.what();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto post_res = cli.Post("/api/controller-heartbeat", hb_json.dump(2), "application/json");
|
||||||
|
if (!post_res) {
|
||||||
|
LOG(ERROR) << "failed to connect to framework: " << post_res.error();
|
||||||
|
} else if (post_res->status != 200) {
|
||||||
|
LOG(ERROR) << "failed to connect to framework: " << post_res->body;
|
||||||
|
}
|
||||||
|
LOG(INFO) << "send one heartbeat success";
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
LOG(ERROR) << "Exception in send_one_heartbeat: " << e.what();
|
||||||
|
} catch (...) {
|
||||||
|
LOG(ERROR) << "Unknown exception in send_one_heartbeat";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
|
// 心跳包
|
||||||
|
void ConveyorBeltController::routine_heartbeat() {
|
||||||
|
LOG(INFO) << "start heart beat routine";
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
send_one_heartbeat(heartbeat_pack);
|
||||||
|
//gather_abilities();
|
||||||
|
//check_ability_status();
|
||||||
|
}catch (const std::exception& e) {
|
||||||
|
LOG(ERROR) << "Exception in routine_heartbeat: " << e.what();
|
||||||
|
} catch (...) {
|
||||||
|
LOG(ERROR) << "Unknown exception in routine_heartbeat";
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConveyorBeltController::Run() {
|
||||||
|
|
||||||
|
//http_server.Init();
|
||||||
|
//http_server.Run();
|
||||||
|
LOG(INFO) << "ConveyorBeltController::Run()";
|
||||||
|
|
||||||
|
configure_http_server();
|
||||||
|
port = http_server.bind_to_any_port("0.0.0.0");
|
||||||
|
CHECK_GE(port, 0) << "http server bind port failed";
|
||||||
|
LOG(WARNING) << "http server listen on: " << port;
|
||||||
|
// 设置心跳包中的端口
|
||||||
|
this->heartbeat_pack.port = port;
|
||||||
|
|
||||||
|
// 启动心跳包线程
|
||||||
|
this->th_heartbeat = std::thread(&ConveyorBeltController::routine_heartbeat, this);
|
||||||
|
// 启动http服务器
|
||||||
|
http_server.listen_after_bind();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool ConveyorBeltController::gather_abilities() {
|
||||||
|
httplib::Client cli{"localhost", 8080};
|
||||||
|
auto get_res = cli.Get("/api/ability-heartbeat");
|
||||||
|
if (!get_res) {
|
||||||
|
LOG(ERROR) << "failed to update ability info: failed to connect to framework";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (get_res.value().status != 200) {
|
||||||
|
LOG(ERROR) << "failed to gather ability information: " << get_res.value().body;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto json_arr_res = nlohmann::json::parse(get_res->body);
|
||||||
|
DLOG(INFO) << "get ablility info:" << json_arr_res;
|
||||||
|
if (json_arr_res.is_null() || (!json_arr_res.is_array())) {
|
||||||
|
DLOG(INFO) << "ability info is null, return";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::lock_guard _lk(m);
|
||||||
|
DLOG(INFO) << "iterating ablility info: " << json_arr_res.dump();
|
||||||
|
for (int i = 0; i < json_arr_res.size(); ++i) {
|
||||||
|
auto sub_json = json_arr_res.at(i);
|
||||||
|
if (!sub_json.is_object()) { continue; }
|
||||||
|
try {
|
||||||
|
auto entry = sub_json.get<ability_sdk::Heartbeat>();
|
||||||
|
if (entry.abilityName != ABILITY_NAME) { continue; }
|
||||||
|
DLOG(INFO) << "update ablility " << entry.id << " with "
|
||||||
|
<< nlohmann::json(entry).dump();
|
||||||
|
ability_heartbeats[entry.id] = entry;
|
||||||
|
}
|
||||||
|
catch (nlohmann::json::exception& e) {
|
||||||
|
LOG(ERROR) << "invalid heartbeat info: " << e.what() << "\n" << sub_json.dump(2);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int ConveyorBeltController::handleCheck() {
|
||||||
|
std::unique_lock<std::shared_mutex> w_lock(mutex_);
|
||||||
|
if (simpleStateCheck()) { return 0; }
|
||||||
|
else { return -1; }
|
||||||
|
}
|
||||||
|
// 获取当前状态,并且根据gRPC检查状态
|
||||||
|
int ConveyorBeltController::getCurrentStatus() {
|
||||||
|
std::shared_lock<std::shared_mutex> r_lock(mutex_);
|
||||||
|
if (status == RUNNING) {
|
||||||
|
if (grpcCheck() < 0) { return READY; }
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConveyorBeltController::handleOpen(float speed, int direction) {
|
||||||
|
std::unique_lock<std::shared_mutex> w_lock(mutex_);
|
||||||
|
int result = 0;
|
||||||
|
if (simpleStateCheck() == false) { return -1; }
|
||||||
|
switch (status) {
|
||||||
|
case RUNNING:
|
||||||
|
if (grpcCheck() < 0) {
|
||||||
|
result = grpcConnect(speed, direction);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
LOG(INFO) << WHITE << "ConveyorBelt is already running, do not open twice" << EMPTY;
|
||||||
|
break;
|
||||||
|
case READY:
|
||||||
|
LOG(INFO) << WHITE << "ConveyorBelt is ready, start handle open request" << EMPTY;
|
||||||
|
result = stateSwitch(RUNNING, "connect");
|
||||||
|
if (result < 0) { break; }
|
||||||
|
result = grpcConnect(speed, direction);
|
||||||
|
break;
|
||||||
|
case OFFLINE:
|
||||||
|
LOG(INFO) << WHITE << "ConveyorBelt is offline, start handle open request" << EMPTY;
|
||||||
|
result = stateSwitch(READY, "start");
|
||||||
|
if (result < 0) { break; }
|
||||||
|
result = stateSwitch(RUNNING, "connect");
|
||||||
|
if (result < 0) { break; }
|
||||||
|
result = grpcConnect(speed, direction);
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConveyorBeltController::handleClose() {
|
||||||
|
std::unique_lock<std::shared_mutex> w_lock(mutex_);
|
||||||
|
int result = 0;
|
||||||
|
if (simpleStateCheck() == false) { return -1; }
|
||||||
|
switch (status) {
|
||||||
|
case READY:
|
||||||
|
case OFFLINE:
|
||||||
|
LOG(INFO) << WHITE << "ConveyorBelt has not been opened, do not close twice" << EMPTY;
|
||||||
|
break;
|
||||||
|
case RUNNING:
|
||||||
|
LOG(INFO) << WHITE << "ConveyorBelt is now running, start handle ConveyorBelt close"
|
||||||
|
<< EMPTY;
|
||||||
|
result = grpcDisconnect();
|
||||||
|
if (result < 0) { break; }
|
||||||
|
result = stateSwitch(READY, "disconnect");
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConveyorBeltController::simpleStateCheck() {
|
||||||
|
LOG(INFO) << WHITE << "start simple check" << EMPTY;
|
||||||
|
httplib::Client client(ip, 8080);
|
||||||
|
int mStatus;
|
||||||
|
auto res = client.Get("/api/AbilityRunning");
|
||||||
|
if (res) {
|
||||||
|
LOG(INFO) << WHITE << "GET response:" << res->status << EMPTY;
|
||||||
|
mStatus = synchState(res->body);
|
||||||
|
if (mStatus == status) {
|
||||||
|
LOG(INFO) << WHITE
|
||||||
|
<< "simple check pass current status is correct with abilityFrameWork"
|
||||||
|
<< EMPTY;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG(INFO) << WHITE << "simple check failed incorrect state" << EMPTY;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG(ERROR) << "FIRST STEP: can not connect with abilityFrameWork" << EMPTY;
|
||||||
|
LOG(INFO) << WHITE << "now ConveyorBelt is OFFLINE" << EMPTY;
|
||||||
|
status = OFFLINE;
|
||||||
|
abilityPort = 0;
|
||||||
|
IPCPort = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ConveyorBeltController::synchState(std::string json) {
|
||||||
|
nlohmann::json states;
|
||||||
|
try {
|
||||||
|
states = nlohmann::json::parse(json); // 使用 nlohmann::json 解析 JSON 字符串
|
||||||
|
for (const auto& state : states) { // 遍历 JSON 数组
|
||||||
|
LOG(INFO) << WHITE << "IPCPort:" << state["IPCPort"].get<std::string>()
|
||||||
|
<< " abilityName:" << state["abilityName"].get<std::string>()
|
||||||
|
<< " status:" << state["status"].get<std::string>() << EMPTY;
|
||||||
|
|
||||||
|
if (state["IPCPort"].get<int>() == IPCPort ||
|
||||||
|
(IPCPort == 0 && state["abilityName"].get<std::string>() == "conveyorBelt")) {
|
||||||
|
if (state["status"].get<std::string>() == "RUNNING") {
|
||||||
|
LOG(INFO) << WHITE << "now ConveyorBelt is RUNNING" << EMPTY;
|
||||||
|
status = RUNNING;
|
||||||
|
IPCPort = state["IPCPort"].get<int>();
|
||||||
|
abilityPort = state["abilityPort"].get<int>();
|
||||||
|
if (abilityPort == 0) {
|
||||||
|
return READY;
|
||||||
|
} else {
|
||||||
|
return RUNNING;
|
||||||
|
}
|
||||||
|
} else if (state["status"].get<std::string>() == "STANDBY" ||
|
||||||
|
state["status"].get<std::string>() == "SUSPEND") {
|
||||||
|
LOG(INFO) << WHITE << "now ConveyorBelt is READY" << EMPTY;
|
||||||
|
status = READY;
|
||||||
|
IPCPort = state["IPCPort"].get<int>();
|
||||||
|
abilityPort = 0;
|
||||||
|
return READY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (const nlohmann::json::parse_error& e) {
|
||||||
|
LOG(ERROR) << "JSON parse error: " << e.what();
|
||||||
|
// 如果解析失败,返回 OFFLINE 状态
|
||||||
|
status = OFFLINE;
|
||||||
|
abilityPort = 0;
|
||||||
|
IPCPort = 0;
|
||||||
|
return OFFLINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有匹配的状态,设置为 OFFLINE
|
||||||
|
LOG(INFO) << WHITE << "now ConveyorBelt is OFFLINE" << EMPTY;
|
||||||
|
status = OFFLINE;
|
||||||
|
abilityPort = 0;
|
||||||
|
IPCPort = 0;
|
||||||
|
return OFFLINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* int ConveyorBeltController::synchState(std::string json) {
|
||||||
|
Json::Reader reader;
|
||||||
|
Json::Value states;
|
||||||
|
if (reader.parse(json, states)) {
|
||||||
|
for (int i = 0; i < states.size(); i++) {
|
||||||
|
LOG(INFO) << WHITE << "IPCPort:" << states[i]["IPCPort"].asString()
|
||||||
|
<< " abilityName:" << states[i]["abilityName"].asString() << "status"
|
||||||
|
<< states[i]["status"].asString() << EMPTY;
|
||||||
|
if (states[i]["IPCPort"].asInt() == IPCPort
|
||||||
|
|| (IPCPort == 0 && states[i]["abilityName"].asString().compare("conveyorBelt") == 0
|
||||||
|
)) {
|
||||||
|
if (states[i]["status"].asString() == "RUNNING") {
|
||||||
|
// std::unique_lock<std::shared_mutex> w_lock(mutex_);
|
||||||
|
LOG(INFO) << WHITE << "now ConveyorBelt is RUNNING" << EMPTY;
|
||||||
|
status = RUNNING;
|
||||||
|
IPCPort = states[i]["IPCPort"].asInt();
|
||||||
|
abilityPort = states[i]["abilityPort"].asInt();
|
||||||
|
if (abilityPort == 0) { return READY; }
|
||||||
|
else { return RUNNING; }
|
||||||
|
}
|
||||||
|
else if (states[i]["status"].asString() == "STANDBY"
|
||||||
|
|| states[i]["status"].asString() == "SUSPEND") {
|
||||||
|
// std::unique_lock<std::shared_mutex> w_lock(mutex_);
|
||||||
|
LOG(INFO) << WHITE << "now ConveyorBelt is READY" << EMPTY;
|
||||||
|
status = READY;
|
||||||
|
IPCPort = states[i]["IPCPort"].asInt();
|
||||||
|
abilityPort = 0;
|
||||||
|
// w_lock.unlock();
|
||||||
|
return READY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// std::unique_lock<std::shared_mutex> w_lock(mutex_);
|
||||||
|
LOG(INFO) << WHITE << "now ConveyorBelt is OFFLINE" << EMPTY;
|
||||||
|
status = OFFLINE;
|
||||||
|
abilityPort = 0;
|
||||||
|
IPCPort = 0;
|
||||||
|
// w_lock.unlock();
|
||||||
|
return OFFLINE;
|
||||||
|
} */
|
||||||
|
|
||||||
|
|
||||||
|
int ConveyorBeltController::stateSwitch(ConveyorBeltStatus destState, std::string cmd) {
|
||||||
|
httplib::Client client(ip, 8080);
|
||||||
|
httplib::Params params;
|
||||||
|
ConveyorBeltStatus mStatus;
|
||||||
|
// 发出请求
|
||||||
|
params.emplace("abilityName", "conveyorBelt");
|
||||||
|
params.emplace("IPCPort", std::to_string(IPCPort));
|
||||||
|
params.emplace("cmd", cmd);
|
||||||
|
params.emplace("connectIP", "0.0.0.0");
|
||||||
|
params.emplace("connectPort", "0");
|
||||||
|
auto res = client.Post("/api/AbilityRequest", params);
|
||||||
|
if (res) { LOG(INFO) << WHITE << "POST response:" << res->status << EMPTY; }
|
||||||
|
else {
|
||||||
|
LOG(ERROR) << "SECOND STEP: can not connect with abilityFrameWork" << EMPTY;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
params.clear();
|
||||||
|
// 查询当前状态
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
res = client.Get("/api/AbilityRunning");
|
||||||
|
if (res) {
|
||||||
|
LOG(INFO) << WHITE << "GET response:" << res->status << EMPTY;
|
||||||
|
mStatus = synchState(res->body);
|
||||||
|
if (mStatus == destState) {
|
||||||
|
LOG(INFO) << WHITE << "switch state success" << EMPTY;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG(ERROR) << "THIRD STEP: can not connect with abilityFrameWork" << EMPTY;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||||
|
}
|
||||||
|
LOG(ERROR) << "ability state change failed" << EMPTY;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConveyorBeltController::grpcConnect(float speed, int direction) {
|
||||||
|
if (abilityPort == 0) { return -1; }
|
||||||
|
|
||||||
|
std::string url;
|
||||||
|
url.append(ip);
|
||||||
|
url.append(":");
|
||||||
|
url.append(std::to_string(abilityPort));
|
||||||
|
LOG(INFO) << WHITE << url << EMPTY;
|
||||||
|
int result;
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
ConveyorBeltGrpcClient client(grpc::CreateChannel(url, grpc::InsecureChannelCredentials()));
|
||||||
|
result = client.startWithSpeedAndDirection(speed, direction);
|
||||||
|
if (result != -2) { break; }
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConveyorBeltController::grpcDisconnect() {
|
||||||
|
if (abilityPort == 0) { return -1; }
|
||||||
|
std::string url;
|
||||||
|
url.append(ip);
|
||||||
|
url.append(":");
|
||||||
|
url.append(std::to_string(abilityPort));
|
||||||
|
LOG(INFO) << WHITE << url << EMPTY;
|
||||||
|
ConveyorBeltGrpcClient client(grpc::CreateChannel(url, grpc::InsecureChannelCredentials()));
|
||||||
|
if (client.close() == -1) {
|
||||||
|
LOG(ERROR) << "grpc call failed" << EMPTY;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConveyorBeltController::grpcCheck() {
|
||||||
|
if (abilityPort == 0) { return -1; }
|
||||||
|
std::string url;
|
||||||
|
url.append(ip);
|
||||||
|
url.append(":");
|
||||||
|
url.append(std::to_string(abilityPort));
|
||||||
|
LOG(INFO) << WHITE << url << EMPTY;
|
||||||
|
ConveyorBeltGrpcClient client(grpc::CreateChannel(url, grpc::InsecureChannelCredentials()));
|
||||||
|
if (client.getWorkState() == -1) {
|
||||||
|
LOG(ERROR) << "grpc work state is false" << EMPTY;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
123
ConveyorBeltController/src/http_server.cpp.txt
Normal file
123
ConveyorBeltController/src/http_server.cpp.txt
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
#include "http_server.h"
|
||||||
|
|
||||||
|
HttpServer::HttpServer(ConveyorBeltController& controller)
|
||||||
|
: controller(controller) {} // 初始化引用
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void HttpServer::Init() {
|
||||||
|
FLAGS_logtostderr = 1;
|
||||||
|
LOG(INFO) << L_GREEN << "init http server" << EMPTY;
|
||||||
|
// 初始化 http 服务器
|
||||||
|
this->server = std::make_shared<httplib::Server>();
|
||||||
|
|
||||||
|
// 初始化控制器
|
||||||
|
//this->controller = std::make_shared<ConveyorBeltController>();
|
||||||
|
// 初始化控制器
|
||||||
|
//this->controller->init();
|
||||||
|
|
||||||
|
ipMap[108] = "192.168.1.217";
|
||||||
|
ipMap[109] = "192.168.1.218";
|
||||||
|
directionMap[108] = 0;
|
||||||
|
directionMap[109] = 0;
|
||||||
|
|
||||||
|
this->server->Get(
|
||||||
|
"/api/processGet",
|
||||||
|
[this](const httplib::Request& req, httplib::Response& res) {
|
||||||
|
LOG(INFO) << L_BLUE << "httpserver receive: method: GET URL: /api/processGet"
|
||||||
|
<< EMPTY;
|
||||||
|
std::string conveyorBeltId;
|
||||||
|
int result = 200;
|
||||||
|
Json::Value response;
|
||||||
|
try {
|
||||||
|
conveyorBeltId = req.get_param_value("id");
|
||||||
|
LOG(INFO) << YELLOW << "GET param id:" << conveyorBeltId << EMPTY;
|
||||||
|
}
|
||||||
|
catch (const std::exception&) {
|
||||||
|
res.status = 400; // Bad Request
|
||||||
|
response["status"] = 400;
|
||||||
|
response["processStatus"] = this->controller.getCurrentStatus();
|
||||||
|
res.set_content(response.toStyledString(), "application/json");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::map<int, std::string>::iterator it = ipMap.find(std::stoi(conveyorBeltId));
|
||||||
|
if (it != ipMap.end()) { this->controller.setServerIp(it->second); }
|
||||||
|
else {
|
||||||
|
response["status"] = 400;
|
||||||
|
response["processStatus"] = this->controller.getCurrentStatus();
|
||||||
|
res.set_content(response.toStyledString(), "application/json");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this->controller.handleCheck() < 0) { result = 400; }
|
||||||
|
response["status"] = result;
|
||||||
|
response["processStatus"] = this->controller.getCurrentStatus();
|
||||||
|
res.set_content(response.toStyledString(), "application/json");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
this->server->Post(
|
||||||
|
"/api/processPost",
|
||||||
|
[this](const httplib::Request& req, httplib::Response& res) {
|
||||||
|
LOG(INFO) << L_BLUE << "httpserver receive: method: POST URL: /api/processPost"
|
||||||
|
<< EMPTY;
|
||||||
|
LOG(INFO) << YELLOW << req.get_header_value("Content-Type") << EMPTY;
|
||||||
|
Json::Value root;
|
||||||
|
int status = 200;
|
||||||
|
if (req.get_header_value("Content-Type").find("application/json")
|
||||||
|
!= std::string::npos) {
|
||||||
|
Json::Reader reader;
|
||||||
|
bool success = reader.parse(req.body, root);
|
||||||
|
if (!success) {
|
||||||
|
LOG(ERROR) << "json parse error";
|
||||||
|
res.status = 400;
|
||||||
|
status = 400;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG(INFO) << YELLOW << "id:" << root["id"].asInt()
|
||||||
|
<< " action:" << root["action"].asInt()
|
||||||
|
<< " speed:" << root["speed"].asFloat() << EMPTY;
|
||||||
|
Json::Value result;
|
||||||
|
std::map<int, std::string>::iterator it = ipMap.find(root["id"].asInt());
|
||||||
|
if (it != ipMap.end()) { this->controller.setServerIp(it->second); }
|
||||||
|
else {
|
||||||
|
result["status"] = 400;
|
||||||
|
result["processStatus"] = this->controller.getCurrentStatus();
|
||||||
|
res.set_content(result.toStyledString(), "application/json");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (root["action"].asInt() == 1) {
|
||||||
|
LOG(INFO) << YELLOW << "http server try to handle open" << EMPTY;
|
||||||
|
std::thread openThread(
|
||||||
|
&ConveyorBeltController::handleOpen,
|
||||||
|
this->controller,
|
||||||
|
root["speed"].asFloat(),
|
||||||
|
directionMap[root["id"].asInt()]
|
||||||
|
);
|
||||||
|
openThread.detach();
|
||||||
|
}
|
||||||
|
else if (root["action"].asInt() == 0) {
|
||||||
|
LOG(INFO) << YELLOW << "http server try to handle close" << EMPTY;
|
||||||
|
std::thread closeThread(
|
||||||
|
&ConveyorBeltController::handleClose, this->controller
|
||||||
|
);
|
||||||
|
closeThread.detach();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG(INFO) << YELLOW << "invalid action code" << EMPTY;
|
||||||
|
status = 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { status = 400; }
|
||||||
|
Json::Value result;
|
||||||
|
result["status"] = status;
|
||||||
|
result["processStatus"] = this->controller.getCurrentStatus();
|
||||||
|
res.set_content(result.toStyledString(), "application/json");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpServer::Run() {
|
||||||
|
LOG(INFO) << L_GREEN << "http server start" << EMPTY;
|
||||||
|
this->server->listen("0.0.0.0", 8001);
|
||||||
|
}
|
||||||
48
ConveyorBeltController/src/main.cpp
Normal file
48
ConveyorBeltController/src/main.cpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#include "conveyorBeltController.hpp"
|
||||||
|
#include "ability_sdk/AbilityStub.hpp"
|
||||||
|
#include "ability_sdk/util/parse_cmd.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char const* argv[]) {
|
||||||
|
// 初始化glog
|
||||||
|
ability_sdk::configure_glog(argv[0]);
|
||||||
|
|
||||||
|
ability_sdk::CmdInfo cmd(argc, argv);
|
||||||
|
ConveyorBeltController controller;
|
||||||
|
|
||||||
|
// 配置心跳包
|
||||||
|
controller.heartbeat_pack.controllerInstanceId = uuids::to_string(cmd.instance_id);
|
||||||
|
controller.heartbeat_pack.abilityName = "ConveyorBelt";
|
||||||
|
controller.heartbeat_pack.package = "ConveyorBelt.test.org";
|
||||||
|
controller.heartbeat_pack.protocol = "http";
|
||||||
|
controller.heartbeat_pack.version = "0.1.0";
|
||||||
|
|
||||||
|
controller.Run();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* struct ControllerHeartbeat {
|
||||||
|
int port; // 控制器基础服务器对应的端口
|
||||||
|
std::string controllerInstanceId; // 控制器的实例id 能力的类id
|
||||||
|
std::string package; // 控制器所对应能力的包名称
|
||||||
|
std::string version; // 控制器所对应能力的版本名
|
||||||
|
std::string abilityName; // 控制器所对应能力的类型名
|
||||||
|
std::string protocol; // 控制器所使用的协议
|
||||||
|
NLOHMANN_DEFINE_TYPE_INTRUSIVE(
|
||||||
|
ControllerHeartbeat, port, controllerInstanceId, package, version, abilityName, protocol
|
||||||
|
);
|
||||||
|
}; */
|
||||||
|
|
||||||
|
|
||||||
|
/* #include "http_server.h"
|
||||||
|
|
||||||
|
// 控制器在http服务器中启动
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
google::InitGoogleLogging(argv[0]);
|
||||||
|
HttpServer server;
|
||||||
|
server.Init();
|
||||||
|
server.Run();
|
||||||
|
} */
|
||||||
|
|
||||||
|
|
||||||
32
package-index.lua
Normal file
32
package-index.lua
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package("wiringPi")
|
||||||
|
add_urls("https://github.com/WiringPi/WiringPi/archive/refs/tags/$(version).tar.gz")
|
||||||
|
add_versions("3.14","71d8b4c3bc967cf77ac15fad38791e9976cded31798715cdd3abbf8cca5cd401")
|
||||||
|
if is_plat("linux") then
|
||||||
|
add_extsources("apt::wiringpi")
|
||||||
|
end
|
||||||
|
on_install(function(package)
|
||||||
|
io.writefile(
|
||||||
|
"xmake.lua",
|
||||||
|
[[add_rules("mode.debug", "mode.release")
|
||||||
|
target("wiringPi")
|
||||||
|
set_kind("static")
|
||||||
|
add_files("wiringPi/*.c")
|
||||||
|
add_headerfiles("wiringPi/wiringPi.h")
|
||||||
|
add_includedirs("wiringPi")
|
||||||
|
]])
|
||||||
|
import("package.tools.xmake").install(package)
|
||||||
|
end)
|
||||||
|
package_end()
|
||||||
|
|
||||||
|
package("my-libmodbus")
|
||||||
|
set_base("libmodbus")
|
||||||
|
on_install(function(package)
|
||||||
|
local configs = {"--disable-tests"};
|
||||||
|
if not package:config("shared") then
|
||||||
|
table.insert(configs,"--enable-static=yes")
|
||||||
|
table.insert(configs,"--enable-shared=no")
|
||||||
|
end
|
||||||
|
import("package.tools.autoconf").install(package,configs)
|
||||||
|
end)
|
||||||
|
package_end()
|
||||||
|
|
||||||
35
protos/abilityProto.proto
Normal file
35
protos/abilityProto.proto
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
package abilityUnit;
|
||||||
|
option java_package = "ability.proto";
|
||||||
|
option java_outer_classname = "AbilityProto";
|
||||||
|
option java_multiple_files = true;
|
||||||
|
|
||||||
|
service Ability{
|
||||||
|
rpc Start(StartInfo) returns (Response){}
|
||||||
|
rpc Connect (ConnectInfo) returns (Response) {}
|
||||||
|
rpc Disconnect(DisconnectInfo) returns (Response){}
|
||||||
|
rpc Terminate(TerminateInfo) returns (Response){}
|
||||||
|
}
|
||||||
|
|
||||||
|
message Response{
|
||||||
|
int32 code = 1;
|
||||||
|
string msg = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message StartInfo{
|
||||||
|
int32 timestamp = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ConnectInfo{
|
||||||
|
string ip = 1;
|
||||||
|
int32 port = 2;
|
||||||
|
int32 timestamp = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DisconnectInfo{
|
||||||
|
int32 timestamp = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TerminateInfo{
|
||||||
|
int32 timestamp = 1;
|
||||||
|
}
|
||||||
29
protos/conveyorBelt.proto
Normal file
29
protos/conveyorBelt.proto
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
package ConveyorBelt;
|
||||||
|
option java_multiple_files = true;
|
||||||
|
option java_package = "ConveyorBelt.proto";
|
||||||
|
|
||||||
|
service ConveyorBeltService {
|
||||||
|
rpc open(SpeedInfo) returns (Response) {}
|
||||||
|
rpc close(DeviceID) returns (Response) {}
|
||||||
|
rpc setSpeed(SpeedInfo) returns (Response) {}
|
||||||
|
rpc setDirection(DirectionInfo) returns (Response) {}
|
||||||
|
rpc getWorkState(DeviceID) returns (Response) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
message Response{
|
||||||
|
int32 code = 1;
|
||||||
|
string msg = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SpeedInfo{
|
||||||
|
float speed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DeviceID{
|
||||||
|
int32 conveyorBeltId = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DirectionInfo{
|
||||||
|
int32 direction = 1;
|
||||||
|
}
|
||||||
13
protos/makefile
Normal file
13
protos/makefile
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
all: abilityProto.grpc.pb.cc abilityProto.grpc.pb.h conveyorBelt.grpc.pb.cc conveyorBelt.grpc.pb.h abilityProto.pb.cc abilityProto.pb.h conveyorBelt.pb.cc conveyorBelt.pb.h
|
||||||
|
abilityProto.grpc.pb.cc abilityProto.grpc.pb.h:
|
||||||
|
protoc -I . --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` abilityProto.proto
|
||||||
|
conveyorBelt.grpc.pb.cc conveyorBelt.grpc.pb.h:
|
||||||
|
protoc -I . --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` conveyorBelt.proto
|
||||||
|
|
||||||
|
abilityProto.pb.cc abilityProto.pb.h:
|
||||||
|
protoc -I . --cpp_out=. abilityProto.proto
|
||||||
|
conveyorBelt.pb.cc conveyorBelt.pb.h:
|
||||||
|
protoc -I . --cpp_out=. conveyorBelt.proto
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm abilityProto.grpc.pb.cc abilityProto.grpc.pb.h conveyorBelt.grpc.pb.cc conveyorBelt.grpc.pb.h abilityProto.pb.cc abilityProto.pb.h conveyorBelt.pb.cc conveyorBelt.pb.h
|
||||||
51
test/test-controller-api.py
Normal file
51
test/test-controller-api.py
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import requests
|
||||||
|
import json
|
||||||
|
|
||||||
|
# 设置服务器地址和端口
|
||||||
|
BASE_URL = "http://127.0.0.1:1"
|
||||||
|
|
||||||
|
def test_process_get(conveyor_belt_id):
|
||||||
|
"""
|
||||||
|
测试 /api/processGet 接口
|
||||||
|
"""
|
||||||
|
url = f"{BASE_URL}/api/processGet"
|
||||||
|
params = {"id": conveyor_belt_id}
|
||||||
|
print(f"Testing GET {url} with params: {params}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.get(url, params=params)
|
||||||
|
print(f"Response Status Code: {response.status_code}")
|
||||||
|
print(f"Response Body: {response.json()}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error during GET request: {e}")
|
||||||
|
|
||||||
|
def test_process_post(conveyor_belt_id, action, speed):
|
||||||
|
"""
|
||||||
|
测试 /api/processPost 接口
|
||||||
|
"""
|
||||||
|
url = f"{BASE_URL}/api/processPost"
|
||||||
|
headers = {"Content-Type": "application/json"}
|
||||||
|
payload = {
|
||||||
|
"id": conveyor_belt_id,
|
||||||
|
"action": action,
|
||||||
|
"speed": speed
|
||||||
|
}
|
||||||
|
print(f"Testing POST {url} with payload: {json.dumps(payload, indent=4)}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.post(url, headers=headers, json=payload)
|
||||||
|
print(f"Response Status Code: {response.status_code}")
|
||||||
|
print(f"Response Body: {response.json()}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error during POST request: {e}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# 测试 /api/processGet
|
||||||
|
print("=== Testing /api/processGet ===")
|
||||||
|
test_process_get(conveyor_belt_id=108) # 替换为实际的传送带 ID
|
||||||
|
|
||||||
|
# 测试 /api/processPost
|
||||||
|
print("\n=== Testing /api/processPost ===")
|
||||||
|
test_process_post(conveyor_belt_id=108, action=1, speed=100) # 启动传送带
|
||||||
|
test_process_post(conveyor_belt_id=108, action=0, speed=0) # 停止传送带
|
||||||
|
test_process_post(conveyor_belt_id=108, action=2, speed=50) # 无效操作测试
|
||||||
61
xmake.lua
Normal file
61
xmake.lua
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
-- 设置项目基本配置
|
||||||
|
add_rules("mode.debug", "mode.release")
|
||||||
|
add_languages("c++20")
|
||||||
|
set_policy("package.install_locally", true)
|
||||||
|
|
||||||
|
-- 包含 SDK 的构建配置
|
||||||
|
includes("AbilitySDK/xmake.lua")
|
||||||
|
|
||||||
|
|
||||||
|
add_requires("wiringPi")
|
||||||
|
add_requires("my-libmodbus",{alias="libmodbus"})
|
||||||
|
|
||||||
|
add_requires("jsoncpp")
|
||||||
|
|
||||||
|
add_requires("protobuf-cpp")
|
||||||
|
add_requires("grpc")
|
||||||
|
|
||||||
|
add_requires("abseil", {alias = "abseil"})
|
||||||
|
|
||||||
|
includes("package-index.lua")
|
||||||
|
|
||||||
|
-- 添加包含路径
|
||||||
|
add_includedirs("AbilitySDK/include")
|
||||||
|
|
||||||
|
|
||||||
|
target("protos")
|
||||||
|
set_kind("object")
|
||||||
|
add_packages("protobuf-cpp","grpc",{public=true})
|
||||||
|
add_rules("protobuf.cpp")
|
||||||
|
add_files("protos/conveyorBelt.proto", {proto_public=true,proto_rootdir = "protos", proto_grpc_cpp_plugin = true})
|
||||||
|
-- 这是旧版api使用的protos,移植到新版后可以去除
|
||||||
|
add_files("protos/abilityProto.proto", {proto_public=true,proto_rootdir = "protos", proto_grpc_cpp_plugin = true})
|
||||||
|
|
||||||
|
|
||||||
|
-- ConveyorBeltControlUnit 库
|
||||||
|
target("conveyor-control-unit")
|
||||||
|
set_kind("static")
|
||||||
|
add_includedirs("ConveyorBeltControlUnit/include", {public = true})
|
||||||
|
add_files("ConveyorBeltControlUnit/src/*.cpp")
|
||||||
|
--add_packages("cpp-httplib","jsoncpp","glog","libmodbus","wiringPi","abseil",{public=true})
|
||||||
|
add_packages("cpp-httplib","jsoncpp","glog","libmodbus","abseil",{public=true})
|
||||||
|
|
||||||
|
|
||||||
|
-- ConveyorBeltAbility 库
|
||||||
|
target("conveyor-ability")
|
||||||
|
set_kind("binary")
|
||||||
|
add_includedirs("ConveyorBeltAbility/include", {public = true})
|
||||||
|
add_files("ConveyorBeltAbility/src/*.cpp")
|
||||||
|
add_deps("AbilitySDK", "conveyor-control-unit", "protos")
|
||||||
|
add_packages("cpp-httplib","jsoncpp","glog","abseil",{public=true})
|
||||||
|
|
||||||
|
|
||||||
|
-- ConveyorBeltController 库
|
||||||
|
target("conveyor-controller")
|
||||||
|
set_kind("binary")
|
||||||
|
add_includedirs("ConveyorBeltControlUnit/include", {public = true})
|
||||||
|
add_includedirs("ConveyorBeltController/include", {public = true})
|
||||||
|
add_files("ConveyorBeltController/src/*.cpp")
|
||||||
|
add_deps("AbilitySDK", "protos")
|
||||||
|
add_packages("cpp-httplib","jsoncpp","libmodbus","glog","abseil",{public=true})
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user