初次提交

This commit is contained in:
myq 2025-03-18 15:03:45 +08:00
commit 45e634bd7c
25 changed files with 1254 additions and 0 deletions

1
AbilitySDK Submodule

@ -0,0 +1 @@
Subproject commit e20893b78a520157efeb28aeadb5914c5435d8f8

View File

@ -0,0 +1,46 @@
#include "ability_sdk/AbilityStub.hpp"
#include "conveyorBeltGrpcServer.h"
class ConveyorBeltAbility : public ability_sdk::AbilityInterface {
public:
ConveyorBeltStatus status;
void OnStart() override{
cout << "OnStart" << endl;
g_GLOBAL_STATUS = STATUS_STANDBY;
sendStateMsg();
}
void OnConnect() override {
cout << "OnConnect" << endl;
thread t_abilityserver(&AbilityTemplate::create_ability_server, this);
t_abilityserver.detach();
g_GLOBAL_STATUS = STATUS_RUNNING;
sendStateMsg();
}
void OnDisconnect() override {
cout << "OnDisconnect" << endl;
ability_server->Shutdown();
ability_cq->Shutdown();
g_GLOBAL_STATUS = STATUS_SUSPEND;
g_abilityPort = 0;
sendStateMsg();
}
void OnTerminate() override {
cout << "OnTerminate" << endl;
g_GLOBAL_STATUS = STATUS_TERMINATE;
sendStateMsg();
// exit(0);
}
// 获取端口
int abilityPort() const override {
return g_abilityPort;
}
// GRPC 服务端
void create_ability_server();
};

View 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

View 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;
}

View 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;
}

View 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

View File

@ -0,0 +1,21 @@
#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);
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;
}

View 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() {}

View File

@ -0,0 +1,17 @@
#include "conveyorBeltAbility.hpp"
using grpc::Server;
using grpc::ServerBuilder;
int main() {
int selected_port;
ConveyorBeltAbility service("conveyorBelt");
ServerBuilder builder;
builder.AddListeningPort("0.0.0.0:0", grpc::InsecureServerCredentials(), &selected_port);
builder.RegisterService(&service);
std::unique_ptr<Server> server(builder.BuildAndStart());
std::cout << "Server listening on :" << selected_port << std::endl;
service.setIpcPort(selected_port);
service.runServer();
server->Wait();
}

View File

@ -0,0 +1,14 @@
add_rules("mode.debug", "mode.release")
add_languages("c++20")
-- 添加包含路径
add_includedirs("include")
add_includedirs("../ConveyorBeltControlUnit/include")
-- 添加源文件
add_files("src/*.cpp")
add_files("protos/*.proto", {proto_rootdir = "protos", proto_grpc_cpp_plugin = true})
-- 添加依赖
add_requires("glog", "grpc", "protobuf-cpp")
add_packages("glog", "grpc", "protobuf-cpp")

View 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_

View File

@ -0,0 +1,75 @@
#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>
}
// 传送带控制单元
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();
};

View File

@ -0,0 +1,216 @@
#include "conveyorBeltControlUnit.h"
// 定义状态
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;
DLOG(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) {
DLOG(INFO) << YELLOW << "find a start signal" << EMPTY;
current_start_signal = 0;
action(EVENT_START_RISING);
}
if (digitalRead(INPUT_FSENSOR) == IN_LOGIC_1) {
// DLOG(INFO) << YELLOW << "find a Fsensor signal" << EMPTY;
action(EVENT_FSENSOR_OBSTRUCT);
}
if (digitalRead(INPUT_RSENSOR) == IN_LOGIC_1) {
// DLOG(INFO) << YELLOW << "find a Rsensor signal" << EMPTY;
action(EVENT_RSENSOR_OBSTRUCT);
}
if (current_stop_signal == 1) {
DLOG(INFO) << YELLOW << "find a stop signal" << EMPTY;
DLOG(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;
}
DLOG(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;
}
DLOG(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);
DLOG(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) {
DLOG(INFO) << YELLOW << "set direction to foreward" << EMPTY;
INPUT_FSENSOR = 28;
INPUT_RSENSOR = 29;
OUT_FRUN = 14;
OUT_RRUN = 10;
}
else if (direction == 1) {
DLOG(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}};
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() {}

View File

@ -0,0 +1,44 @@
#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 <json/json.h>
#include <map>
#include <memory>
#include <shared_mutex>
#include <stdio.h>
#include <string>
typedef int ConveyorBeltStatus;
class 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);
int grpcConnect(float speed, int direction);
int grpcDisconnect();
int grpcCheck();
int synchState(std::string json);
bool simpleStateCheck();
public:
int handleOpen(float speed, int direction);
int handleClose();
int handleCheck();
void init();
void setServerIp(std::string serverIp);
ConveyorBeltStatus getCurrentStatus();
ConveyorBeltController(/* args */);
~ConveyorBeltController();
};
#endif

View File

@ -0,0 +1,82 @@
#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) {
DLOG(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()) {
DLOG(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; }
DLOG(INFO) << GRAY << "finish connect to belt" << EMPTY;
return 0;
}
int close() {
DLOG(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; }
DLOG(INFO) << GRAY << "start connect to belt" << EMPTY;
return 0;
}
int getWorkState() {
DLOG(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);
DLOG(INFO) << GRAY << "start connect to belt" << EMPTY;
return response.code();
}
ConveyorBeltGrpcClient(std::shared_ptr<Channel> channel)
: stub_(ConveyorBelt::ConveyorBeltService::NewStub(channel)) {}
~ConveyorBeltGrpcClient() {}
};
#endif

