added get protocol version api

This commit is contained in:
Ruixiang Du
2021-07-13 18:03:50 +08:00
parent 8b606b7520
commit f7224bf56f
14 changed files with 96 additions and 55 deletions

View File

@@ -34,9 +34,11 @@ int main(int argc, char **argv) {
std::unique_ptr<ScoutRobot> scout; std::unique_ptr<ScoutRobot> scout;
if (protocol_version == "v1") { if (protocol_version == "v1") {
scout = std::unique_ptr<ScoutRobot>(new ScoutRobot(ProtocolType::AGX_V1)); scout =
std::unique_ptr<ScoutRobot>(new ScoutRobot(ProtocolVersion::AGX_V1));
} else if (protocol_version == "v2") { } else if (protocol_version == "v2") {
scout = std::unique_ptr<ScoutRobot>(new ScoutRobot(ProtocolType::AGX_V2)); scout =
std::unique_ptr<ScoutRobot>(new ScoutRobot(ProtocolVersion::AGX_V2));
} else { } else {
std::cout << "Error: invalid protocol version string" << std::endl; std::cout << "Error: invalid protocol version string" << std::endl;
return -1; return -1;
@@ -46,7 +48,13 @@ int main(int argc, char **argv) {
std::cout << "Failed to create robot object" << std::endl; std::cout << "Failed to create robot object" << std::endl;
scout->Connect(device_name); scout->Connect(device_name);
scout->EnableCommandedMode();
if (scout->GetProtocolVersion() == ProtocolVersion::AGX_V2) {
scout->EnableCommandedMode();
std::cout << "Protocol version 2" << std::endl;
} else {
std::cout << "Protocol version 1" << std::endl;
}
// light control // light control
std::cout << "Light: const off" << std::endl; std::cout << "Light: const off" << std::endl;
@@ -67,10 +75,10 @@ int main(int argc, char **argv) {
int count = 0; int count = 0;
while (true) { while (true) {
// motion control // motion control
if (count < 100) { // if (count < 100) {
std::cout << "Motor: 0.2, 0" << std::endl; // std::cout << "Motor: 0.2, 0" << std::endl;
scout->SetMotionCommand(0.2, 0.0); // scout->SetMotionCommand(0.2, 0.0);
} // }
// get robot state // get robot state
auto state = scout->GetRobotState(); auto state = scout->GetRobotState();
@@ -80,12 +88,23 @@ int main(int argc, char **argv) {
<< static_cast<int>(state.system_state.control_mode) << static_cast<int>(state.system_state.control_mode)
<< " , vehicle state: " << " , vehicle state: "
<< static_cast<int>(state.system_state.vehicle_state) << static_cast<int>(state.system_state.vehicle_state)
<< std::endl; << " , error code: " << std::hex << state.system_state.error_code
std::cout << "battery voltage: " << state.system_state.battery_voltage << ", battery voltage: " << state.system_state.battery_voltage
<< std::endl; << std::endl;
std::cout << "velocity (linear, angular): " std::cout << "velocity (linear, angular): "
<< state.motion_state.linear_velocity << ", " << state.motion_state.linear_velocity << ", "
<< state.motion_state.angular_velocity << std::endl; << state.motion_state.angular_velocity << std::endl;
if (scout->GetProtocolVersion() == ProtocolVersion::AGX_V1) {
for (int i = 0; i < 4; ++i) {
printf("motor %d: current %f, rpm %d, driver temp %f, motor temp %f\n",
state.actuator_state[i].motor_id,
state.actuator_state[i].current, state.actuator_state[i].rpm,
state.actuator_state[i].driver_temp,
state.actuator_state[i].motor_temp);
}
} else {
}
std::cout << "-------------------------------" << std::endl; std::cout << "-------------------------------" << std::endl;
usleep(20000); usleep(20000);

View File

@@ -26,11 +26,17 @@ struct can_frame {
#include "ugv_sdk/details/interface/agilex_message.h" #include "ugv_sdk/details/interface/agilex_message.h"
struct ParserInterface { enum class ProtocolVersion { AGX_V1, AGX_V2 };
template <ProtocolVersion VersionNumber = ProtocolVersion::AGX_V2>
class ParserInterface {
public:
virtual ~ParserInterface() = default;
// CAN support // CAN support
virtual bool DecodeMessage(const struct can_frame *rx_frame, virtual bool DecodeMessage(const struct can_frame *rx_frame,
AgxMessage *msg) = 0; AgxMessage *msg) = 0;
virtual void EncodeMessage(const AgxMessage *msg, virtual bool EncodeMessage(const AgxMessage *msg,
struct can_frame *tx_frame) = 0; struct can_frame *tx_frame) = 0;
virtual uint8_t CalculateChecksum(uint16_t id, uint8_t *data, virtual uint8_t CalculateChecksum(uint16_t id, uint8_t *data,
uint8_t dlc) = 0; uint8_t dlc) = 0;
@@ -47,6 +53,8 @@ struct ParserInterface {
// throw exception // throw exception
return 0; return 0;
}; };
ProtocolVersion GetProtocolVersion() { return VersionNumber; }
}; };
#endif /* PASER_INTERFACE_HPP */ #endif /* PASER_INTERFACE_HPP */

View File

@@ -13,10 +13,9 @@
#include <string> #include <string>
#include "ugv_sdk/details/interface/agilex_message.h" #include "ugv_sdk/details/interface/agilex_message.h"
#include "ugv_sdk/details/interface/parser_interface.hpp"
namespace westonrobot { namespace westonrobot {
enum class ProtocolType { AGX_V1, AGX_V2 };
class RobotInterface { class RobotInterface {
public: public:
~RobotInterface() = default; ~RobotInterface() = default;
@@ -33,12 +32,14 @@ class RobotInterface {
}; };
virtual void ResetRobotState() = 0; virtual void ResetRobotState() = 0;
virtual ProtocolVersion GetProtocolVersion() = 0;
protected: protected:
/****** functions not available/valid to all robots ******/ /****** functions not available/valid to all robots ******/
// functions to be implemented by class AgilexBase // functions to be implemented by class AgilexBase
virtual void SetMotionMode(uint8_t mode){}; virtual void SetMotionMode(uint8_t mode){};
// any specific robot will use a specialized version of the two functions // any specific robot will use a specialized version of the two functions
virtual void SendMotionCommand(double linear_vel, double angular_vel, virtual void SendMotionCommand(double linear_vel, double angular_vel,
double lateral_velocity, double lateral_velocity,
double steering_angle){ double steering_angle){

View File

@@ -29,7 +29,7 @@ struct ScoutState {
}; };
struct ScoutInterface { struct ScoutInterface {
~ScoutInterface() = default; virtual ~ScoutInterface() = default;
virtual void SetMotionCommand(double linear_vel, double angular_vel) = 0; virtual void SetMotionCommand(double linear_vel, double angular_vel) = 0;
virtual void SetLightCommand(LightMode f_mode, uint8_t f_value, virtual void SetLightCommand(LightMode f_mode, uint8_t f_value,

View File

@@ -31,7 +31,7 @@ struct can_frame {
#include "ugv_sdk/details/interface/agilex_message.h" #include "ugv_sdk/details/interface/agilex_message.h"
bool DecodeCanFrameV1(const struct can_frame *rx_frame, AgxMessage *msg); bool DecodeCanFrameV1(const struct can_frame *rx_frame, AgxMessage *msg);
void EncodeCanFrameV1(const AgxMessage *msg, struct can_frame *tx_frame); bool EncodeCanFrameV1(const AgxMessage *msg, struct can_frame *tx_frame);
uint8_t CalcCanFrameChecksumV1(uint16_t id, uint8_t *data, uint8_t dlc); uint8_t CalcCanFrameChecksumV1(uint16_t id, uint8_t *data, uint8_t dlc);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -17,14 +17,14 @@
namespace westonrobot { namespace westonrobot {
template <typename RobotLimitsType> template <typename RobotLimitsType>
class ProtocolV1Parser : public ParserInterface { class ProtocolV1Parser : public ParserInterface<ProtocolVersion::AGX_V1> {
public: public:
bool DecodeMessage(const struct can_frame *rx_frame, bool DecodeMessage(const struct can_frame *rx_frame,
AgxMessage *msg) override { AgxMessage *msg) override {
return DecodeCanFrameV1(rx_frame, msg); return DecodeCanFrameV1(rx_frame, msg);
} }
void EncodeMessage(const AgxMessage *msg, bool EncodeMessage(const AgxMessage *msg,
struct can_frame *tx_frame) override { struct can_frame *tx_frame) override {
AgxMessage msg_v1 = *msg; AgxMessage msg_v1 = *msg;
if (msg->type == AgxMsgMotionCommandV1) { if (msg->type == AgxMsgMotionCommandV1) {
@@ -44,7 +44,7 @@ class ProtocolV1Parser : public ParserInterface {
msg_v1.body.v1_motion_command_msg.angular = msg_v1.body.v1_motion_command_msg.angular =
angular / RobotLimitsType::max_angular * 100.0; angular / RobotLimitsType::max_angular * 100.0;
} }
EncodeCanFrameV1(&msg_v1, tx_frame); return EncodeCanFrameV1(&msg_v1, tx_frame);
} }
uint8_t CalculateChecksum(uint16_t id, uint8_t *data, uint8_t dlc) override { uint8_t CalculateChecksum(uint16_t id, uint8_t *data, uint8_t dlc) override {

View File

@@ -13,11 +13,11 @@
#include "ugv_sdk/details/interface/parser_interface.hpp" #include "ugv_sdk/details/interface/parser_interface.hpp"
namespace westonrobot { namespace westonrobot {
class ProtocolV2Parser : public ParserInterface { class ProtocolV2Parser : public ParserInterface<ProtocolVersion::AGX_V2> {
public: public:
bool DecodeMessage(const struct can_frame *rx_frame, bool DecodeMessage(const struct can_frame *rx_frame,
AgxMessage *msg) override; AgxMessage *msg) override;
void EncodeMessage(const AgxMessage *msg, bool EncodeMessage(const AgxMessage *msg,
struct can_frame *tx_frame) override; struct can_frame *tx_frame) override;
uint8_t CalculateChecksum(uint16_t id, uint8_t *data, uint8_t dlc) override; uint8_t CalculateChecksum(uint16_t id, uint8_t *data, uint8_t dlc) override;
}; };

View File

@@ -46,8 +46,7 @@ class AgilexBase : public RobotInterface {
// encode msg to can frame and send to bus // encode msg to can frame and send to bus
can_frame frame; can_frame frame;
parser_.EncodeMessage(&msg, &frame); if (parser_.EncodeMessage(&msg, &frame)) can_->SendFrame(frame);
can_->SendFrame(frame);
} }
// must be called at a frequency >= 50Hz // must be called at a frequency >= 50Hz
@@ -64,8 +63,7 @@ class AgilexBase : public RobotInterface {
// send to can bus // send to can bus
can_frame frame; can_frame frame;
parser_.EncodeMessage(&msg, &frame); if (parser_.EncodeMessage(&msg, &frame)) can_->SendFrame(frame);
can_->SendFrame(frame);
} }
} }
@@ -83,8 +81,7 @@ class AgilexBase : public RobotInterface {
// send to can bus // send to can bus
can_frame frame; can_frame frame;
parser_.EncodeMessage(&msg, &frame); if (parser_.EncodeMessage(&msg, &frame)) can_->SendFrame(frame);
can_->SendFrame(frame);
} }
} }
@@ -97,8 +94,7 @@ class AgilexBase : public RobotInterface {
// send to can bus // send to can bus
can_frame frame; can_frame frame;
parser_.EncodeMessage(&msg, &frame); if (parser_.EncodeMessage(&msg, &frame)) can_->SendFrame(frame);
can_->SendFrame(frame);
} }
} }
@@ -111,11 +107,14 @@ class AgilexBase : public RobotInterface {
// send to can bus // send to can bus
can_frame frame; can_frame frame;
parser_.EncodeMessage(&msg, &frame); if (parser_.EncodeMessage(&msg, &frame)) can_->SendFrame(frame);
can_->SendFrame(frame);
} }
} }
ProtocolVersion GetProtocolVersion() override {
return parser_.GetProtocolVersion();
}
protected: protected:
ParserType parser_; ParserType parser_;
std::mutex state_mutex_; std::mutex state_mutex_;

View File

@@ -18,7 +18,7 @@
namespace westonrobot { namespace westonrobot {
class ScoutRobot : public RobotInterface, public ScoutInterface { class ScoutRobot : public RobotInterface, public ScoutInterface {
public: public:
ScoutRobot(ProtocolType protocol = ProtocolType::AGX_V2); ScoutRobot(ProtocolVersion protocol = ProtocolVersion::AGX_V2);
~ScoutRobot(); ~ScoutRobot();
void Connect(std::string can_name) override; void Connect(std::string can_name) override;
@@ -33,6 +33,8 @@ class ScoutRobot : public RobotInterface, public ScoutInterface {
void ResetRobotState() override; void ResetRobotState() override;
ProtocolVersion GetProtocolVersion() override;
// get robot state // get robot state
ScoutState GetRobotState() override; ScoutState GetRobotState() override;

View File

@@ -11,10 +11,10 @@
#include "ugv_sdk/details/robot_base/scout_base.hpp" #include "ugv_sdk/details/robot_base/scout_base.hpp"
namespace westonrobot { namespace westonrobot {
ScoutRobot::ScoutRobot(ProtocolType protocol) { ScoutRobot::ScoutRobot(ProtocolVersion protocol) {
if (protocol == ProtocolType::AGX_V1) { if (protocol == ProtocolVersion::AGX_V1) {
robot_ = new ScoutBaseV1(); robot_ = new ScoutBaseV1();
} else if (protocol == ProtocolType::AGX_V2) { } else if (protocol == ProtocolVersion::AGX_V2) {
robot_ = new ScoutBaseV2(); robot_ = new ScoutBaseV2();
} }
} }
@@ -33,6 +33,10 @@ void ScoutRobot::Connect(std::string uart_name, uint32_t baudrate) {
void ScoutRobot::ResetRobotState() { robot_->ResetRobotState(); } void ScoutRobot::ResetRobotState() { robot_->ResetRobotState(); }
ProtocolVersion ScoutRobot::GetProtocolVersion() {
return robot_->GetProtocolVersion();
}
void ScoutRobot::SetMotionCommand(double linear_vel, double angular_vel) { void ScoutRobot::SetMotionCommand(double linear_vel, double angular_vel) {
auto scout = dynamic_cast<ScoutInterface*>(robot_); auto scout = dynamic_cast<ScoutInterface*>(robot_);
scout->SetMotionCommand(linear_vel, angular_vel); scout->SetMotionCommand(linear_vel, angular_vel);

View File

@@ -18,6 +18,7 @@ bool DecodeCanFrameV1(const struct can_frame *rx_frame, AgxMessage *msg) {
// if checksum not correct // if checksum not correct
if (!CalcCanFrameChecksumV1(rx_frame->can_id, (uint8_t *)rx_frame->data, if (!CalcCanFrameChecksumV1(rx_frame->can_id, (uint8_t *)rx_frame->data,
rx_frame->can_dlc)) { rx_frame->can_dlc)) {
printf("wrong checksum for id: %x-------------->\n", rx_frame->can_id);
return false; return false;
} }
@@ -36,13 +37,16 @@ bool DecodeCanFrameV1(const struct can_frame *rx_frame, AgxMessage *msg) {
case CAN_MSG_MOTION_STATE_ID: { case CAN_MSG_MOTION_STATE_ID: {
msg->type = AgxMsgMotionState; msg->type = AgxMsgMotionState;
msg->body.motion_state_msg.linear_velocity = msg->body.motion_state_msg.linear_velocity =
((((uint16_t)rx_frame->data[0]) << 8) | (uint16_t)rx_frame->data[1]) / ((int16_t)((((uint16_t)rx_frame->data[0]) << 8) |
(uint16_t)rx_frame->data[1])) /
1000.0f; 1000.0f;
msg->body.motion_state_msg.angular_velocity = msg->body.motion_state_msg.angular_velocity =
((((uint16_t)rx_frame->data[2]) << 8) | (uint16_t)rx_frame->data[3]) / ((int16_t)((((uint16_t)rx_frame->data[2]) << 8) |
(uint16_t)rx_frame->data[3])) /
1000.0f; 1000.0f;
msg->body.motion_state_msg.lateral_velocity = msg->body.motion_state_msg.lateral_velocity =
((((uint16_t)rx_frame->data[4]) << 8) | (uint16_t)rx_frame->data[5]) / ((int16_t)((((uint16_t)rx_frame->data[4]) << 8) |
(uint16_t)rx_frame->data[5])) /
1000.0f; 1000.0f;
break; break;
} }
@@ -89,7 +93,8 @@ bool DecodeCanFrameV1(const struct can_frame *rx_frame, AgxMessage *msg) {
return true; return true;
} }
void EncodeCanFrameV1(const AgxMessage *msg, struct can_frame *tx_frame) { bool EncodeCanFrameV1(const AgxMessage *msg, struct can_frame *tx_frame) {
bool ret = true;
switch (msg->type) { switch (msg->type) {
case AgxMsgMotionCommandV1: { case AgxMsgMotionCommandV1: {
static uint8_t count = 0; static uint8_t count = 0;
@@ -155,9 +160,12 @@ void EncodeCanFrameV1(const AgxMessage *msg, struct can_frame *tx_frame) {
tx_frame->can_id, tx_frame->data, tx_frame->can_dlc); tx_frame->can_id, tx_frame->data, tx_frame->can_dlc);
break; break;
} }
default: default: {
ret = false;
break; break;
}
} }
return ret;
} }
uint8_t CalcCanFrameChecksumV1(uint16_t id, uint8_t *data, uint8_t dlc) { uint8_t CalcCanFrameChecksumV1(uint16_t id, uint8_t *data, uint8_t dlc) {

View File

@@ -50,8 +50,7 @@ bool DecodeCanFrameV2(const struct can_frame *rx_frame, AgxMessage *msg) {
msg->body.light_command_msg.front_light.custom_value = msg->body.light_command_msg.front_light.custom_value =
frame->front_custom; frame->front_custom;
msg->body.light_command_msg.rear_light.mode = frame->rear_mode; msg->body.light_command_msg.rear_light.mode = frame->rear_mode;
msg->body.light_command_msg.rear_light.custom_value = msg->body.light_command_msg.rear_light.custom_value = frame->rear_custom;
frame->rear_custom;
break; break;
} }
case CAN_MSG_BRAKING_COMMAND_ID: { case CAN_MSG_BRAKING_COMMAND_ID: {
@@ -104,8 +103,7 @@ bool DecodeCanFrameV2(const struct can_frame *rx_frame, AgxMessage *msg) {
msg->body.light_command_msg.front_light.custom_value = msg->body.light_command_msg.front_light.custom_value =
frame->front_custom; frame->front_custom;
msg->body.light_command_msg.rear_light.mode = frame->rear_mode; msg->body.light_command_msg.rear_light.mode = frame->rear_mode;
msg->body.light_command_msg.rear_light.custom_value = msg->body.light_command_msg.rear_light.custom_value = frame->rear_custom;
frame->rear_custom;
break; break;
} }
case CAN_MSG_RC_STATE_ID: { case CAN_MSG_RC_STATE_ID: {
@@ -192,10 +190,9 @@ bool DecodeCanFrameV2(const struct can_frame *rx_frame, AgxMessage *msg) {
msg->body.actuator_ls_state_msg.driver_state = frame->driver_state; msg->body.actuator_ls_state_msg.driver_state = frame->driver_state;
break; break;
} }
case CAN_MSG_CURRENT_CTRL_MODE: case CAN_MSG_CURRENT_CTRL_MODE: {
{ msg->type = AgxMsgMotionModeState;
msg->type=AgxMsgMotionModeState; MotionModeStateFrame *frame = (MotionModeStateFrame *)(rx_frame->data);
MotionModeStateFrame *frame = (MotionModeStateFrame*)(rx_frame->data);
msg->body.motion_mode_feedback_msg.motion_mode = frame->motion_mode; msg->body.motion_mode_feedback_msg.motion_mode = frame->motion_mode;
msg->body.motion_mode_feedback_msg.mode_changing = frame->mode_changing; msg->body.motion_mode_feedback_msg.mode_changing = frame->mode_changing;
@@ -309,7 +306,8 @@ bool DecodeCanFrameV2(const struct can_frame *rx_frame, AgxMessage *msg) {
return true; return true;
} }
void EncodeCanFrameV2(const AgxMessage *msg, struct can_frame *tx_frame) { bool EncodeCanFrameV2(const AgxMessage *msg, struct can_frame *tx_frame) {
bool ret = true;
switch (msg->type) { switch (msg->type) {
/***************** command frame *****************/ /***************** command frame *****************/
case AgxMsgMotionCommand: { case AgxMsgMotionCommand: {
@@ -346,8 +344,7 @@ void EncodeCanFrameV2(const AgxMessage *msg, struct can_frame *tx_frame) {
frame.front_custom = frame.front_custom =
msg->body.light_command_msg.front_light.custom_value; msg->body.light_command_msg.front_light.custom_value;
frame.rear_mode = msg->body.light_command_msg.rear_light.mode; frame.rear_mode = msg->body.light_command_msg.rear_light.mode;
frame.rear_custom = frame.rear_custom = msg->body.light_command_msg.rear_light.custom_value;
msg->body.light_command_msg.rear_light.custom_value;
} else { } else {
frame.enable_cmd_ctrl = LIGHT_DISABLE_CMD_CTRL; frame.enable_cmd_ctrl = LIGHT_DISABLE_CMD_CTRL;
frame.front_mode = 0; frame.front_mode = 0;
@@ -590,9 +587,12 @@ void EncodeCanFrameV2(const AgxMessage *msg, struct can_frame *tx_frame) {
memcpy(tx_frame->data, (uint8_t *)(&frame), tx_frame->can_dlc); memcpy(tx_frame->data, (uint8_t *)(&frame), tx_frame->can_dlc);
break; break;
} }
default: default: {
ret = false;
break; break;
}
} }
return ret;
} }
uint8_t CalcCanFrameChecksumV2(uint16_t id, uint8_t *data, uint8_t dlc) { uint8_t CalcCanFrameChecksumV2(uint16_t id, uint8_t *data, uint8_t dlc) {

View File

@@ -31,7 +31,7 @@ struct can_frame {
#include "ugv_sdk/details/interface/agilex_message.h" #include "ugv_sdk/details/interface/agilex_message.h"
bool DecodeCanFrameV2(const struct can_frame *rx_frame, AgxMessage *msg); bool DecodeCanFrameV2(const struct can_frame *rx_frame, AgxMessage *msg);
void EncodeCanFrameV2(const AgxMessage *msg, struct can_frame *tx_frame); bool EncodeCanFrameV2(const AgxMessage *msg, struct can_frame *tx_frame);
uint8_t CalcCanFrameChecksumV2(uint16_t id, uint8_t *data, uint8_t dlc); uint8_t CalcCanFrameChecksumV2(uint16_t id, uint8_t *data, uint8_t dlc);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -16,9 +16,9 @@ bool ProtocolV2Parser::DecodeMessage(const struct can_frame *rx_frame,
return DecodeCanFrameV2(rx_frame, msg); return DecodeCanFrameV2(rx_frame, msg);
} }
void ProtocolV2Parser::EncodeMessage(const AgxMessage *msg, bool ProtocolV2Parser::EncodeMessage(const AgxMessage *msg,
struct can_frame *tx_frame) { struct can_frame *tx_frame) {
EncodeCanFrameV2(msg, tx_frame); return EncodeCanFrameV2(msg, tx_frame);
} }
uint8_t ProtocolV2Parser::CalculateChecksum(uint16_t id, uint8_t *data, uint8_t ProtocolV2Parser::CalculateChecksum(uint16_t id, uint8_t *data,