简体   繁体   English

Arduino巨型队列

[英]Arduino mega queue

I wrote this simple code which reads a length from the Sharp infrared sensor, end presents the average meter in cm (unit) by serial. 我编写了这个简单的代码,该代码从Sharp红外传感器读取一个长度,最后以串行形式显示以厘米(单位)为单位的平均米。

When write this code for the Arduino Mega board, the Arduino starts a blinking LED (pin 13) and the program does nothing. 当为Arduino Mega开发板编写此代码时,Arduino启动一个闪烁的LED(引脚13),并且该程序不执行任何操作。 Where is the bug in this code? 此代码中的错误在哪里?

#include <QueueList.h>

const int ANALOG_SHARP = 0; //Set pin data from sharp.
QueueList <float> queuea;
float cm;
float qu1;
float qu2;
float qu3;
float qu4;
float qu5;

void setup() {
    Serial.begin(9600);
}

void loop() {
    cm = read_gp2d12_range(ANALOG_SHARP); //Convert to cm (unit).
    queuea.push(cm); //Add item to queue, when I add only this line Arduino crash.
    if ( 5 <= queuea.peek()) {
        Serial.println(average());
    }
}

float read_gp2d12_range(byte pin) { //Function converting to cm (unit).
    int tmp;

    tmp = analogRead(pin);
    if (tmp < 3)
        return -1; // Invalid value.

    return (6787.0 /((float)tmp - 3.0)) - 4.0;
}

float average() { //Calculate average length
    qu1 += queuea.pop();
    qu2 += queuea.pop();
    qu3 += queuea.pop();
    qu4 += queuea.pop();
    qu5 += queuea.pop();

    float aver = ((qu1+qu2+qu3+qu4+qu5)/5);
    return aver;
}

I agree with the peek() -> count() error listed by vhallac. 我同意vhallac列出的peek() -> count()错误。 But I'll also point out that you should consider averaging by powers of 2 unless there is a strong case to do otherwise. 但我还要指出,除非有很强的理由,否则您应该考虑以2的幂进行平均。

The reason is that on microcontrollers, division is slow. 原因是在微控制器上,除法很慢。 By averaging over a power of 2 (2,4,8,16,etc.) you can simply calculate the sum and then bitshift it. 通过对2(2、4、8、16等)的幂进行平均,您可以简单地计算出总和,然后对其进行位移位。

To calculate the average of 2: (v1 + v2) >> 1 计算2的平均值: (v1 + v2) >> 1

To calculate the average of 4: (v1 + v2 + v3 + v4) >> 2 计算4的平均值: (v1 + v2 + v3 + v4) >> 2

To calculate the average of n values (where n is a power of 2) just right bitshift the sum right by [log2(n)]. 要计算n个值的平均值(其中n是2的幂),只需将总和右移[log2(n)]。

As long as the datatype for your sum variable is big enough and won't overflow, this is much easier and much faster. 只要您的sum变量的数据类型足够大且不会溢出,这将变得更加容易和快捷。

Note : this won't work for floats in general. 注意 :一般而言,这不适用于浮点数。 In fact, microcontrollers aren't optimized for floats. 实际上,微控制器并未针对浮点数进行优化。 You should consider converting from int (what I'm assuming you're ADC is reading) to float at the end after the averaging rather than before. 您应该考虑从int(我假设您正在读取ADC的数据)转换为在平均值之后而不是之前的末尾浮动。

By converting from int to float and then averaging floats you are losing more precision than averaging ints than converting the int to a float. 通过将int转换为float,然后对float进行平均,与将int转换为float相比,与平均int相比,您损失的精度更高。

Other: 其他:

You're using the += operator without initializing the variables ( qu1 , qu2 , etc.) -- it's good practice to initialize them if you're going to use += but it looks as if = would work fine. 您正在使用+=运算符而不初始化变量( qu1qu2等)-如果您要使用+= ,则将它们初始化是一个好习惯,但是看起来=可以正常工作。

For floats, I'd have written the average function as: 对于浮点数,我将average函数编写为:

float average(QueueList<float> & q, int n)
{
    float sum = 0;
    for(int i=0; i<n; i++)
    {
        sum += q.pop();
    }

    return (sum / (float) n);
}

And called it: average(queuea, 5); 并称之为: average(queuea, 5);

You could use this to average any number of sensor readings and later use the same code to later average floats in a completely different QueueList. 您可以使用它来平均任意数量的传感器读数,然后使用相同的代码来以后平均一个完全不同的QueueList中的浮动。 Passing the number of readings to average as a parameter will really come in handy in the case that you need to tweak it. 在需要调整读数的情况下,将读数的数量作为平均值传递将非常有用。

TL;DR: TL; DR:

Here's how I would have done it: 这是我应该做的:

#include <QueueList.h>

const int ANALOG_SHARP=0;   // set pin data from sharp
const int AvgPower = 2;     // 1 for 2 readings, 2 for 4 readings, 3 for 8, etc.
const int AvgCount = pow(2,AvgPow);

QueueList <int> SensorReadings;


void setup(){
    Serial.begin(9600);
}

void loop()
{
    int reading = analogRead(ANALOG_SHARP);
    SensorReadings.push(reading);

    if(SensorReadings.count() > AvgCount)
    {
        int avg = average2(SensorReadings, AvgPower);
        Serial.println(gpd12_to_cm(avg));
    }
}

float gp2d12_to_cm(int reading)
{
    if(reading <= 3){ return -1; }

    return((6787.0 /((float)reading - 3.0)) - 4.0);
}

int average2(QueueList<int> & q, int AvgPower)
{
    int AvgCount = pow(2, AvgPower);
    long sum = 0;
    for(int i=0; i<AvgCount; i++)
    {
        sum += q.pop();
    }

    return (sum >> AvgPower);
}

You are using queuea.peek() to obtain the count. 您正在使用queuea.peek()获取计数。 This will only return the last element in queue. 这只会返回队列中的最后一个元素。 You should use queuea.count() instead. 您应该改为使用queuea.count()

Also you might consider changing the condition tmp < 3 to tmp <= 3 . 您也可以考虑将条件tmp < 3更改为tmp <= 3 If tmp is 3, you divide by zero. 如果tmp为3,则除以零。

Great improvement jedwards, however the first question I have is why use queuelist instead of an int array. 吉德沃兹(Jedwards)取得了很大的进步,但是,我的第一个问题是,为什么要使用队列列表而不是整数数组。

As an example I would do the following: 例如,我将执行以下操作:

int average(int analog_reading)
{
    #define NUM_OF_AVG 5
    static int readings[NUM_OF_AVG];
    static int next_position;
    static int sum;

    if (++next_position >= NUM_OF_AVG)
    {
        next_position=0;
    }
    reading[next_position]=analog_reading;

    for(int i=0; i<NUM_OF_AVG; i++)
    {
        sum += reading[i];
    }
    average = sum/NUM_OF_AVG
}

Now I compute a new rolling average with every reading and it eliminates all the issues related to dynamic memory allocation (memory fragmentation, no available memory, memory leaks) in a embedded device. 现在,我每次读取都会计算一个新的滚动平均值,它消除了与嵌入式设备中的动态内存分配(内存碎片,无可用内存,内存泄漏)有关的所有问题。

I appreciate and understand the use of shifting for a division by 2,4 or 8, however I would stay away from that technique for two reasons. 我欣赏并理解使用移位除以2,4或8的方法,但是出于两个原因,我会远离该技术。

I think readability and maintainability of the source code is more important then saving a little bit of time with a shift instead of a divide unless you can test and verify the divide is a bottleneck. 我认为,源代码的可读性和可维护性更为重要,因此,除非您可以测试和验证划分是一个瓶颈,否则通过转移而不是使用划分来节省一点时间。

Second, I believe most current optimizing compilers will do a shift if possible, I know GCC does. 其次,我相信大多数当前的优化编译器都将尽可能改变,我知道GCC会这样做。

I will leave refactoring out the for loop for the next guy. 我将把重构留给下一个家伙。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM