2

这个问题不是关于任何特定的语言,而是解决一个问题。

我有一个计时器,它向机器人发送一个方法并询问传感器数据。

一些传感器非常关键,几乎总是应该被请求,而其他一些传感器不是那么关键,但应该不时读取。

所以想象我有我的计时器,在计时器中它要求一个方法,该方法将由下面的代码返回:

Timer_Tick()
{
   AskForData(SensorRequestList())
}

private int _tCliffState = 0;
private int _tCliffSignal = 0;
private int _tLight = 0;
//and 7 other 

private byte[] SensorRequestList()
{
    if (_tCliffState <= 5)
    {
        _tCliffState++;
        return RequestCliffStates();
    }
    if(_tCliffSignal < 1)
    {
        _tCliffSignal++;
        return RequestCliffSignals();
    }
    if(_tLight < 1)
    {
        _tLight++;
        RequestLightSignals();
    }
    //and more ifs!


    //reset all
    _tCliffState = 0;
    _tCliffSignal = 0;
    _tLight = 0;
    //...
}

如果我有 10 种方法,那么最好的方法是什么,比如命名为 1、2、3、...10,优先级为 1、2、3...10。

我怎样才能获得一个很好的模式,我可以确定具有更高优先级的方法会请求更多?像这样的模式:

1,1,1,2,1,3,1,1,4,1,1,1,2,1,1,1,3,1,1,1,4 and so on

4

3 回答 3

2

如果数据有规律地进入,那么分析一段时间内收集的数据会更容易——例如,每毫秒一次、每秒一次、每天一次、每周一次等等。

如果您最终需要保证性能 - 如果机器人至少每秒没有从某个传感器或其他什么情况下听到某个传感器的声音,那么它可能会犯错误 - 如果您的程序按某种规则运行会更容易。

出于这些原因,我建议您通过重复发出一些固定数量的请求来收集数据,每个固定数量的请求之间有固定的间隔。我通常会将这样一个固定数量的请求称为一个帧。

在帧中为非常重要的传感器读数提供自己的插槽,以便每帧都收集它们。让不太重要的传感器读数在它们之间共享一个插槽,例如,您可以让 8 个传感器读数共享一个插槽,每个读数每 8 帧收集一次。如果你想让生活更复杂,你可以共享子槽,所以 8 个真正不重要的传感器读数可以共享一个子槽,每 64 帧收集一次。

为数据和原始值保留某种时间戳通常是一个好主意。事实上,有些系统会安排每帧拍摄一张快照,并记录这个快照的时间,然后在快照时间之后将值读出。那么所有的值都是在同一时刻取得的读数,并且这一时刻是已知的。

于 2013-01-06T08:16:31.577 回答
1

像您正在使用的计数器技术的问题是,在给定的时间,您可能有不止一种方法可以执行。缓解问题的解决方案是停止计数器,将所有合格的方法排队,并为下一个计时器事件选择每个排队的方法,直到队列为空。清空后,您可以重新开始计数过程以选择一组新方法

这是一个可能的实现(未经测试的代码),使用int存储方法队列:

Timer_Tick() {
   AskForData(SensorRequestList());
}

private int _state[NUM_METHODS]; // initialized to 0
private int _priority[NUM_METHODS]; 
private int _flags; // initialized to 0
private (byte [])(*_methods)[NUM_METHODS]; // array of pointer to functions, 
                                                                            // runnables, etc.


private byte[] SensorRequestList() {
     do {
        for (int i = 0; i < NUM_METHODS; ++i)
            if ((1 << i) & _flags){
                _flags &= ~(1 << i);
                _state[i] = 0;
                return _method[i]();
           }

         for (i = 0; i < NUM_METHODS; ++i){
            _state[i]++;
            _flags |= (_state[i] >= _priority[i]) << i;
        }
    } while (!_flags);
}

此实现要求方法的数量小于sizeof(int) * 8平台的数量(假设每字节 8 位)。它可以很容易地切换到使用更大数量的真实队列。

除了重置_stateto之外0,还可以使用以下命令:

  _state[i] -= _priority[i];

并保持计数器滚动,但这肯定需要更加注意所选元素的排队方式。

于 2013-01-06T19:18:48.510 回答
1

这是启发式伪代码的描述,它应该给你一些合理的东西。

  1. 将所有优先级加在一起,称为总和。
  2. 按优先级对列表进行降序排序。
  3. 初始化一个大小为 sum 的空数组。
  4. 从第一个(最高优先级)元素开始,将与其优先级一样多的实例添加到列表中。选择间距时,请考虑环绕。
  5. 继续使用较低优先级的元素,仅考虑数组中的空闲空间。
  6. 在 t 滴答之后,请求与数组中位置 t % sum 相对应的传感器数据。

使用具有 10 个唯一元素 A..J 且优先级为 1..10 的示例,我们得到 sum = 55,我们的数组是 [A, B, C, D, E, A, C, B, F, G, A , D, C, B, E, A, H, F, C, B, A, D, E, G, C, A, B, I, D, E, A, C, B, F, H, A , D, C, B, E, A, G_, F, C, B, A, D, E, I, G, B, D, F, H, J],根据你的情况,它们似乎分布合理需要。

于 2013-01-07T23:32:59.137 回答