View File

@ -0,0 +1,27 @@
#ifndef HTTP_SERVER_H_
#define HTTP_SERVER_H_
#include <httplib.h>
#include "color.h"
#include "conveyorBeltController.h"
#include <glog/logging.h>
#include <json/json.h>
#include <map>
#include <memory>
#include <thread>
class HttpServer {
public:
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;
};
#endif // HTTP_SERVER_H_

View 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;
}

View 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;
}

View 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

View File

@ -0,0 +1,245 @@
#include "conveyorBeltController.h"
const ConveyorBeltStatus OFFLINE = 0;
const ConveyorBeltStatus READY = 1;
const ConveyorBeltStatus RUNNING = 2;
ConveyorBeltController::ConveyorBeltController(/* args */) {}
ConveyorBeltController::~ConveyorBeltController() {}
void ConveyorBeltController::setServerIp(std::string conveyorBeltIp) {
this->ip = conveyorBeltIp;
}
void ConveyorBeltController::init() {
std::unique_lock<std::shared_mutex> w_lock(mutex_);
DLOG(INFO) << WHITE << "init controller state" << EMPTY;
status = OFFLINE;
abilityPort = 0;
IPCPort = 0;
}
int ConveyorBeltController::handleCheck() {
std::unique_lock<std::shared_mutex> w_lock(mutex_);
if (simpleStateCheck()) { return 0; }
else { return -1; }
}
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;
}
DLOG(INFO) << WHITE << "ConveyorBelt is already running, do not open twice" << EMPTY;
break;
case READY:
DLOG(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:
DLOG(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:
DLOG(INFO) << WHITE << "ConveyorBelt has not been opened, do not close twice" << EMPTY;
break;
case RUNNING:
DLOG(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() {
DLOG(INFO) << WHITE << "start simple check" << EMPTY;
httplib::Client client(ip, 8080);
int mStatus;
auto res = client.Get("/api/AbilityRunning");
if (res) {
DLOG(INFO) << WHITE << "GET response:" << res->status << EMPTY;
mStatus = synchState(res->body);
if (mStatus == status) {
DLOG(INFO) << WHITE
<< "simple check pass current status is correct with abilityFrameWork"
<< EMPTY;
return true;
}
else {
DLOG(INFO) << WHITE << "simple check failed incorrect state" << EMPTY;
return false;
}
}
else {
DLOG(ERROR) << "FIRST STEP: can not connect with abilityFrameWork" << EMPTY;
DLOG(INFO) << WHITE << "now ConveyorBelt is OFFLINE" << EMPTY;
status = OFFLINE;
abilityPort = 0;
IPCPort = 0;
return false;
}
}
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++) {
DLOG(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_);
DLOG(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_);
DLOG(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_);
DLOG(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) { DLOG(INFO) << WHITE << "POST response:" << res->status << EMPTY; }
else {
DLOG(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) {
DLOG(INFO) << WHITE << "GET response:" << res->status << EMPTY;
mStatus = synchState(res->body);
if (mStatus == destState) {
DLOG(INFO) << WHITE << "switch state success" << EMPTY;
return 0;
}
}
else {
DLOG(ERROR) << "THIRD STEP: can not connect with abilityFrameWork" << EMPTY;
return -1;
}
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
DLOG(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));
DLOG(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));
DLOG(INFO) << WHITE << url << EMPTY;
ConveyorBeltGrpcClient client(grpc::CreateChannel(url, grpc::InsecureChannelCredentials()));
if (client.close() == -1) {
DLOG(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));
DLOG(INFO) << WHITE << url << EMPTY;
ConveyorBeltGrpcClient client(grpc::CreateChannel(url, grpc::InsecureChannelCredentials()));
if (client.getWorkState() == -1) {
DLOG(ERROR) << "grpc work state is false" << EMPTY;
return -1;
}
return 0;
}

View File

@ -0,0 +1,116 @@
#include "http_server.h"
void HttpServer::Init() {
FLAGS_logtostderr = 1;
DLOG(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) {
DLOG(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");
DLOG(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) {
DLOG(INFO) << L_BLUE << "httpserver receive: method: POST URL: /api/processPost"
<< EMPTY;
DLOG(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) {
DLOG(ERROR) << "json parse error";
res.status = 400;
status = 400;
}
else {
DLOG(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) {
DLOG(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) {
DLOG(INFO) << YELLOW << "http server try to handle close" << EMPTY;
std::thread closeThread(
&ConveyorBeltController::handleClose, this->controller
);
closeThread.detach();
}
else {
DLOG(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() {
DLOG(INFO) << L_GREEN << "http server start" << EMPTY;
this->server->listen("0.0.0.0", 8001);
}

View File

@ -0,0 +1,9 @@
#include "http_server.h"
// 控制器在http服务器中启动
int main(int argc, char* argv[]) {
google::InitGoogleLogging(argv[0]);
HttpServer server;
server.Init();
server.Run();
}

View File

@ -0,0 +1 @@
version: 0.1.0

2
Readme.md Normal file
View File

@ -0,0 +1,2 @@
传送带控制单元 conveyorBeltControlUnit

@ -0,0 +1 @@
Subproject commit bcd2e16ad2c44769c056f4b774e1697c7e52be5e