从USB阅读到一个特殊的角色;与Ubuntu和Arduino

发布于 2025-01-27 17:22:41 字数 4801 浏览 2 评论 0原文

我有一个Arduino代码,该代码输出来自USB上某些传感器的字符串。 这些是字符串:

Sensor 1 F1 410nm : 0 F2 435nm : 290 F3 445nm : 0 F4 460nm : 211 F5 480nm : 0 F6 515nm : 0 F7 535nm : 262 F8 555nm : 0 F9 590nm : 0 F10 610nm : 263 F11 630nm : 0 F12 645nm : 262 F13 680nm : 0 F14 715nm : 181 F15 730nm : 201 F16 780nm : 0 F17  860nm  : 262 F18 940nm : 211;
Sensor 0 F1 410nm : 0 F2 435nm : 171 F3 445nm : 0 F4 460nm : 213 F5 480nm : 0 F6 515nm : 0 F7 535nm : 228 F8 555nm : 0 F9 590nm : 0 F10 610nm : 150 F11 630nm : 0 F12 645nm : 200 F13 680nm : 0 F14 715nm : 159 F15 730nm : 204 F16 780nm : 0 F17  860nm  : 213 F18 940nm : 228;

每个字符串都是由字符“”终止的。

现在,我编写了一个简单的C ++程序,该程序在Ubuntu上运行,并从串行和输出数据中读取。 Arduino通过USB连接到我必须运行C/C ++程序的计算机。 问题在于它打印字符是它们到达和随机的,例如:

传感器0 F1 410nm:0 F2 435nm:272 F3 445nm:[INFO] [1652193464.896782509]:传感器0 F1 410NM:0 F1 410NM:0 F2 435nm:272 F3 4445nm:272 F3 4445nm: 0 F4 460NM:178 F5 480NM:0 F6 515NM:0 F7 53 [INFO] [1652193464.900888273]:0 F4 460NM:178 F5 480NM:0 5nm:298 F8 555nm:0 F9 590nm:0 F10 610nm:170 F11 630nm:0 F12 645nm:237 F13 680NM:0 F14 715NM:297 F15 730NM:289 F16 F16 780NM:0 F17NM:0 F17 860NM:0 7860NM:0 78 MENM:0 78.860NM:0 78;

虽然我想阅读所有字符,直到“”;然后打印完整的字符串。

我该如何以明智的方式做到这一点?

我还可以通过在每个字符串之前添加一个字符来格式化arduino的字符串,例如:

:String1_with_values;

为了知道字符串何时启动以及何时完成。 您认为这将是改进它的好解决方案吗?

这是我当前的完整代码:

#include "ros/ros.h"
#include "std_msgs/String.h"
// C library headers
#include <iostream> 
#include <stdio.h>
#include <string.h>

// Linux headers
#include <fcntl.h> // Contains file controls like O_RDWR
#include <errno.h> // Error integer and strerror() function
#include <termios.h> // Contains POSIX terminal control definitions
#include <unistd.h> // write(), read(), close()

int main(int argc,char **argv) {

 ros::init(argc, argv, "talker");
 ros::NodeHandle n;
 ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);

  ros::Rate loop_rate(10);

  // Open the serial port. Change device path as needed (currently set to an standard FTDI USB-UART cable type device)
  int serial_port = open("/dev/ttyACM0", O_RDWR);

  // Create new termios struc, we call it 'tty' for convention
  struct termios tty;

  // Read in existing settings, and handle any error
  if(tcgetattr(serial_port, &tty) != 0) {
      printf("Error %i from tcgetattr: %s\n", errno, strerror(errno));
      return 1;
  }

  tty.c_cflag &= ~PARENB; // Clear parity bit, disabling parity (most common)
  tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication (most common)
  tty.c_cflag &= ~CSIZE; // Clear all bits that set the data size 
  tty.c_cflag |= CS8; // 8 bits per byte (most common)
  tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control (most common)
  tty.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1)

  tty.c_lflag &= ~ICANON;
  tty.c_lflag &= ~ECHO; // Disable echo
  tty.c_lflag &= ~ECHOE; // Disable erasure
  tty.c_lflag &= ~ECHONL; // Disable new-line echo
  tty.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP
  tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl
  tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); // Disable any special handling of received bytes

  tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars)
  tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed
  // tty.c_oflag &= ~OXTABS; // Prevent conversion of tabs to spaces (NOT PRESENT ON LINUX)
  // tty.c_oflag &= ~ONOEOT; // Prevent removal of C-d chars (0x004) in output (NOT PRESENT ON LINUX)

  tty.c_cc[VTIME] = 10;    // Wait for up to 1s (10 deciseconds), returning as soon as any data is received.
  tty.c_cc[VMIN] = 0;

  // Set in/out baud rate to be 9600
  cfsetispeed(&tty, B115200);
  cfsetospeed(&tty, B115200);

  // Save tty settings, also checking for error
  if (tcsetattr(serial_port, TCSANOW, &tty) != 0) {
      printf("Error %i from tcsetattr: %s\n", errno, strerror(errno));
      return 1;
  }
unsigned char read_buf[800];
int count = 0;
 while (ros::ok())
  {
    int n = read(serial_port, read_buf, sizeof(read_buf) - 1);
    if (n < 0) {
        /* handle errno condition */
        return -1;
    }
    read_buf[n] = '\0';
    std::cout << read_buf ;

std_msgs::String msg;

    std::stringstream ss;
    ss << read_buf;
    msg.data = ss.str();

    ROS_INFO("%s", msg.data.c_str());

    chatter_pub.publish(msg);

    ros::spinOnce();

    loop_rate.sleep();
    ++count;

}

  close(serial_port);
  return 0; // success
}

I have an Arduino code that outputs strings coming from some sensors over the USB.
These are the strings:

Sensor 1 F1 410nm : 0 F2 435nm : 290 F3 445nm : 0 F4 460nm : 211 F5 480nm : 0 F6 515nm : 0 F7 535nm : 262 F8 555nm : 0 F9 590nm : 0 F10 610nm : 263 F11 630nm : 0 F12 645nm : 262 F13 680nm : 0 F14 715nm : 181 F15 730nm : 201 F16 780nm : 0 F17  860nm  : 262 F18 940nm : 211;
Sensor 0 F1 410nm : 0 F2 435nm : 171 F3 445nm : 0 F4 460nm : 213 F5 480nm : 0 F6 515nm : 0 F7 535nm : 228 F8 555nm : 0 F9 590nm : 0 F10 610nm : 150 F11 630nm : 0 F12 645nm : 200 F13 680nm : 0 F14 715nm : 159 F15 730nm : 204 F16 780nm : 0 F17  860nm  : 213 F18 940nm : 228;

Each string is terminated by the character ";".

Now, I wrote a simple C++ program that runs on Ubuntu and reads from serial and outputs data.
Arduino is connected via USB to the computer where I have to run the C/C++ program.
The problem is that it prints characters are they arrive and randomly, like this:

Sensor 0 F1 410nm : 0 F2 435nm : 272 F3 445nm : [ INFO] [1652193464.896782509]: Sensor 0 F1 410nm : 0 F2 435nm : 272 F3 445nm :
0 F4 460nm : 178 F5 480nm : 0 F6 515nm : 0 F7 53[ INFO] [1652193464.900888273]: 0 F4 460nm : 178 F5 480nm : 0 F6 515nm : 0 F7 53
5nm : 298 F8 555nm : 0 F9 590nm : 0 F10 610nm : 170 F11 630nm : 0 F12 645nm : 237 F13 680nm : 0 F14 715nm : 297 F15 730nm : 289 F16 780nm : 0 F17 860nm : 178 F18 940nm : 298;

while I would like to read all the characters till the ";" and then print the full string.

How can I do this in a smart way?

I can also format the string from Arduino by adding a character before each string, for example:

:String1_with_values;

in order to be able to know when the string starts and when it finishes.
Do you think it would be a good solution to improve it?

This is my current full code:

#include "ros/ros.h"
#include "std_msgs/String.h"
// C library headers
#include <iostream> 
#include <stdio.h>
#include <string.h>

// Linux headers
#include <fcntl.h> // Contains file controls like O_RDWR
#include <errno.h> // Error integer and strerror() function
#include <termios.h> // Contains POSIX terminal control definitions
#include <unistd.h> // write(), read(), close()

int main(int argc,char **argv) {

 ros::init(argc, argv, "talker");
 ros::NodeHandle n;
 ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);

  ros::Rate loop_rate(10);

  // Open the serial port. Change device path as needed (currently set to an standard FTDI USB-UART cable type device)
  int serial_port = open("/dev/ttyACM0", O_RDWR);

  // Create new termios struc, we call it 'tty' for convention
  struct termios tty;

  // Read in existing settings, and handle any error
  if(tcgetattr(serial_port, &tty) != 0) {
      printf("Error %i from tcgetattr: %s\n", errno, strerror(errno));
      return 1;
  }

  tty.c_cflag &= ~PARENB; // Clear parity bit, disabling parity (most common)
  tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication (most common)
  tty.c_cflag &= ~CSIZE; // Clear all bits that set the data size 
  tty.c_cflag |= CS8; // 8 bits per byte (most common)
  tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control (most common)
  tty.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1)

  tty.c_lflag &= ~ICANON;
  tty.c_lflag &= ~ECHO; // Disable echo
  tty.c_lflag &= ~ECHOE; // Disable erasure
  tty.c_lflag &= ~ECHONL; // Disable new-line echo
  tty.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP
  tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl
  tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); // Disable any special handling of received bytes

  tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars)
  tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed
  // tty.c_oflag &= ~OXTABS; // Prevent conversion of tabs to spaces (NOT PRESENT ON LINUX)
  // tty.c_oflag &= ~ONOEOT; // Prevent removal of C-d chars (0x004) in output (NOT PRESENT ON LINUX)

  tty.c_cc[VTIME] = 10;    // Wait for up to 1s (10 deciseconds), returning as soon as any data is received.
  tty.c_cc[VMIN] = 0;

  // Set in/out baud rate to be 9600
  cfsetispeed(&tty, B115200);
  cfsetospeed(&tty, B115200);

  // Save tty settings, also checking for error
  if (tcsetattr(serial_port, TCSANOW, &tty) != 0) {
      printf("Error %i from tcsetattr: %s\n", errno, strerror(errno));
      return 1;
  }
unsigned char read_buf[800];
int count = 0;
 while (ros::ok())
  {
    int n = read(serial_port, read_buf, sizeof(read_buf) - 1);
    if (n < 0) {
        /* handle errno condition */
        return -1;
    }
    read_buf[n] = '\0';
    std::cout << read_buf ;

std_msgs::String msg;

    std::stringstream ss;
    ss << read_buf;
    msg.data = ss.str();

    ROS_INFO("%s", msg.data.c_str());

    chatter_pub.publish(msg);

    ros::spinOnce();

    loop_rate.sleep();
    ++count;

}

  close(serial_port);
  return 0; // success
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

笛声青案梦长安 2025-02-03 17:22:41

对您的消息来源的评论说:

//等待最多1秒(10个决定),一旦收到任何数据,请立即返回。

请立即返回。”,因为串行线上的变速多个部分。 (查找“ baudrate”以了解传输时间。)一个部分包含多少个字符,取决于许多因素,通常您不能预见到它。

将您的阅读算法更改为简单的有限状态机,该机器收集接收的字符,直到接收到末期标记为止。原始解决方案会扫描它。

The comment on your source says:

"// Wait for up to 1s (10 deciseconds), returning as soon as any data is received."

Since a transmission over a serial line takes some time, you will in most cases receive the message in multiple parts. (Look up "baudrate" to learn about transmission times.) How many characters one part contains, depends on many factors, and commonly you cannot foresee it.

Change your reading algorithm to a simple finite state machine that collects received characters until the end-of-message marker is received. A primitive solution would scan for it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文