C语言 在WebBots的单个接收器上接受多个数据包

yws3nbqq  于 2023-03-01  发布在  其他
关注(0)|答案(1)|浏览(325)

我正在尝试对e-puck机器人上的接收器模块进行编程,以接收来自多个发射器模块的数据包及其相关信号强度。
我面临的问题是,当接收到新数据时,之前的数据包(未被读取)会丢失(参见https://cyberbotics.com/doc/reference/receiver#field-summary中的bufferSize)。这意味着,当Webots运行接收器模块的控制器时,只有来自最新发射器的数据存储在缓冲区中,所有其他数据(来自其他发射器)在控制器有机会读取之前就已经丢失。
我尝试了几种不同的选择,但似乎都不起作用:
异步运行接收器控制器(通过将控制器的SYNCHRONISATION设置为FALSE),以更频繁地运行它,并独立于Webot时间步长,以便它也有机会从其他发射器读取数据。
安排发射器一次发送一个数据,这样接收器就可以处理信息。这是可行的,但它会使系统对动态变化的响应非常慢。对于上下文,我正尝试将接收器与至少7个发射器连接。
我考虑过在任何数据被添加到接收器的缓冲区时使用中断服务例程,但我找不到任何有关在Webots控制器中实现中断的文档。
我试着减少接收器控制器的时间步长,这样它就可以运行得更频繁,丢失的数据也更少,但Webots要求控制器的时间步长是模拟时间步长的整数倍,这意味着接收器总是与最新的发射器同时运行,这又让我们回到了同一个问题。
我认为要使我的模拟工作,我将不得不要么运行接收器7倍的速度比发射器在这样一种方式,它读取数据从每个发射器每次运行。或者,改变接收器模块的缓冲区设置不知何故,不丢失数据从以前的传输。任何和所有的建议感谢。
蒂亚!

fwzugrvs

fwzugrvs1#

注意事项:
1.我 * 不 * 熟悉webots
1.我稍微熟悉ROS,但远非Maven。
1.我的ROS经验(在一个商业机器人项目上)是"边走边学ROS"
1.所以我接下来要说的很多东西可能完全不知道ROS提供的机制。
当我的进程"订阅"一个发布的流时,基于给我的"控制器",控制器创建了一个"隐藏"线程,该线程在recv等上循环,并保存流中的最新状态。
我的线程可以轮询控制器的状态,但是,它经常会说"没有新数据",我的循环会查看时间戳,并试图计算它应该休眠到新数据发布后被唤醒的时间。
这是充满了问题,类似于你的。
AFAICT,这样做是为了让我的线程是"同步的"。
我想要的是"成为"处理所有传入消息的线程。我一直在寻找一种方法,从每个传入消息的隐藏线程中获得异步回调。不幸的是,在我找到答案之前,项目就结束了。
但是,我的感觉是,我必须修改控制器以提供回调[* 如果 * 没有标准机制来实现这一点--我没有机会找到它]。
另一个问题是,我的代码运行的线程/进程可以订阅多个流,但每个流都需要轮询给定流的控制器接口。
每个控制器对于每个流都有一个隐藏线程,它只处理来自给定源的数据。
理想情况下,我需要的是流的套接字列表,这样我就可以通过selectpoll系统调用来等待它们,这样,只要有数据到达,我就会被唤醒。
ROS和/或网络机器人 * 可能 * 提供这样的回调机制(您尝试通过将控制器的SYNCHRONISATION设置为FALSE来实现)。
希望ROS/webots中有这样的机制。否则,你可能需要破解源代码。或者,只使用API的一部分来做管理连接的样板,但建立自己的控制器。
在我的ROS体验之后,出现了ROS2。上面的警告仍然适用;- )我粗略地看了一下。事实上,一个重要的变化是使用多播套接字代替单播。因此,如果发布者有多个订阅者,它可以向多播组发送一个 * 单个 * 数据包(而不是向单播地址列表发送单独的数据包)。因此,可能会更有效。
为了调试这个问题,我使用了我以前(非ROS)项目中的一个技巧。我创建了一个"事件"结构体的环形队列,这些结构体带有时间戳和线程ID。这些不是ROS意义上的事件。只是跟踪程序/进程/线程以及它们所在的位置(例如):

enum evt_type {
    EVENT_FOO_TOPLOOP,
    EVENT_FOO_POST_WAIT,
    // ...
};

void
foo(void)
{

    for (int iter = 1;  ++iter) {
        event_trace(EVENT_FOO_TOPLOOP,iter);
        wait_for_some_ros_event(stream);
        event_trace(EVENT_FOO_POST_WAIT,iter);
    }
}

我在源代码中加入了event_trace回调函数,event_trace会向循环队列添加一个结构体,其形式为:

struct trace_event {
    uint64_t evt_timestamp;                     // event timestamp
    enum evt_type evt_type;                     // event type
    uint64_t evt_data;                          // per-event data
    int evt_tid;                                // sequential thread id
};

event_add具有两个全局环队列索引(例如int queue_enq, queue_deq;
它将使用使用atomic_compare_exchangestdatomic.h原语来推进入队/出队索引(即,半无锁)。
其目的是要有一个"低开销"的跟踪机制,很少甚至没有旋转/等待。
当程序检测到异常(或接收到SIGINT等)时,它将调用转储函数,并将环形队列的内容转储到文件中。转储文件对于每个代理/进程都是不同的,(例如)sprintf(file,"event_dump.%d",getpid())

相关问题