View Single Post
  #3   Spotlight this post!  
Unread 02-08-2010, 06:59 AM
charrisTTI charrisTTI is offline
Ramblin' Wreck
AKA: Charles Harris
FRC #0623
Team Role: Mentor
 
Join Date: Jan 2005
Rookie Year: 2003
Location: Vienna, VA
Posts: 106
charrisTTI has a spectacular aura aboutcharrisTTI has a spectacular aura about
Send a message via AIM to charrisTTI
Re: Magnetic Encoder Programming Question\Consult

I spent the better part of a day looking at the magnetic encoder I/O options. We ruled out the analog angle output because of the slow response at the rollover point. I did not give the PWM output much thought. I tried two different approaches for which I am including code samples. The first reads the data digitally using the SPI support and the second uses two analog channels to read the sin/cos outputs (be sure to remove the solder jumper to enable these ports).

Here is the digital one using SPI:

Code:
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package edu.wpi.first.wpilibj;

import edu.wpi.first.wpilibj.fpga.tSPI;

/**
 *
 * @author charris
 */
public class AS5030FourWireSPI extends SensorBase {

    public class AS5030Result
    {
        public double angle;
        public int agc;
    }


    tSPI spi;
    DigitalModule module;
    int slot;
    int clockPin;
    int dataOutPin;
    int dataInPin;
    int chipSelectPin;


    public AS5030FourWireSPI( int slotParam, int clockPinParam, int dataOutPinParam, int dataInPinParam, int chipSelectPinParam )
    {
        slot = slotParam;
        clockPin = clockPinParam;
        dataOutPin = dataOutPinParam;
        dataInPin = dataInPinParam;
        chipSelectPin = chipSelectPinParam;
        
        // get our module
        module = DigitalModule.getInstance(slot);

        // create SPI instance
        //spi = new tSPI();

        // allocate our pins
        module.allocateDIO(clockPin, false);
        module.allocateDIO(dataOutPin, false);
        module.allocateDIO(dataInPin, true);
        module.allocateDIO(chipSelectPin, false);

        // setup for SPI
        tSPI.writeChannels_SCLK_Module(DigitalModule.slotToIndex(slot));
        tSPI.writeChannels_SCLK_Channel(DigitalModule.remapDigitalChannel(clockPin-1));

        tSPI.writeChannels_MOSI_Module(DigitalModule.slotToIndex(slot));
        tSPI.writeChannels_MOSI_Channel(DigitalModule.remapDigitalChannel(dataOutPin-1));

        tSPI.writeChannels_MISO_Module(DigitalModule.slotToIndex(slot));
        tSPI.writeChannels_MISO_Channel(DigitalModule.remapDigitalChannel(dataInPin-1));
    }

    public void initialize()
    {
        // set chip select low to start
        module.setDIO(chipSelectPin, true);

        // data is valid on rising edge of clock
        tSPI.writeConfig_DataOnFalling(false);

        // set the bit order
        tSPI.writeConfig_MSBfirst(true);

        tSPI.strobeReset();
        tSPI.strobeClearReceivedData();
    }

    public AS5030Result getData( )
    {
        // select the chip
        module.setDIO(chipSelectPin, false);

        // write the 5 bit command
        // set the width
        tSPI.writeConfig_BusBitWidth(5);

        // write the data to load
        tSPI.writeDataToLoad(0x1F);

        // strobe out the data
        tSPI.strobeLoad();

        // wait for completion
        while( !tSPI.readStatus_Idle() )
        {
            java.lang.Thread.yield();
        }

        // change back to 16 bits
        tSPI.writeConfig_BusBitWidth(16);
        // clear the data to load
        tSPI.writeDataToLoad(0x0);

        // clear received data
        tSPI.strobeClearReceivedData();

        // strobe in the data
        tSPI.strobeLoad();


        // wait for completion
        //while( !tSPI.readStatus_Idle() )
        while( tSPI.readReceivedElements() == 0 )
        {
            java.lang.Thread.yield();
        }

        // strobe in the received data
        tSPI.strobeReadReceivedData();

        // read the data
        long rawData = tSPI.readReceivedData();

        // deselect the chip
        module.setDIO(chipSelectPin, true);

        AS5030Result result = new AS5030Result();

        long rawAngle = rawData & 0xFF;

        int agc = (int)((rawData >> 8) & 0x3F);

        result.angle = (double)rawAngle * 360.0 / 256.0;
        result.agc = agc;
        
        return result;
    }
}
Here is the dual analog input approach:

Code:
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package edu.wpi.first.wpilibj;

import  com.sun.squawk.util.MathUtils;

/**
 *
 * @author charris
 */
public class AS5030DualAnalog extends SensorBase implements PIDSource {

    private static final double biasVoltage = 2.25;
    private AnalogChannel sinChannel;
    private AnalogChannel cosChannel;

    public AS5030DualAnalog( int slotParam, int sinChannelParam, int cosChannelParam)
    {
        sinChannel = new AnalogChannel( slotParam, sinChannelParam );
        cosChannel = new AnalogChannel( slotParam, cosChannelParam );
    }

    protected double getCos()
    {
        return cosChannel.getVoltage() - biasVoltage;
    }

    protected double getSin()
    {
        return sinChannel.getVoltage() - biasVoltage;
    }

    public double getAngle()
    {
        // calculate the angle
        double theta = MathUtils.atan2( getSin(), getCos() );
        // convert to degrees
        return Math.toDegrees(theta) + 180.0;
    }

    /**
     * Get the angle of the encoder for use with PIDControllers
     * @return the current angle according to the encoder
     */
    public double pidGet() {
        return getAngle();
    }


}
Give them a try.
__________________
FRC 623 2003,2004,2005,2006,2007,2008, 2009, 2010, 2011
FRC 1900 2007
FVC 60 and 193 2006
FVC 3271 2007
FTC 226 and 369 2008, 2009, 2010, 2011
FTC 3806 2010
Reply With Quote