Reading and transmitting accelerometer values

I would not expect that code to work, because once again you are reading from rxPacket without first guaranteeing that it is non-zero. You are doing that in the conditions of your while loops.

I still recommend that you try to do something simpler where both Wixels are periodically transmitting no matter what state the accelerometers are in. The code would look something like this:

void radioRxService()
{
    adcReport XDATA * rxPacket;

    if (rxPacket = (adcReport XDATA *) radioQueueRxCurrentPacket()) {
        ... // Copy the accelerometer data from the rxPacket to other variables so you can easily access it later.
        radioQueueRxDoneWithPacket();
    }
}

void servoService()
{
    ... // Using the accelerometer data from this Wixel and the stored data from the other Wixel, set the servo positions.
}

If you want to do hysteresis, you can add some extra variables instead of creating while loops.

–David

I’d like to elaborate a little on why I think this is a good approach. Basically what I am doing is breaking down your program into small, simple subtasks that have well-defined inputs and outputs.

radioTxService (a.k.a. adcToRadioService)
Input: Information (i.e. accelerometer readings) from this Wixel.
Output: Packets to be sent to the radioQueue library.

radioRxService
Input: Packets from the radioQueue library.
Output: Information about the other Wixel, stored in RAM.

servoService
Input: Information about the other Wixel, stored in RAM. Information about this Wixel.
Output: Servo position.

All of these functions would be non-blocking (no long-running while loops).

Breaking the program up into small, simple tasks like this has several advantages. First of all, the functions you create will be more general, so you will be able to use them in the future with minor modifications. For example, radioTxService and radioRxService are general functions for synchronizing a data structure between two Wixels, and they can easily be adapted to data types other than accelerometer readings. For another example, the servoService function doesn’t need to know or care that a radio was used to receive the data from the other Wixel; it will work no matter what type of transport was used as long as the data has been stored in the right place. Secondly, when you break things up like this, each individual function will have a smaller amount of work to do and a smaller number of inputs and outputs, which means it will be easier to understand, write, maintain, and debug. Instead of just telling me that your overall system “isn’t working” and then presenting me with some complex code to debug, you’ll be able to print debugging information to the USB COM port and figure out which of the tasks is not doing its job.

–David

Thank you for the advice!

I got it to work but I have one more problem! I noticed that one Wixel’s accelerometer ADC reading has a different range (with a maximum of about 1945 mV) than the other Wixel’s accelerometer reading (maximum of 2030 mV). I thought using the 1.25 V internal reference might make the readings more accurate, but after using adcConvertToMillivolts(adcRead(5| ADC_REFERENCE_INTERNAL)), the terminal window displays values of around 3330 mV, which don’t change when the accelerometer rotates. My IR distance sensor doesn’t have this problem when I use the internal reference in adcRead.

Hello.

I’m glad you got things working!

If you use the internal 1.25 V reference, then you can only measure voltages between 0 and 1.25 V. This is explained in the documentation of adcRead:
pololu.github.com/wixel-sdk/adc_ … c3a0cf1789

The argument to adcConvertToMillivolts is supposed to be “an ADC result between -2048 and 2047 that was measured using VDD as a reference”. This is explained in the documentation of adcConvertToMillivolts:
pololu.github.com/wixel-sdk/adc_ … 2892254a33

If you want to make the readings more accurate, you should try calling running this once in a while:
adcSetMillivoltCalibration(adcReadVddMillivolts());

–David

Thanks! I’m actually calling adcSetMillivoltCalibration(adcReadVddMillivolts()); regularly already. Do you know why I could be getting different ranges for each Wixel/accelerometer or do you think it’s an insignificant difference?

It could be significant depending on what you want to do with the numbers. Does you application need a lot of precision?

When a system with two components is not behaving as I expect it to, I like to look at the signals between the two components to figure out which of the two components is not behaving as expected. You could measure the voltage on the accelerometer outputs and that would give us a good clue about what’s going on.

–David

The voltage I measured at the accelerometer outputs was about 100 mV more than the voltage being printed in the terminal window. One accelerometer had a voltmeter reading of 1643 mV and on the computer it was 1580 mV. The other accelerometer had a voltmeter reading of 1560 mV and on the computer it was around 1460 mV.

For my application, the more precision the better because an action is performed when the accelerometer reading is beyond a threshold value.

The fact that you are using a threshold does not imply that you need a lot of precision. You also need to think about what kind of signal the threshold is being applied to. If the signal changes very slowly (i.e. you’re measuing the angle of the hour hand of a clock) then a small inaccuracy in the threshold could correspond to a difference of several minutes in the time it takes to trigger the threshold, which could conceivably be bad for your application. On the other hand, if you are measuring a signal that quickly spikes way above the threshold once in a while (i.e. the acceleration of a human hand making gestures), then the precise value of the threshold doesn’t matter that much.

I’m not sure what could be causing the 100 mV discrepancy you are seeing. In case there is some residual charge left in the ADC from another channel, I would try taking 2-6 ADC readings on the channel you want to read, and throwing out every result except the last one. I would also consult the CC2511 datasheet and learn about what I can do to make the ADC more accurate.

–David

It just occurred to me that there’s no reason I need to convert the raw ADC values to millivolts for my application. I wanted to test how accurate the ADC values were using the internal 1.25 V reference, but after adding the ADC_REFERNCE_INTERNAL parameter to adcRead, the values hardly changed from “2047” while rotating the accelerometer.
here’s the code:

/*
 * This program outputs the raw ADC accelerometer values on P0_5.
 *
 */
#include <wixel.h>
#include <time.h>
#include <usb.h>
#include <usb_com.h>
#include <adc.h>
#include <stdio.h>

uint32 lastToggle = 0;

void analogInputsInit() {
 //Disable pull-ups and pull-downs for all pins on Port 0.
		P0INP = 0x3F;

}

void putchar(char c)
{
    usbComTxSendByte(c);
}


void updateprint()
{

    if (getMs() - lastToggle >= 1000)
    {
    	if (usbComTxAvailable() >= 64)
    	        {

    	            printf("adc: %d\r\n",  adcRead(5 | ADC_REFERENCE_INTERNAL));
    	        }
        lastToggle = getMs();
    }
}


void main()
{
    systemInit();
    usbInit();
    analogInputsInit();

    while(1)
    {
        boardService();
        updateprint();
        usbComService();

        usbShowStatusWithGreenLed();
        LED_RED(1);
    }
}

Is there something about the ADC_REFERENCE_INTERNAL parameter I’m missing?

Yes. If you use the internal 1.25 V reference, then you can only measure voltages between 0 and 1.25 V. This is explained in the documentation of adcRead:
pololu.github.com/wixel-sdk/adc_ … c3a0cf1789

–David