osrf / ros2_serial_example

72 stars 16 forks source link

problem with building any packages with ros2 foxy #78

Closed masoudir closed 3 years ago

masoudir commented 3 years ago

Problem

I am trying to build ros2_serial bridge you provided with ros2 foxy. But it does not build for any packages like std_msgs, geometry_msgs , ... What is the problem?

Error log

    colcon build --cmake-args -DROS2_SERIAL_PKGS="std_msgs"
    Starting >>> ros2_serial_msgs
    --- stderr: ros2_serial_msgs                              
    CMake Warning:
      Manually-specified variables were not used by the project:

        ROS2_SERIAL_PKGS

    ---
    Finished <<< ros2_serial_msgs [1.56s]
    Starting >>> ros2_serial_example
    --- stderr: ros2_serial_example                             
    /home/a/softwares/ros2_serial/src/ros2_serial_example/ros2_serial_example/src/dummy_udp.cpp:30:10: fatal error: ros2_serial_msgs/msg/serial_mapping__rosidl_typesupport_fastrtps_cpp.hpp: No such file or directory
       30 | #include "ros2_serial_msgs/msg/serial_mapping__rosidl_typesupport_fastrtps_cpp.hpp"
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    compilation terminated.
    make[2]: *** [CMakeFiles/dummy_udp.dir/build.make:63: CMakeFiles/dummy_udp.dir/src/dummy_udp.cpp.o] Error 1
    make[2]: *** Waiting for unfinished jobs....
    /home/a/softwares/ros2_serial/src/ros2_serial_example/ros2_serial_example/src/dummy_serial.cpp:30:10: fatal error: ros2_serial_msgs/msg/serial_mapping__rosidl_typesupport_fastrtps_cpp.hpp: No such file or directory
       30 | #include "ros2_serial_msgs/msg/serial_mapping__rosidl_typesupport_fastrtps_cpp.hpp"
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    compilation terminated.
    make[2]: *** [CMakeFiles/dummy_serial.dir/build.make:63: CMakeFiles/dummy_serial.dir/src/dummy_serial.cpp.o] Error 1
    make[1]: *** [CMakeFiles/Makefile2:369: CMakeFiles/dummy_serial.dir/all] Error 2
    make[1]: *** Waiting for unfinished jobs....
    /home/a/softwares/ros2_serial/build/ros2_serial_example/std_msgs_int8_pub_sub_type.cpp:24:10: fatal error: std_msgs/msg/int8__rosidl_typesupport_fastrtps_cpp.hpp: No such file or directory
       24 | #include <std_msgs/msg/int8__rosidl_typesupport_fastrtps_cpp.hpp>
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    compilation terminated.
    make[2]: *** [CMakeFiles/bridge_gen.dir/build.make:250: CMakeFiles/bridge_gen.dir/std_msgs_int8_pub_sub_type.cpp.o] Error 1
    make[2]: *** Waiting for unfinished jobs....
    /home/a/softwares/ros2_serial/build/ros2_serial_example/std_msgs_int64_pub_sub_type.cpp:24:10: fatal error: std_msgs/msg/int64__rosidl_typesupport_fastrtps_cpp.hpp: No such file or directory
       24 | #include <std_msgs/msg/int64__rosidl_typesupport_fastrtps_cpp.hpp>
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    compilation terminated.
    make[2]: *** [CMakeFiles/bridge_gen.dir/build.make:263: CMakeFiles/bridge_gen.dir/std_msgs_int64_pub_sub_type.cpp.o] Error 1
    /home/a/softwares/ros2_serial/build/ros2_serial_example/std_msgs_u_int32_multi_array_pub_sub_type.cpp:24:10: fatal error: std_msgs/msg/u_int32_multi_array__rosidl_typesupport_fastrtps_cpp.hpp: No such file or directory
       24 | #include <std_msgs/msg/u_int32_multi_array__rosidl_typesupport_fastrtps_cpp.hpp>
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    compilation terminated.
    make[2]: *** [CMakeFiles/bridge_gen.dir/build.make:276: CMakeFiles/bridge_gen.dir/std_msgs_u_int32_multi_array_pub_sub_type.cpp.o] Error 1
    make[1]: *** [CMakeFiles/Makefile2:198: CMakeFiles/bridge_gen.dir/all] Error 2
    make[1]: *** [CMakeFiles/Makefile2:282: CMakeFiles/dummy_udp.dir/all] Error 2
    make: *** [Makefile:141: all] Error 2
    ---
    Failed   <<< ros2_serial_example [2.04s, exited with code 2]

    Summary: 1 package finished [3.76s]
      1 package failed: ros2_serial_example
      2 packages had stderr output: ros2_serial_example ros2_serial_msgs
clalancette commented 3 years ago

In short, we've never tested on Foxy; the last time I looked at this was in Dashing days. However, see #79 which should make it compile on Foxy.

clalancette commented 3 years ago

This was fixed by #79, so closing.

huak95 commented 3 years ago

Hi @masoudir . I wonder that you can build the ros2_serial_example package or not? I got the error when building it. thank.

masoudir commented 3 years ago

Hi @huak95 , I am not sure, as I remember I have built it in foxy using the help of #79. But that was a couple of months ago and I do not remember it exactly.

But you can simply use the uros arduino library to transfer your messages easily. I have not used ros2_serial_example repo. link.

huak95 commented 3 years ago

@masoudir I have Arduino mega 2560 board that is not support for that micro-ROS for Arduino library. So, what should I need to do for using ROS2 with Arduino.

  1. Buy new MCU Board, plz you recommend for me.
  2. Finding other library for ROS2 and Arduino Communicate.
  3. Or other method Thank you.
masoudir commented 3 years ago

I have used uros library for other not supported microcontrollers, using the static library using this link. But that is a little complicated for absolute beginners. But if you was successful for building that static library, you can use it for your project. But remember that this static library can be used in a project with similar configuration as you have used for Cmake in building uros.

I have done that for STM32G474 arduino framework using Platformio IDE.

I recommend you to search another git issue to find your exact solution, or if there are not any issues related to your problem, create a new one for this repo.

Sorry, I did not work with AVR for uros libraries and I have not the exact solution for you.

jonathanTIE commented 3 years ago

@huak95 I'm also looking for a ros2 library to use serial and I don't find any that are satisfying and lightweight enough. I think it'll be easier to make your own ros2 node that receive the messages for the arduino, read the message and send the useful data to the arduino using serial (like pyserial) , and vice versa in the other side. If you're beggining, learn to communicate in serial between your computer and arduino, then learn how to make a basic ros2 node and then combine the two!

huak95 commented 3 years ago

@jonathanTIE I have try create new node with PySerial to received Serial.print from arduino but it's working very slow. If I send the spin message faster than 1 second the arduino mega can't received the serial data from PySerial.

Here is my code for Arduino

// check if data is available
  if (Serial.available() > 0) {
    // read the incoming string:
    incomingString = Serial.readString();
}
    int str_len = incomingString.length() + 1;
    char char_array[str_len];
    incomingString.toCharArray(char_array, str_len);

    pch = strtok(char_array,",");
    Serial.print("cmd_vel:");
    int i = 0;
    while(pch != NULL)
    {
        cmd_vel[i] = String(pch).toDouble();
        Serial.print(" ");
        Serial.print(cmd_vel[i]);
        pch = strtok(NULL, ","); 
        i = i+1;
    }
    Serial.println("");    

Here is my code for PySerial and ROS2

#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
import serial
import time

ser = serial.Serial('/dev/ttyUSB1', 115200, timeout=0.1)
r = 1

class Connect_Arduino_Node(Node):

    def __init__(self):
        super().__init__("Connect_Arduino_Node")
        self.counter_ = 0
        self.get_logger().info("Hello ROS2")

        # self.create_timer(0.5, self.arduino_callback) # this can't work
        self.create_timer(0.1, self.arduino_callback) # this can work

    def arduino_callback(self):
        vel_x = -3.0
        vel_th = 0.0
        self.value_ = self.write_read(vel_x, vel_th)
        self.get_logger().info("read "+str(self.value_)) 

    def write_read(self, vel_x, vel_th):
        global r, ser
        print("I am writing!" + " vel_x:" + str(vel_x) + " vel_th:" + str(vel_th))
        x = str(r * vel_x) +","+ str(vel_th) +"\n"
        ser.write(bytes(x,'utf-8'))
        time.sleep(0.02)
        data = ser.readline()
        txt = str(data).split(",")
        r = r * -1
        return (txt[1:])

