Commit 34086263 authored by Christian Sponfeldner's avatar Christian Sponfeldner

send actual values of all motors together

parent d2541b8b
......@@ -33,7 +33,6 @@ private:
Error MsgBoxCallback(const MsgBoxHandler::Dataframe& dataframe);
Error MsgBoxCallbackBroadcast(const MsgBoxHandler::Dataframe& dataframe);
Error EthMsgCallback(const EthHandler::Dataframe& dataframe);
Error FilterAndSendActualVelocitiesCallback();
Error CyclicCANSyncCallback();
Error CyclicTimerCallback();
void UpdateMotorTargetVelocities();
......@@ -62,15 +61,10 @@ private:
std::vector<Motor*>* mMotors;
TargetVelocitiesInterface* mTargetVelocities;
TargetVelocitiesInterface* mRampedVelocities;
ActualVelocitiesInterface* mActualVelocities;
ActualVelocitiesInterface* mAverageVelocities;
EthHandler::ObserverEthHandler mObserver_eth;
MsgBoxHandler::ObserverMsgBox mObserver_msg_box;
MsgBoxHandler::ObserverMsgBox mObserver_msg_box_broadcast;
CANSyncHandler::ObserverSyncHandler mObserver_delayed_can_sync;
CANSyncHandler::ObserverSyncHandler mObserver_cyclic_can_sync;
};
......
......@@ -23,17 +23,14 @@ Basecontroller::Basecontroller() :
mStatus_word(mInstanceFactory.GetMotorStatusInstance()),
mMotors(mInstanceFactory.GetWheelDriveMotors()),
mTargetVelocities(mInstanceFactory.GetTargetVelocitiesInstance()),
mActualVelocities(mInstanceFactory.GetActualVelocitiesInstance()),
mRampedVelocities(mInstanceFactory.GetTargetVelocitiesInstance()),
mAverageVelocities(mInstanceFactory.GetActualVelocitiesInstance()),
mObserver_eth(mDevice_id,&Basecontroller::EthMsgCallback,this),
mObserver_msg_box(mDevice_id,&Basecontroller::MsgBoxCallback,this),
mObserver_msg_box_broadcast(EMROSCmdType::BROADCAST_ID,&Basecontroller::MsgBoxCallbackBroadcast,this),
mObserver_cyclic_can_sync(every_cansync_event,&Basecontroller::CyclicCANSyncCallback,this),
mObserver_delayed_can_sync(filter_period_in_cansyncs,&Basecontroller::FilterAndSendActualVelocitiesCallback,this) {
mObserver_cyclic_can_sync(every_cansync_event,&Basecontroller::CyclicCANSyncCallback,this) {
if (!(mTargetVelocities && mActualVelocities && mRampedVelocities
if (!(mTargetVelocities && mRampedVelocities
&& mStatus_word)) {
OFCLoggerRTClient::instance()->InsertCriticalError(__PRETTY_FUNCTION__,
"resource init failed");
......@@ -55,7 +52,6 @@ Basecontroller::Basecontroller() :
Basecontroller::~Basecontroller() {
delete &mTargetVelocities;
delete &mActualVelocities;
delete &mRampedVelocities;
delete &mStatus_word;
......@@ -110,19 +106,7 @@ Error Basecontroller::MsgBoxCallback(
if (status != Error::NO_ERROR) {
return (status);
}
break;
// case ENABLE_CSV_MODE:
//
// mCSV_mode_enabled = true;
// break;
//
// case DISABLE_CSV_MODE:
//
// mCSV_mode_enabled = false;
// break;
case EMROSCmdType::Security::CMD_VEL_DOWNLINK_TIMEOUT:
//set target velocities to zero
mTargetVelocities->clearData();
......@@ -172,31 +156,6 @@ Error Basecontroller::EthMsgCallback(const EthHandler::Dataframe& dataframe) {
return (status);
}
break;
// case ENABLE_CSV_MODE: //TODO: Move to Robot-State-Controller
// mCSV_mode_enabled = true;
// tx_eth_msg.setData().id = mDevice_id;
// tx_eth_msg.setData().cmd = ENABLE_CSV_MODE;
// tx_eth_msg.setData().payload_length = 0;
// status = EthHandler::instance()->SendEthMsg(tx_eth_msg);
// if (status != Error::NO_ERROR)
// {
// return (status);
// }
// break;
//
// case DISABLE_CSV_MODE: //TODO: Move to Robot-State-Controller
// mCSV_mode_enabled = false;
// tx_eth_msg.setData().id = mDevice_id;
// tx_eth_msg.setData().cmd = DISABLE_CSV_MODE;
// tx_eth_msg.setData().payload_length = 0;
// status = EthHandler::instance()->SendEthMsg(tx_eth_msg);
// if (status != Error::NO_ERROR)
// {
// return (status);
// }
// break;
default:
;
break;
......@@ -227,8 +186,6 @@ Error Basecontroller::CyclicCANSyncCallback() {
for (auto motor : *mMotors) {
motor->GetPdoHandle()->getStatusWord((*mStatus_word)[motor->ordinal_in_datagram]);
motor->GetPdoHandle()->getVelocityActualValue(
mActualVelocities->dataByType()[motor->ordinal_in_datagram]);
}
if (mCritical_fault) {
......@@ -237,36 +194,6 @@ Error Basecontroller::CyclicCANSyncCallback() {
return (Error::ERROR);
}
if (mRos_link_enabled == true) {
mAverageVelocities->addVelocities(mActualVelocities->dataByType(),
mActualVelocities->getNumberOfMotors());
}
return (Error::NO_ERROR);
}
Error Basecontroller::FilterAndSendActualVelocitiesCallback() {
Error status { Error::NO_ERROR };
if (mRos_link_enabled == true) {
mAverageVelocities->calcAverage(uint8_t(filter_period_in_cansyncs));
EthHandler::Dataframe tx_eth_msg;
tx_eth_msg.setData().id = mDevice_id;
tx_eth_msg.setData().cmd = ACTUAL_VELOCITIES;
tx_eth_msg.setData().time =
CANSyncHandler::instance()->GetTimeOfLastSyncInUs();
status = mAverageVelocities->get(tx_eth_msg.setData().payload.begin(),
Ethprotocol::MAX_PAYLOAD_LENGTH);
if (status != Error::NO_ERROR) {
return (status);
}
tx_eth_msg.setData().payload_length = Ethprotocol::PayLen(
mAverageVelocities->getRawSize());
status = EthHandler::instance()->SendEthMsg(tx_eth_msg);
mAverageVelocities->clearData();
}
return (status);
}
#pragma once
#include "../../emros_common/include/emros_common/emros_commands.h"
#include "../../emros_common/include/emros_common/kinematics_kind_configuration.h"
#include "../../NanoOFC/core/inc/nano_ofc.h"
#include "../../system/inc/msg.h"
#include "../../system/inc/factories.h"
#include "../../motors/inc/profile_position_mode.h"
#include "../../motors/inc/homing_mode.h"
class AllMotorsController {
public:
AllMotorsController();
~AllMotorsController();
private:
Error MsgBoxCallback(const MsgBoxHandler::Dataframe& dataframe);
Error MsgBoxCallbackBroadcast(const MsgBoxHandler::Dataframe& dataframe);
Error EthMsgCallback(const EthHandler::Dataframe& dataframe);
Error SendActualVelocitiesCallback();
Error SendActualPositionsCallback();
Error CyclicCANSyncCallback();
Error CyclicTimerCallback();
Error CheckAndResetHeartbeat();
void ReactToCriticalError();
void UpdateActualPositions();
Error CopyActualPositionsInMessage(EthHandler::Dataframe& tx_dataframe);
Error SendActualPositions();
Error CopyAverageVelocitiesInMessage(EthHandler::Dataframe& tx_eth_msg);
Error SendAverageVelocities();
void PrepareMessageToRos(EthHandler::Dataframe& tx_eth_msg,
Ethprotocol::Cmd command);
EthHandler::DeviceId mDevice_id;
bool mRos_link_enabled;
bool mHeartbeat;
bool mCritical_fault;
std::vector<Motor*>* mMotors;
EMROSCmdType::AllMotorsController::ActualPositionsInterface* mActualPositions;
EMROSCmdType::AllMotorsController::ActualVelocitiesInterface* mActualVelocities;
EMROSCmdType::AllMotorsController::ActualVelocitiesInterface* mAverageVelocities;
EthHandler::ObserverEthHandler mObserver_eth;
MsgBoxHandler::ObserverMsgBox mObserver_msg_box;
MsgBoxHandler::ObserverMsgBox mObserver_msg_box_broadcast;
CANSyncHandler::ObserverSyncHandler mObserver_cyclic_can_sync;
CANSyncHandler::ObserverSyncHandler mObserver_delayed_can_sync_for_actual_velocities;
CANSyncHandler::ObserverSyncHandler mObserver_delayed_can_sync_for_actual_positions;
};
......@@ -21,7 +21,6 @@ private:
Error MsgBoxCallback(const MsgBoxHandler::Dataframe& dataframe);
Error MsgBoxCallbackBroadcast(const MsgBoxHandler::Dataframe& dataframe);
Error EthMsgCallback(const EthHandler::Dataframe& dataframe);
Error SendActualPositionsCallback();
Error CyclicCANSyncCallback();
Error CyclicTimerCallback();
Error CopyTargetPositionFromDataFrame(const EthHandler::Dataframe& dataframe);
......@@ -47,7 +46,6 @@ private:
EthHandler::ObserverEthHandler mObserver_eth;
MsgBoxHandler::ObserverMsgBox mObserver_msg_box;
MsgBoxHandler::ObserverMsgBox mObserver_msg_box_broadcast;
CANSyncHandler::ObserverSyncHandler mObserver_delayed_can_sync;
CANSyncHandler::ObserverSyncHandler mObserver_cyclic_can_sync;
ProfilePositionMode mProfilePositionHandle;
......
#include "../inc/all_motors_controller.h"
#include "../../emros_common/include/emros_common/emros_commands.h"
namespace {
const int every_cansync_event = 1;
const TimerHandler::timer_event_t every_timer_event = 1;
const uint32_t period_for_reporting_actual_values_in_cansyncs = 8;
const uint32_t filter_period_in_cansyncs =
period_for_reporting_actual_values_in_cansyncs;
const uint8_t time_to_set_start_travel_order_in_syncs = 3;
}
using namespace EMROSCmdType::AllMotorsController;
AllMotorsController::AllMotorsController() :
mDevice_id(DEVICE_ID),
mRos_link_enabled(false),
mHeartbeat(true),
mCritical_fault(false),
mMotors(InstanceFactory::instance()->GetAllMotors()),
mActualPositions(
InstanceFactory::instance()->GetActualPositionsInstance()),
mActualVelocities(
InstanceFactory::instance()->GetActualVelocitiesInstance()),
mAverageVelocities(
InstanceFactory::instance()->GetActualVelocitiesInstance()),
mObserver_eth(mDevice_id, &AllMotorsController::EthMsgCallback, this),
mObserver_msg_box(mDevice_id, &AllMotorsController::MsgBoxCallback,
this),
mObserver_msg_box_broadcast(EMROSCmdType::BROADCAST_ID,
&AllMotorsController::MsgBoxCallbackBroadcast, this),
mObserver_cyclic_can_sync(every_cansync_event,
&AllMotorsController::CyclicCANSyncCallback, this),
mObserver_delayed_can_sync_for_actual_velocities(
period_for_reporting_actual_values_in_cansyncs,
&AllMotorsController::SendActualVelocitiesCallback, this),
mObserver_delayed_can_sync_for_actual_positions(
period_for_reporting_actual_values_in_cansyncs,
&AllMotorsController::SendActualPositionsCallback, this) {
}
AllMotorsController::~AllMotorsController() {
delete &mMotors;
}
Error AllMotorsController::MsgBoxCallback(
const MsgBoxHandler::Dataframe& dataframe) {
Error status { Error::NO_ERROR };
MsgBoxHandler::Dataframe tx_msg_box;
switch (dataframe.getData().cmd) {
case EMROSCmdType::Security::CMD_VEL_DOWNLINK_TIMEOUT:
ReactToCriticalError();
break;
default:
break;
}
return (status);
}
Error AllMotorsController::MsgBoxCallbackBroadcast(
const MsgBoxHandler::Dataframe& dataframe) {
switch (dataframe.getData().cmd) {
case EMROSCmdType::Service::ENABLE_SYNC:
mRos_link_enabled = true;
break;
case EMROSCmdType::Service::DISABLE_SYNC:
mRos_link_enabled = false;
break;
case EMROSCmdType::Security::HEARTBEAT:
mHeartbeat = true;
break;
default:
break;
}
return (Error::NO_ERROR);
}
Error AllMotorsController::EthMsgCallback(
const EthHandler::Dataframe& dataframe) {
Error status { Error::NO_ERROR };
if ((mCritical_fault == false) && (mRos_link_enabled == true)) {
switch (dataframe.getData().cmd) {
// No commands from EMROS-ROS to EMROS-EM5 yet
default:
break;
}
} else if (mCritical_fault) {
// this should never happen !
ReactToCriticalError();
return (Error::ERROR);
}
return (status);
}
Error AllMotorsController::CyclicCANSyncCallback() {
if (CheckAndResetHeartbeat() == Error::ERROR) {
return Error::ERROR;
}
// Add Actual Velocity to sum for calculation of average velocity
for (auto motor : *mMotors) {
motor->GetPdoHandle()->getVelocityActualValue(
mActualVelocities->dataByType()[motor->ordinal_in_datagram]);
}
mAverageVelocities->addVelocities(mActualVelocities->dataByType(),
mActualVelocities->getNumberOfMotors());
return Error::NO_ERROR;
}
Error AllMotorsController::SendActualVelocitiesCallback() {
Error status = Error::NO_ERROR;
mAverageVelocities->calcAverage(uint8_t(filter_period_in_cansyncs));
status = SendAverageVelocities();
mAverageVelocities->clearData();
return status;
}
Error AllMotorsController::SendActualPositionsCallback() {
UpdateActualPositions();
return SendActualPositions();
}
Error AllMotorsController::CheckAndResetHeartbeat() {
if (mHeartbeat == true) {
mHeartbeat = false;
return Error::NO_ERROR;
} else {
mCritical_fault = true;
ReactToCriticalError();
return Error::ERROR;
}
}
void AllMotorsController::ReactToCriticalError() {
OFCLoggerRTClient::instance()->InsertCriticalError(__PRETTY_FUNCTION__,
" security heartbeat failed");
}
void AllMotorsController::UpdateActualPositions() {
for (auto motor : *mMotors) {
motor->GetPdoHandle()->getPositionActualValue(
mActualPositions->dataByType()[motor->ordinal_in_datagram]);
}
}
Error AllMotorsController::CopyActualPositionsInMessage(
EthHandler::Dataframe& tx_eth_msg) {
Error status { Error::NO_ERROR };
status = mActualPositions->get(tx_eth_msg.setData().payload.begin(),
Ethprotocol::MAX_PAYLOAD_LENGTH);
if (status == Error::NO_ERROR) {
tx_eth_msg.setData().payload_length = Ethprotocol::PayLen(
mActualPositions->getRawSize());
}
return status;
}
Error AllMotorsController::SendActualPositions() {
Error status = Error::NO_ERROR;
if (mRos_link_enabled == true) {
EthHandler::Dataframe tx_eth_msg;
PrepareMessageToRos(tx_eth_msg, ACTUAL_POSITIONS);
status = CopyActualPositionsInMessage(tx_eth_msg);
if (status == Error::ERROR) {
return Error::ERROR;
}
EthHandler::instance()->SendEthMsg(tx_eth_msg);
}
return (status);
}
Error AllMotorsController::CopyAverageVelocitiesInMessage(
EthHandler::Dataframe& tx_eth_msg) {
Error status { Error::NO_ERROR };
status = mAverageVelocities->get(tx_eth_msg.setData().payload.begin(),
Ethprotocol::MAX_PAYLOAD_LENGTH);
if (status == Error::NO_ERROR) {
tx_eth_msg.setData().payload_length = Ethprotocol::PayLen(
mAverageVelocities->getRawSize());
}
return status;
}
Error AllMotorsController::SendAverageVelocities() {
Error status { Error::NO_ERROR };
if (mRos_link_enabled == true) {
EthHandler::Dataframe tx_eth_msg;
PrepareMessageToRos(tx_eth_msg, ACTUAL_VELOCITIES);
status = CopyAverageVelocitiesInMessage(tx_eth_msg);
if (status == Error::NO_ERROR) {
status = EthHandler::instance()->SendEthMsg(tx_eth_msg);
}
}
return (status);
}
void AllMotorsController::PrepareMessageToRos(EthHandler::Dataframe& tx_eth_msg,
Ethprotocol::Cmd command) {
tx_eth_msg.clearData();
tx_eth_msg.setData().id = mDevice_id;
tx_eth_msg.setData().cmd = command;
tx_eth_msg.setData().time =
CANSyncHandler::instance()->GetTimeOfLastSyncInUs();
}
......@@ -11,19 +11,21 @@ namespace {
using namespace EMROSCmdType::AuxiliaryController;
AuxiliaryController::AuxiliaryController() :
mDevice_id(DEVICE_ID), mRos_link_enabled(false), mHeartbeat(true), mCritical_fault(
false), mMotor(
MotorManagerAux::instance()->GetMotor("MotorAuxiliaryOne")), mObserver_eth(
mDevice_id, &AuxiliaryController::EthMsgCallback, this), mObserver_msg_box(
mDevice_id, &AuxiliaryController::MsgBoxCallback, this), mObserver_msg_box_broadcast(
EMROSCmdType::BROADCAST_ID,
&AuxiliaryController::MsgBoxCallbackBroadcast, this), mObserver_cyclic_can_sync(
every_cansync_event,
&AuxiliaryController::CyclicCANSyncCallback, this), mObserver_delayed_can_sync(
period_for_reporting_actual_values_in_cansyncs,
&AuxiliaryController::SendActualPositionsCallback, this), mProfilePositionHandle(
ProfilePositionMode(this->mMotor)), mHomingModeHandle(
this->mMotor), mOperationalState(POSITIONING_STATE) {
mDevice_id(DEVICE_ID),
mRos_link_enabled(false),
mHeartbeat(true),
mCritical_fault(false),
mMotor(MotorManagerAux::instance()->GetMotor("MotorAuxiliaryOne")),
mObserver_eth(mDevice_id, &AuxiliaryController::EthMsgCallback, this),
mObserver_msg_box(mDevice_id, &AuxiliaryController::MsgBoxCallback,
this),
mObserver_msg_box_broadcast(EMROSCmdType::BROADCAST_ID,
&AuxiliaryController::MsgBoxCallbackBroadcast, this),
mObserver_cyclic_can_sync(every_cansync_event,
&AuxiliaryController::CyclicCANSyncCallback, this),
mProfilePositionHandle(ProfilePositionMode(this->mMotor)),
mHomingModeHandle(this->mMotor),
mOperationalState(POSITIONING_STATE) {
EnterPositioningState();
}
......@@ -142,24 +144,6 @@ Error AuxiliaryController::CyclicCANSyncCallback() {
return Error::NO_ERROR;
}
Error AuxiliaryController::SendActualPositionsCallback() {
Error status { Error::NO_ERROR };
if (mRos_link_enabled == true) {
EthHandler::Dataframe tx_eth_msg;
tx_eth_msg.setData().id = mDevice_id;
tx_eth_msg.setData().cmd = ACTUAL_POSITION;
tx_eth_msg.setData().time =
CANSyncHandler::instance()->GetTimeOfLastSyncInUs();
status = mProfilePositionHandle.GetActualPosition(tx_eth_msg);
if (status == Error::ERROR) {
return Error::ERROR;
}
EthHandler::instance()->SendEthMsg(tx_eth_msg);
}
return (status);
}
Error AuxiliaryController::CheckAndResetHeartbeat() {
if (mHeartbeat == true) {
mHeartbeat = false;
......
Subproject commit cad2db03b333e51e5566a78e4ca983e534b3d35b
Subproject commit 3d46583dff5a65926d39c72e74e6ffaa1c86f2b4
......@@ -15,6 +15,7 @@
#include "NanoOFC/logger/inc/ofc_logger_server.h"
#include "NanoOFC/logger/inc/ofc_client_RT.h"
#include "system/inc/msg.h"
#include "devices/inc/all_motors_controller.h"
#include "basecontroller/inc/basecontroller.h"
#include "devices/inc/auxiliary_controller.h"
#include "robotstatecontroller/inc/robotstatecontroller.h"
......@@ -66,6 +67,7 @@ void RealtimeTask(void) {
CANSyncHandler::instance()->Init(can_sync_interval_us);
Security security { };
AllMotorsController allmotorscontroller { };
Basecontroller basecontroller { };
AuxiliaryController auxiliarycontroller { };
Robotstatecontroller robotstatecontroller { };
......
......@@ -80,6 +80,6 @@ private:
Motor* mMotor;
EMROSCmdType::AuxiliaryController::TargetPositionsInterface* mTargetPositions;
EMROSCmdType::AuxiliaryController::ActualPositionsInterface* mActualPositions;
EMROSCmdType::AllMotorsController::ActualPositionsInterface* mActualPositions;
};
......@@ -110,7 +110,8 @@ modes_of_operation_specific::type Motor::GetActualModeOfOperation() {
}
bool Motor::IsMotorConfigReady() {
return (IsOperationModeConfigured() && IsAppConfigFinished());
//return (IsOperationModeConfigured() && IsAppConfigFinished()); //Only necessary for Firmware version <= FIR-v1650, because it can't change operation mode in Powerstate Operation Enabled
return (IsAppConfigFinished());
}
Error Motor::ProcessPowerStateMachine() {
......@@ -409,7 +410,7 @@ void Motor::ProcessStateEnabled() {
EnterStateLockedAfterFault();
return;
} else if (!IsMotorConfigReady()
//|| !IsEnablePowerRequested() //Only necessary for Firmware version <= FIR-v1650, but will cause voltage shutdown(except handled separate via 3212h:01h)
|| !IsEnablePowerRequested()
|| !IsActualPowerStateEqualTargetState()) {
mMotorState = SimplifiedMotorState::Disabled;
return;
......
......@@ -31,9 +31,9 @@ public:
}
void Init();
EMROSCmdType::Basecontroller::TargetVelocitiesInterface* GetTargetVelocitiesInstance();
EMROSCmdType::Basecontroller::ActualVelocitiesInterface* GetActualVelocitiesInstance();
EMROSCmdType::AllMotorsController::ActualVelocitiesInterface* GetActualVelocitiesInstance();
EMROSCmdType::AuxiliaryController::TargetPositionsInterface* GetTargetPositionsInstance();
EMROSCmdType::AuxiliaryController::ActualPositionsInterface* GetActualPositionsInstance();
EMROSCmdType::AllMotorsController::ActualPositionsInterface* GetActualPositionsInstance();
MotorStatus* GetMotorStatusInstance();
std::vector<Motor*>* GetAllMotors();
std::vector<Motor*>* GetWheelDriveMotors();
......
......@@ -78,18 +78,18 @@ Basecontroller::TargetVelocitiesInterface* InstanceFactory::GetTargetVelocitiesI
}
}
Basecontroller::ActualVelocitiesInterface* InstanceFactory::GetActualVelocitiesInstance()
AllMotorsController::ActualVelocitiesInterface* InstanceFactory::GetActualVelocitiesInstance()
{
switch (mDriveConfiguration)
{
case Robot::KindOfKinematics::TWO_WD:
return (new Basecontroller::ActualWheelVelocities2WD);
return (new AllMotorsController::ActualWheelVelocities2WD);
break;
case Robot::KindOfKinematics::TWO_WD_PLUS_AUX:
return (new Basecontroller::ActualWheelVelocities2WDplusAuxiliary);
return (new AllMotorsController::ActualWheelVelocities2WDplusAuxiliary);
break;
case Robot::KindOfKinematics::FOUR_WD:
return (new Basecontroller::ActualWheelVelocities4WD);
return (new AllMotorsController::ActualWheelVelocities4WD);
break;
case Robot::KindOfKinematics::UNDEFINED:
return (nullptr);
......@@ -123,18 +123,18 @@ AuxiliaryController::TargetPositionsInterface* InstanceFactory::GetTargetPositio
}
}
AuxiliaryController::ActualPositionsInterface* InstanceFactory::GetActualPositionsInstance()
AllMotorsController::ActualPositionsInterface* InstanceFactory::GetActualPositionsInstance()
{
switch (mDriveConfiguration)
{
case Robot::KindOfKinematics::TWO_WD:
return (new AuxiliaryController::ActualPositions2WD);
return (new AllMotorsController::ActualPositions2WD);
break;
case Robot::KindOfKinematics::TWO_WD_PLUS_AUX:
return (new AuxiliaryController::ActualPositions2WDplusAuxiliary);
return (new AllMotorsController::ActualPositions2WDplusAuxiliary);
break;
case Robot::KindOfKinematics::FOUR_WD:
return (new AuxiliaryController::ActualPositions4WD);
return (new AllMotorsController::ActualPositions4WD);
break;
case Robot::KindOfKinematics::UNDEFINED:
return (nullptr);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment