Search code examples
rosesp32freertosarduino-esp32platformio

Undefined Reference error with a defined reference in PlatformIO


I am currently implementing rosserial with an existing project but the linker is unable to find functions I defined for rosserial: "undefined reference to start_ros_com'"*, *undefined reference to publish_position'

Including other self-written files like "MotorControl" and "GlobalVariables" workers without a problem and during compiling the compiler outputs "Compiling .pio\build\esp-wrover-kit\src\RosCom.cpp.o", indicating that the file RosCom is included.

I tried hours of debugging, deleting .pio, restarting VSCode, restarting the PC and nothing changes the behaviour. ChatGPT and Phind are in a loop of are you sure that RosCom.h is in the correct folder and make sure the function is named correctly.

This is my first time using FreeRTOS, is my error maybe there?

├── platformio.ini
├── src
      └── main.cpp
      └── RosCom.cpp
      └── RosCom.h
      └── MotorControl.cpp
      └── MotorControl.h
      └── ui
            └── ui files for lvgl gui

RosCom.h gets imported in main.cpp like this:

#include "MotorControl.h"
#include "ui/ui.h"
#include "RosCom.h"

and used like this:

void ROSSerialTask(void *pvParameters) {
    start_ros_com(); // Initialize ROS communication
    for (;;) {
        // Publish current positions
        publish_position();
        vTaskDelay(pdMS_TO_TICKS(5));
    }
}

void setup() {
  Serial.begin(115200);
  delay(1000);

  xTaskCreatePinnedToCore(ROSSerialTask, "ROSSerialTask", 2048, NULL, 1, NULL, 0);

 //other functions that worked before
}

void loop() {
  lv_timer_handler(); // GUI Task Handler
  delay(1);
  vTaskDelete(NULL);
}

RosCom.h is defined as the following:

#ifndef ROSCOM_H
#define ROSCOM_H

#include <std_msgs/Int32MultiArray.h>

#ifdef __cplusplus
extern "C" {
#endif

void start_ros_com();
void receive_position(const std_msgs::Int32MultiArray& cmd_msg);
void publish_position();

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif // ROSCOM_H

And RosCom.cpp like this:

#include <ros.h>
#include <std_msgs/Int32MultiArray.h>

#include "MotorControl.h"
#include "ui/ui.h"
#include <lvgl.h>
#include "GlobalVariables.h"

bool ros_communication_working = false;

// Forward declaration of receive_position function
void receive_position(const std_msgs::Int32MultiArray& cmd_msg);

//ros node and publisher
std_msgs::Int32MultiArray actual_position_msg;

ros::Publisher pub_actualpos("actual_position", &actual_position_msg);
ros::Subscriber<std_msgs::Int32MultiArray> sub("wanted_position", receive_position);

ros::NodeHandle nh;

// Initialize ROS communication
void start_ros_com(){
    nh.initNode();
    nh.subscribe(sub);
    nh.advertise(pub_actualpos);
}

int wanted_position[2];

// Receiving wanted positions
void receive_position(const std_msgs::Int32MultiArray& cmd_msg){
    if (cmd_msg.data_length == 2) { // Assuming you're expecting a pair of positions
        wanted_position[0] = cmd_msg.data[0];
        wanted_position[1] = cmd_msg.data[1];
        move_motors();
    } else {
        Serial.println("Invalid data received for wanted positions.");
    }
}

// Publish current positions
void publish_position(){
    actual_position_msg.data_length = 2; // Assuming you're publishing a pair of positions
    actual_position_msg.data[0] = current_position[0];
    actual_position_msg.data[1] = current_position[1];
    pub_actualpos.publish(&actual_position_msg);
    nh.spinOnce();

    //ros_communication_working = nh.connected();
    if (ros_communication_working) {
        lv_obj_add_state(ui_roscomcheckbox, LV_STATE_CHECKED);
        Serial.println("ROSCOM Working");
    } else {
        lv_obj_clear_state(ui_roscomcheckbox, LV_STATE_CHECKED);
        Serial.println("ROSCOM NOT Working");
    }
}

platformio.ini:

[env:esp-wrover-kit]
platform = espressif32
board = esp-wrover-kit
framework = arduino
monitor_port = /dev/ttyUSB*
monitor_speed = 115200
lib_deps = 
    teemuatlut/TMCStepper@^0.7.3
    gin66/FastAccelStepper@^0.28.3
    lovyan03/LovyanGFX@^0.4.14
    lvgl/lvgl@^8.3.6
    frankjoshua/Rosserial Arduino Library@^0.9.1
    khoek/libesp @ ^2.3.0

upload_speed = 921600
build_flags = 
    -DBOARD_HAS_PSRAM
    -mfix-esp32-psram-cache-issue
    -DLV_CONF_INCLUDE_SIMPLE
    -D LV_COMP_CONF_INCLUDE_SIMPLE
    -I src/
    -I src/ui


Solution

  • Your file RosCom.h has this code in it:

    #ifdef __cplusplus
    extern "C" {
    #endif
    
    void start_ros_com();
    void receive_position(const std_msgs::Int32MultiArray& cmd_msg);
    void publish_position();
    
    #ifdef __cplusplus
    } /* extern "C" */
    #endif
    

    That tells the compiler to treat start_ros_com() as C rather than C++.

    You then define start_ros_com() in C++ rather than C - it's in RosCom.cpp not RosCom.c, so when the compiler compiles that file it will treat it as C++ code.

    C and C++ represent their symbol names differently. No start_ros_com() C function was ever defined, so you get the error you're seeing.

    You need to be consistent about whether a function is C or C++.

    The fix is simple, don't declare the function as C code if you're not going to compile it as C code

    void start_ros_com();
    void receive_position(const std_msgs::Int32MultiArray& cmd_msg);
    void publish_position();