I don't know how to make it a better ROS2 communication with Arduino. May I code something wrong. Please help. Thank you.

jonathanTIE commented 3 years ago

@huak95

The first parameter of self.create_timer is the interval between every call, so if 0.1 work fast enough, 0.5 should work too. The problem is on the arduino side, the function Serial.readString(), if you don't set the Serial.setTimeout(), waits by default for 1s before executing the code. The readString waits like a sleep(1). The same problem on the pyserial side is present, the timeout is too high on the ser, it waits 0.1 s when you read the serial, so you can't read more than 10 times per second. So for the arduino side, you can reduce the timeout, but personally I prefer to read the serial port using read, to avoid hanging the program for a few ms everytime, like so :

char buffer[50];
int buff_index=0;
    void update() {
        int a;
        a = SerialCtrl.available();

        if (a) {

            for (int k=0;k<a;k++) {
                char c=SerialCtrl.read();
                //serialCtrl.write(c);
                if (c=='\n'){

                   buffer[buff_index]='\0';
                   parse_data(); //function that will read the buffer variable
                   buff_index=0;

                }
                else if (c=='\r') {}
                else {
                    buffer[buff_index]=c;
                    buff_index++;
                }
            }
        }

It's unrelated with the issue, if you want you can contact me by mail or by discord if you have other questions !

chrisalbertson commented 3 years ago

On top of what is already said, the Arduino code makes a bad assumption. It assumes that if any serial data is available then the entire line of text is available. Statistically this assumption will be true much of the time but not always.

What if you check for data just after the first character of the line is written? This will happen one in athousand times and then the system stops working What if on poer up the Arduino stars after the line is half written?

The correct solution is to accumulate characters one at a time until the "/n" is found. An improved solution uses a "start" character, perhaps a "$" at the start of each line, then you reader waits until it reads a "$". Even better is to place a checksum in the line and ignore lines that have a wrong checksum.

So, on the arduino.. waitfor data to be available, if so read a character. Is the character s "$"? If not ignore the data.

Finally we see a start sign "$", so now we read until we see "/n"

Process the line, including the checksum, if the checksum is bad ignore the line if OK then save the data.

One other idea, reading charagters and convertingthem to floating point is expensive on an arduino. Why not send them as binary data?

On Thu, Aug 19, 2021 at 5:23 AM jonathanTIE @.***> wrote:

@huak95 https://github.com/huak95

The first parameter of self.create_timer is the interval between every call, so if 0.1 work fast enough, 0.5 should work too. The problem is on the arduino side, the function Serial.readString(), if you don't set the Serial.setTimeout(), waits by default for 1s before executing the code. The readString waits like a sleep(1). The same problem on the pyserial side is present, the timeout is too high on the ser, it waits 0.1 s when you read the serial, so you can't read more than 10 times per second. So for the arduino side, you can reduce the timeout, but personally I prefer to read the serial port using read, to avoid hanging the program for a few ms everytime, like so :

char buffer[50]; int buff_index=0; void update() { int a; a = SerialCtrl.available();

    if (a) {

        for (int k=0;k<a;k++) {
            char c=SerialCtrl.read();
            //serialCtrl.write(c);
            if (c=='\n'){

               buffer[buff_index]='\0';
               parse_data(); //function that will read the buffer variable
               buff_index=0;

            }
            else if (c=='\r') {}
            else {
                buffer[buff_index]=c;
                buff_index++;
            }
        }
    }

It's unrelated with the issue, if you want you can contact me by mail or by discord if you have other questions !

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/osrf/ros2_serial_example/issues/78#issuecomment-901870294, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABQKNRUO73WIIUU7EEAZS5TT5TZUFANCNFSM4YLPBCIQ . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&utm_campaign=notification-email .

--

Chris Albertson Redondo Beach, California