I am building firmware for a project at university and currently want to clean up the code in a way, that the main.cpp file is very lightweight. I thus shift most code into headers and cpp files, which I include. So far everything worked (with some minor bumps on the way) but right on the last leg I get errors telling me methods of a class from a library I use have multiple definitions…
Error Message:
.pio\build\teensy41\lib3d6\librobotStateMachine.a(robotStateMachine.cpp.o): In function `StateMachine::~StateMachine()':
robotStateMachine.cpp:(.text._ZN12StateMachineD2Ev+0x0): multiple definition of `StateMachine::~StateMachine()'
.pio\build\teensy41\src\main.cpp.o:main.cpp:(.text._ZN12StateMachineD2Ev+0x0): first defined here
c:/users/lelem/.platformio/packages/toolchain-gccarmnoneeabi/bin/../lib/gcc/arm-none-eabi/5.4.1/../../../../arm-none-eabi/bin/ld.exe: Disabling relaxation: it will not work with multiple definitions
.pio\build\teensy41\lib3d6\librobotStateMachine.a(robotStateMachine.cpp.o): In function `StateMachine::~StateMachine()':
robotStateMachine.cpp:(.text._ZN12StateMachineD2Ev+0x0): multiple definition of `StateMachine::~StateMachine()'
.pio\build\teensy41\src\main.cpp.o:main.cpp:(.text._ZN12StateMachineD2Ev+0x0): first defined here
.pio\build\teensy41\lib3d6\librobotStateMachine.a(robotStateMachine.cpp.o): In function `State::State()':
robotStateMachine.cpp:(.text._ZN5StateC2Ev+0x0): multiple definition of `State::State()'
.pio\build\teensy41\src\main.cpp.o:main.cpp:(.text._ZN5StateC2Ev+0x0): first defined here
.pio\build\teensy41\lib3d6\librobotStateMachine.a(robotStateMachine.cpp.o): In function `State::State()':
robotStateMachine.cpp:(.text._ZN5StateC2Ev+0x0): multiple definition of `State::State()'
.pio\build\teensy41\src\main.cpp.o:main.cpp:(.text._ZN5StateC2Ev+0x0): first defined here
.pio\build\teensy41\lib3d6\librobotStateMachine.a(robotStateMachine.cpp.o): In function `State::~State()':
robotStateMachine.cpp:(.text._ZN5StateD2Ev+0x0): multiple definition of `State::~State()'
.pio\build\teensy41\src\main.cpp.o:main.cpp:(.text._ZN5StateD2Ev+0x0): first defined here
.pio\build\teensy41\lib3d6\librobotStateMachine.a(robotStateMachine.cpp.o): In function `State::~State()':
robotStateMachine.cpp:(.text._ZN5StateD2Ev+0x0): multiple definition of `State::~State()'
.pio\build\teensy41\src\main.cpp.o:main.cpp:(.text._ZN5StateD2Ev+0x0): first defined here
.pio\build\teensy41\lib3d6\librobotStateMachine.a(robotStateMachine.cpp.o): In function `State::addTransition(bool (*)(), State*)':
robotStateMachine.cpp:(.text._ZN5State13addTransitionEPFbvEPS_+0x0): multiple definition of `State::addTransition(bool (*)(), State*)'
.pio\build\teensy41\src\main.cpp.o:main.cpp:(.text._ZN5State13addTransitionEPFbvEPS_+0x0): first defined here
.pio\build\teensy41\lib3d6\librobotStateMachine.a(robotStateMachine.cpp.o): In function `State::addTransition(bool (*)(), int)':
robotStateMachine.cpp:(.text._ZN5State13addTransitionEPFbvEi+0x0): multiple definition of `State::addTransition(bool (*)(), int)'
.pio\build\teensy41\src\main.cpp.o:main.cpp:(.text._ZN5State13addTransitionEPFbvEi+0x0): first defined here
.pio\build\teensy41\lib3d6\librobotStateMachine.a(robotStateMachine.cpp.o): In function `State::evalTransitions()':
robotStateMachine.cpp:(.text._ZN5State15evalTransitionsEv+0x0): multiple definition of `State::evalTransitions()'
.pio\build\teensy41\src\main.cpp.o:main.cpp:(.text._ZN5State15evalTransitionsEv+0x0): first defined here
.pio\build\teensy41\lib3d6\librobotStateMachine.a(robotStateMachine.cpp.o): In function `State::execute()':
robotStateMachine.cpp:(.text._ZN5State7executeEv+0x0): multiple definition of `State::execute()'
.pio\build\teensy41\src\main.cpp.o:main.cpp:(.text._ZN5State7executeEv+0x0): first defined here
.pio\build\teensy41\lib3d6\librobotStateMachine.a(robotStateMachine.cpp.o): In function `State::setTransition(int, int)':
robotStateMachine.cpp:(.text._ZN5State13setTransitionEii+0x0): multiple definition of `State::setTransition(int, int)'
.pio\build\teensy41\src\main.cpp.o:main.cpp:(.text._ZN5State13setTransitionEii+0x0): first defined here
.pio\build\teensy41\lib3d6\librobotStateMachine.a(robotStateMachine.cpp.o): In function `StateMachine::StateMachine()':
robotStateMachine.cpp:(.text._ZN12StateMachineC2Ev+0x0): multiple definition of `StateMachine::StateMachine()'
.pio\build\teensy41\src\main.cpp.o:main.cpp:(.text._ZN12StateMachineC2Ev+0x0): first defined here
.pio\build\teensy41\lib3d6\librobotStateMachine.a(robotStateMachine.cpp.o): In function `StateMachine::StateMachine()':
robotStateMachine.cpp:(.text._ZN12StateMachineC2Ev+0x0): multiple definition of `StateMachine::StateMachine()'
.pio\build\teensy41\src\main.cpp.o:main.cpp:(.text._ZN12StateMachineC2Ev+0x0): first defined here
.pio\build\teensy41\lib3d6\librobotStateMachine.a(robotStateMachine.cpp.o): In function `StateMachine::run()':
robotStateMachine.cpp:(.text._ZN12StateMachine3runEv+0x0): multiple definition of `StateMachine::run()'
.pio\build\teensy41\src\main.cpp.o:main.cpp:(.text._ZN12StateMachine3runEv+0x0): first defined here
.pio\build\teensy41\lib3d6\librobotStateMachine.a(robotStateMachine.cpp.o): In function `StateMachine::addState(void (*)())':
robotStateMachine.cpp:(.text._ZN12StateMachine8addStateEPFvvE+0x0): multiple definition of `StateMachine::addState(void (*)())'
.pio\build\teensy41\src\main.cpp.o:main.cpp:(.text._ZN12StateMachine8addStateEPFvvE+0x0): first defined here
.pio\build\teensy41\lib3d6\librobotStateMachine.a(robotStateMachine.cpp.o): In function `StateMachine::transitionTo(State*)':
robotStateMachine.cpp:(.text._ZN12StateMachine12transitionToEP5State+0x0): multiple definition of `StateMachine::transitionTo(State*)'
.pio\build\teensy41\src\main.cpp.o:main.cpp:(.text._ZN12StateMachine12transitionToEP5State+0x0): first defined here
.pio\build\teensy41\lib3d6\librobotStateMachine.a(robotStateMachine.cpp.o): In function `StateMachine::transitionTo(int)':
robotStateMachine.cpp:(.text._ZN12StateMachine12transitionToEi+0x0): multiple definition of `StateMachine::transitionTo(int)'
.pio\build\teensy41\src\main.cpp.o:main.cpp:(.text._ZN12StateMachine12transitionToEi+0x0): first defined here
main.cpp
#include <Arduino.h>
#include <robotStateMachine.h>
void emergencyStop()
{
lcl.recordingbutton = 0;
robotStateMachine.transitionTo(SafeState);
return;
}
/// @brief setup function to be run once
void setup()
{
// Serial.begin(115200); // this seems to be done in lcl already..
Serial.println("Setting up buttons");
setupButtons();
pinMode(ON_OFF_BUTTON, INPUT_PULLDOWN);
attachInterrupt(digitalPinToInterrupt(ON_OFF_BUTTON), emergencyStop, RISING);
SetupSerialCommands();
robotStateMachine.transitionTo(Idle);
statusLED.begin();
statusLEDShineFullColorCode(COLOR_OFF);
Serial.println("Setup complete");
}
void loop()
{
loopButtons();
robotCommands.ReadSerial();
robotStateMachine.run();
// delay(10);
}
robotStateMachine.h
#ifndef STATE_MACHINE_H_GUARD
#define STATE_MACHINE_H_GUARD
#include <robotCommands.h>
#include <robotButtons.h>
#include <robotStatusLED.h>
#include <stateMachine.h>
/**
* @brief robotStateMachine declaration
*/
extern StateMachine robotStateMachine;
/**
* @defgroup robotStates States for the robot
*
* @{
*/
extern State* Idle;
extern State* SafeState;
extern State* Recording;
extern State* ProcessRecording;
extern State* Play;
extern State* DirectControl;
extern State* SerialComm;
/// @}
/**
* @defgroup robotStateLogic Functions to the states
*
* @{
*/
void idleLogic();
void safeStateLogic();
void recordingLogic();
void processRecordingLogic();
void playLogic();
void directControlLogic();
void serialCommLogic();
/// @}
/**
* @defgroup robotStateTransition transition functions to the states
*
* @{
*/
bool transitionIdleRecord();
bool transitionIdlePlay();
bool transitionIdleDirectControl();
bool transitionPlayIdle();
bool transitionRecordProcessRecording();
bool transitionProcessRecordingIdle();
bool transitionDirectControlIdle();
bool transitionSafeStateIdle();
/// @}
void setupTransitions();
#endif
robotStateMachine.cpp
#include <robotStateMachine.h>
StateMachine robotStateMachine;
void idleLogic() {
if(robotStateMachine.executeOnce) {
statusLEDShineFullColorCode(COLOR_GREEN);
Serial.println("Idle");
}
if ((millis() % 5000 < 5 || millis() % 5000 > 4995)) {
lcl.lclServoBus.getServoPositions();
for (int k = 0; k < lcl.lclServoBus.busServoCount; k++) {
Serial.print("Servo ");
Serial.print(lcl.lclServoBus.servoIDs[k]);
Serial.print(" at position: ");
Serial.println(lcl.lclServoBus.servoPositions[k]);
}
}
}
void safeStateLogic() {
if(robotStateMachine.executeOnce) {
statusLEDShineFullColorCode(COLOR_RED);
Serial.println("SafeState");
}
lcl.lclServoBus.EnableTorque(0xFE, 0);
}
void recordingLogic(){
unsigned long timeStartRecording = 0;
if(robotStateMachine.executeOnce) {
statusLEDShineFullColorCode(COLOR_ORANGE);
lcl.lclServoBus.EnableTorque(SERVOBROADCAST, 0);
lcl.iteration = 0;
Serial.println("Recording");
// Header for Table output over Serial
Serial.print("Time_ms");
for (int k = 0; k < lcl.lclServoBus.busServoCount; k++) {
Serial.print(";Pos_Servo_");
Serial.print(lcl.lclServoBus.servoIDs[k]);
Serial.print(";Speed_Servo_");
Serial.print(lcl.lclServoBus.servoIDs[k]);
}
Serial.print("; timeArray");
Serial.println();
timeStartRecording = millis();
}
lcl.timluethrecord(timeStartRecording);
}
void processRecordingLogic() {
if(robotStateMachine.executeOnce) {
Serial.println("Processing Recording");
statusLEDShineFullColorCode(COLOR_TUM_DARKBLUE);
}
lcl.processPositions(); /// FIXME: actually this is the transition function as well... so we will have done the processPostions two times
}
void playLogic() {
if(robotStateMachine.executeOnce) {
lcl.playIteration = 0;
Serial.println("Play");
Serial.print(lcl.iteration);
Serial.println(" will be played");
}
lcl.playProgram();
}
void directControlLogic() {
if (robotStateMachine.executeOnce) {
Serial.println("Direct control");
statusLEDShineFullColorCode(COLOR_CYAN);
}
for (int k = 0; k < NUMBEROFPOSITIONS; k++) {
for (int n = 0; n < NUMBEROFSERVOS; n++) {
lcl.lclServoBus.WritePosEx(lcl.lclServoBus.servoIDs[n], directControlPositionList[k][n], directControlVelocityList[k][n]); //directControlAccelerationList[k][n]
}
while (lcl.lclServoBus.isAnyMoving()) {}
}
}
void serialCommLogic();
bool transitionIdleRecord() {
return recordButton.isPressed();
}
bool transitionIdlePlay() {
return playButton.isPressed();
}
bool transitionIdleDirectControl() {
return playButton.isPressed() && recordButton.isPressed();
}
bool transitionPlayIdle() {
return lcl.iteration == lcl.playIteration;
}
bool transitionRecordProcessRecording() {
return lcl.recordingbutton == 0;
}
bool transitionProcessRecordingIdle() {
return lcl.processPositions();
}
bool transitionDirectControlIdle() {
return playButton.isPressed() || playButton.isPressed();
}
bool transitionSafeStateIdle() {
return digitalRead(ON_OFF_BUTTON) == HIGH;
};
State* Idle = robotStateMachine.addState(&idleLogic);
State* SafeState = robotStateMachine.addState(&safeStateLogic);
State* Recording = robotStateMachine.addState(&recordingLogic);
State* ProcessRecording = robotStateMachine.addState(&processRecordingLogic);
State* Play = robotStateMachine.addState(&playLogic);
State* DirectControl = robotStateMachine.addState(&directControlLogic);
void setupTransitions() {
Idle->addTransition(&transitionIdlePlay,Play);
Idle->addTransition(&transitionIdleRecord,Recording);Idle->addTransition(&transitionIdleDirectControl,DirectControl);
SafeState->addTransition(&transitionSafeStateIdle,Idle);
Recording->addTransition(&transitionRecordProcessRecording, ProcessRecording);
ProcessRecording->addTransition(&transitionProcessRecordingIdle, Idle);
Play->addTransition(&transitionPlayIdle, Idle);
DirectControl->addTransition(&transitionDirectControlIdle, Idle);
}
I am very confused, as I don’t do any definition on class methods nor even use the deconstructor of StateMachine
class…
I am kind of unsure about this line StateMachine robotStateMachine;
in robotStateMachine.cpp
as the library “documentation” uses StateMachine robotStateMachine = StateMachine();
instead… I get the same error, however then there also is a multiple definition error for the StateMachine
constructor.