Test probram to setup XBus servo settings.

Dependencies:   ACM1602NI XBusServo mbed-src

This is just a working sample. This is setup tool for XBus servo. You can change all setting on XBus servo. Tested only on KL25Z

これはただの動作サンプルです。 これはXBusサーボ用のセットアップツールです。 このコードで、XBusサーボの全てのセッティングが変更できます。 KL25Z上でのみ動作確認しています。

main.cpp

Committer:
sawa
Date:
2014-11-05
Revision:
1:4fdeb414f4ce
Parent:
0:3e197b983b65

File content as of revision 1:4fdeb414f4ce:

/* main.cpp file
 *
 * for testing mbed XBusServo.cpp
 *
 * Copyright (c) 2014-2014 JR PROPO
 * Released under the MIT License: http://mbed.org/license/mit
 *
 * by Zak Sawa
 */

#include "mbed.h"
#include "ACM1602NI.h"
#include "XBusServo.h"

//#define DEBUGmain

#ifdef DEBUGmain
#define DBG(fmt) printf(fmt)
#define DBGF(fmt, ...) printf(fmt, __VA_ARGS__)
#else
#define DBG(...)
#define DBGF(...)
#endif

//
// defines
//
#define kYellowSwitch       D2
#define kRedSwitch          D3
#define kBlueSwitch         D4
#define kGreenSwitch        D5
#define kRotary_A           D8
#define kRotary_B           D9
#define kXBusTx             PTE0    // PTD3 p13
#define kXBusRx             PTE1    // PTD2 p14
#define kXBusSwitch         D10
#define kMaxServoNum        16      // 1 - 50
#define kLCDI2C_CLK         PTC8
#define lLCDI2C_DATA        PTC9

#define kMaxServoCommand    (sizeof(commandData) / sizeof(servoCommandRec))


//
// typedefs
//
typedef enum {
    kCursor_ID,
    kCursor_SubID,
    kCursor_Function,
    kCursor_Param
}
cursorType;

typedef struct servoCommandRec {
    char                    name[9];
    unsigned char           order;
    unsigned char           writeIndex;
    unsigned char           payloadSize;        // 5 for 2byte data / 4 for 1byte data
    unsigned char           hexData;            // true if the data should be show in Hex
    unsigned char           unsignedData;       // true if the data is unsigned
    long                    maxValue;
    long                    minValue;
}
servoCommandRec;

typedef enum {
    kRotaly_Stop,
    kRotaly_Right,
    kRotaly_Left
}
rotalyType;


//
// servo command data base
//
static const servoCommandRec        commandData[] = {
//  name        order                           write index               size hex unsin  max         mix
    {"Position",    0x00,                       0,                          0,  1,  1,  0x0FFFF,    0x0000},
    {"Servo ID",    0x00,                       0,                          0,  0,  0,  50,         1},
    {"SubID   ",    0x00,                       0,                          0,  0,  0,  3,          0},
    {"Version ",    kXBusOrder_2_Version,       0,                          5,  1,  1,  0,          0},
    {"Model No",    kXBusOrder_2_Product,       0,                          5,  1,  1,  0,          0},
    {"Reverse ",    kXBusOrder_2_Reverse,       kParamIdx_Reversed,         5,  0,  0,  1,          0},
    {"Neutral ",    kXBusOrder_2_Neutral,       kParamIdx_NeutralOffset,    5,  0,  0,  300,        -300},
    {"H-Travel",    kXBusOrder_2_H_Travel,      kParamIdx_TravelHigh,       5,  0,  0,  192,        0},
    {"L-Travel",    kXBusOrder_2_L_Travel,      kParamIdx_TravelLow,        5,  0,  0,  192,        0},
    {"H-Limit ",    kXBusOrder_2_H_Limit,       kParamIdx_LimitHigh,        5,  1,  1,  0x0FFFF,    0x0000},
    {"L-Limit ",    kXBusOrder_2_L_Limit,       kParamIdx_LimitLow,         5,  1,  1,  0x0FFFF,    0x0000},
    {"P-Gain  ",    kXBusOrder_1_P_Gain,        kParamIdx_PGainDiff,        4,  0,  0,  50,         -50},
    {"I-Gain  ",    kXBusOrder_1_I_Gain,        kParamIdx_IGainDiff,        4,  0,  0,  50,         -50},
    {"D-Gain  ",    kXBusOrder_1_D_Gain,        kParamIdx_DGainDiff,        4,  0,  0,  50,         -50},
    {"Int-Max ",    kXBusOrder_2_MaxInteger,    kParamIdx_MaxIntegerDiff,   5,  0,  0,  999,        -999},
    {"DeadBand",    kXBusOrder_1_DeadBand,      kParamIdx_DeadBandDiff,     4,  0,  0,  10,         -10},
    {"180deg  ",    kXBusOrder_1_Angle_180,     kParamIdx_Angle_180,        4,  0,  0,  1,          0},
    {"SpeedLim",    kXBusOrder_1_SpeedLimit,    kParamIdx_SpeedLimit,       4,  0,  0,  30,         0},
    {"StopMode",    kXBusOrder_1_StopMode,      kParamIdx_StopMode,         4,  0,  0,  1,          0},
    {"PowOffst",    kXBusOrder_2_PowerOffset,   kParamIdx_PWOffsetDiff,     5,  0,  0,  999,        -999},
    {"SlowStat",    kXBusOrder_1_SlowStart,     kParamIdx_SlowStart,        4,  0,  0,  1,          0},
    {"AlarmLv ",    kXBusOrder_1_AlarmLevel,    kParamIdx_AlarmLevel,       4,  0,  0,  99,         0},
    {"AlarmDly",    kXBusOrder_2_AlarmDelay,    kParamIdx_AlarmDelay,       5,  0,  0,  5000,       0},
    {"CurPossi",    kXBusOrder_2_CurrentPos,    0,                          5,  1,  1,  0,          0},
    {"CurPower",    kXBusOrder_1_CurrentPow,    0,                          4,  0,  0,  0,          0}
};


//
// global vars
//
ACM1602NI                       gLCD(lLCDI2C_DATA, kLCDI2C_CLK);
XBusServo                       gXBus(kXBusTx, kXBusRx, kXBusSwitch, kMaxServoNum);
Ticker                          gTimer;
DigitalIn                       gUp_SW(kYellowSwitch, PullUp);
DigitalIn                       gLeft_SW(kBlueSwitch, PullUp);
DigitalIn                       gRight_SW(kRedSwitch, PullUp);
DigitalIn                       gDown_SW(kGreenSwitch, PullUp);
DigitalIn                       gRotary_A(kRotary_A, PullUp);
InterruptIn                     gRotary_B(kRotary_B);

uint8_t                         gDirty = true;          // true for first update
uint8_t                         gSaveCurrentValue = false;
uint8_t                         gOK2SendPacket = true;
uint8_t                         gCurrentValueChanged = false;

uint16_t                        gCurrentPos = kXbusServoNeutral;
int32_t                         gCurrentValue = 0;
cursorType                      gCurrentCursor = kCursor_ID;
volatile rotalyType             gRotalyJob = kRotaly_Stop;
uint8_t                         gCurrentFunction = 0;
uint8_t                         gNextFunction = 0;

uint8_t                         gCurrentServoID = 1;
uint8_t                         gCurrentSubID = 0;


void getRotary(void);



//=============================================================
// XbusIntervalHandler()
//  14mSec interval handler
//=============================================================
void XbusIntervalHandler()
{
    if (gOK2SendPacket)
        gXBus.sendChannelDataPacket();
}


//=============================================================
// init()
//  initialize all setup
//=============================================================
void init()
{
    gLCD.cls();
    gLCD.locate(0, 0);

    gRotary_B.mode(PullUp);
    gRotary_B.rise(getRotary);
    gRotary_B.fall(getRotary);
    gRotary_B.enable_irq();
}


//=============================================================
// rotaryRight()
//  This is what to do when rotary encoder turn right
//=============================================================
void rotaryRight()
{
    if (gDirty)
        return;

    switch (gCurrentCursor) {
        case kCursor_ID:
            if (gCurrentServoID < kXBusMaxServoNum) {
                gXBus.removeServo(ChannelID(gCurrentServoID, gCurrentSubID));
                gCurrentServoID++;
                gXBus.addServo(ChannelID(gCurrentServoID, gCurrentSubID), gCurrentPos);
                gDirty = true;
            }
            break;

        case kCursor_SubID:
            if (gCurrentSubID < 3) {
                gXBus.removeServo(ChannelID(gCurrentServoID, gCurrentSubID));
                gCurrentSubID++;
                gXBus.addServo(ChannelID(gCurrentServoID, gCurrentSubID), gCurrentPos);
                gDirty = true;
            }
            break;

        case kCursor_Function:
            if (gCurrentFunction < (kMaxServoCommand - 1)) {
                gNextFunction = gCurrentFunction + 1;
                gDirty = true;
            }
            break;

        case kCursor_Param:
            if (commandData[gCurrentFunction].maxValue == commandData[gCurrentFunction].minValue)
                break;

            if (gCurrentFunction == 0) {
                gCurrentPos += 200;
                gDirty = true;
            } else if (gCurrentValue < commandData[gCurrentFunction].maxValue) {
                gCurrentValue++;
                gCurrentValueChanged = true;
                gDirty = true;
            }
            break;
    }
}


//=============================================================
// rotaryLeft()
//  This is what to do when rotary encoder turn left
//=============================================================
void rotaryLeft()
{
    if (gDirty)
        return;

    switch (gCurrentCursor) {
        case kCursor_ID:
            if (gCurrentServoID > 1) {
                gXBus.removeServo(ChannelID(gCurrentServoID, gCurrentSubID));       // add first servo with channelID = 0x01
                gCurrentServoID--;
                gXBus.addServo(ChannelID(gCurrentServoID, gCurrentSubID), gCurrentPos);         // add first servo with channelID = 0x01
                gDirty = true;
            }
            break;

        case kCursor_SubID:
            if (gCurrentSubID > 0) {
                gXBus.removeServo(ChannelID(gCurrentServoID, gCurrentSubID));       // add first servo with channelID = 0x01
                gCurrentSubID--;
                gXBus.addServo(ChannelID(gCurrentServoID, gCurrentSubID), gCurrentPos);         // add first servo with channelID = 0x01
                gDirty = true;
            }
            break;

        case kCursor_Function:
            if (gCurrentFunction > 0) {
                gNextFunction = gCurrentFunction - 1;
                gDirty = true;
            }
            break;

        case kCursor_Param:
            if (commandData[gCurrentFunction].maxValue == commandData[gCurrentFunction].minValue)
                break;

            if (gCurrentFunction == 0) {
                gCurrentPos -= 200;
                gDirty = true;
            } else if (gCurrentValue > commandData[gCurrentFunction].minValue) {
                gCurrentValue--;
                gCurrentValueChanged = true;
                gDirty = true;
            }
            break;
    }
}


//=============================================================
// getRotary()
//  This is the handler to get rotary encoder
//=============================================================
void getRotary(void)
{
    static unsigned char sOldRot = 0;

    if (! gRotary_A.read()) {
        // Check to start rotating
        if (gRotary_B.read())
            sOldRot = 'R'; // Right turn started
        else
            sOldRot = 'L'; // Left turn started
    } else {
        // Check to stop rotating
        if (gRotary_B.read()) {
            if (sOldRot == 'L') // It's still left turn
                if (gRotalyJob == kRotaly_Stop)
                    gRotalyJob = kRotaly_Left;
        } else {
            if (sOldRot == 'R')  // It's still right turn
                if (gRotalyJob == kRotaly_Stop)
                    gRotalyJob = kRotaly_Right;
        }

        sOldRot = 0;
    }
}


//=============================================================
// updateLCD()
//  update contents of LCD
//=============================================================
void updateLCD()
{
    // update ID
    gLCD.locate(0, 0);
    gLCD.printf("XBus ID %02d-%02d", gCurrentServoID, gCurrentSubID);
    gLCD.printf("  ");

    // update function name
    gLCD.locate(0, 1);
    gLCD.printf(commandData[gCurrentFunction].name);

    // update current value
    gLCD.locate(9, 1);
    switch(gCurrentFunction) {
        case 0:         // position
            gLCD.printf("%04X", gCurrentPos);
            break;

        default:
            if (commandData[gCurrentFunction].hexData)
                gLCD.printf("%04X", gCurrentValue);
            else if ((commandData[gCurrentFunction].maxValue == 1) && (commandData[gCurrentFunction].minValue == 0)) {
                if (gCurrentValue == 1)
                    gLCD.printf("  on");
                else
                    gLCD.printf(" off");
            } else
                gLCD.printf("%4d", gCurrentValue);
    }
    gLCD.printf("  ");

    // update cursor
    switch(gCurrentCursor) {
        case kCursor_ID:
            gLCD.locate(9, 0);
            break;

        case kCursor_SubID:
            gLCD.locate(12, 0);
            break;

        case kCursor_Function:
            gLCD.locate(7, 1);
            break;

        case kCursor_Param:
            gLCD.locate(12, 1);
            break;
    }
}


//=============================================================
// buttonHandler()
//  get push button status and change flags
//=============================================================
void buttonHandler()
{
    if (! gUp_SW.read()) {
        if (gCurrentCursor == kCursor_Function) {
            gCurrentCursor = kCursor_ID;
            gDirty = true;
        } else if (gCurrentCursor == kCursor_Param) {
            gCurrentCursor = kCursor_SubID;
            gDirty = true;
            gSaveCurrentValue = true;
        }
    } else if (! gDown_SW.read()) {
        if (gCurrentCursor == kCursor_ID) {
            gCurrentCursor = kCursor_Function;
            gDirty = true;
        } else if (gCurrentCursor == kCursor_SubID) {
            gCurrentCursor = kCursor_Param;
            gDirty = true;
        }
    } else if (! gRight_SW.read()) {
        if (gCurrentCursor == kCursor_ID) {
            gCurrentCursor = kCursor_SubID;
            gDirty = true;
        } else if (gCurrentCursor == kCursor_Function) {
            gCurrentCursor = kCursor_Param;
            gDirty = true;
        }
    } else if (! gLeft_SW.read()) {
        if (gCurrentCursor == kCursor_SubID) {
            gCurrentCursor = kCursor_ID;
            gDirty = true;
        } else if (gCurrentCursor == kCursor_Param) {
            gCurrentCursor = kCursor_Function;
            gDirty = true;
            gSaveCurrentValue = true;
        }
    }
}


//=============================================================
// setCurrentValue()
//  set current value to the servo for temp
//=============================================================
void setCurrentValue()
{
    int16_t         theValue;
    XBusError       result;

    // set current value
    if (gCurrentValueChanged) {
        if (commandData[gCurrentFunction].writeIndex != 0) {
            theValue = gCurrentValue;
            for(;;) {
                result = gXBus.setCommand(ChannelID(gCurrentServoID, gCurrentSubID), commandData[gCurrentFunction].order, &theValue);
                wait_ms(10);
                if (result == kXBusError_NoError)
                    break;
            }
        }
    }
}


//=============================================================
// writeCurrentValue()
//  write current value to the servo
//=============================================================
void writeCurrentValue()
{
    XBusError       result;
    uint8_t         currentChannelID;

    currentChannelID = ChannelID(gCurrentServoID, gCurrentSubID);

    if (commandData[gCurrentFunction].writeIndex == 0) {
        // for change ID
        if ((gCurrentFunction == 1) || (gCurrentFunction == 2)) {
            int         newChannelID;

            if (gCurrentFunction == 1)
                gCurrentServoID = gCurrentValue;
            else
                gCurrentSubID = gCurrentValue;

            newChannelID = ChannelID(gCurrentServoID, gCurrentSubID);

            for (;;) {
                result = gXBus.setChannelID(currentChannelID, newChannelID);
                wait_ms(10);
                if (result == kXBusError_NoError)
                    break;
            }

            gXBus.removeServo(currentChannelID);
            gXBus.addServo(newChannelID, gCurrentPos);
        }
    } else {
        int16_t         writeIndex;

        writeIndex = commandData[gCurrentFunction].writeIndex;
        for (;;) {
            result = gXBus.setCommand(currentChannelID, kXBusOrder_2_ParamWrite, &writeIndex);
            wait_ms(10);
            if (result == kXBusError_NoError)
                break;
        }
    }
}


//=============================================================
// getCurrentValue()
//  get current value from the servo
//=============================================================
void getCurrentValue()
{
    int16_t         theValue;
    XBusError       result;

    // get current value
    switch(gCurrentFunction) {
        case 0:
        case 1:
        case 2:
            // do nothing
            break;

        default:
            for (;;) {
                result = gXBus.getCommand(ChannelID(gCurrentServoID, gCurrentSubID), commandData[gCurrentFunction].order, &theValue);
                wait_ms(10);
                if (result == kXBusError_NoError)
                    break;
            }
            gCurrentValue = theValue;
            if (commandData[gCurrentFunction].unsignedData)
                gCurrentValue &= 0x0000FFFF;
            break;
    }
}


//=============================================================
// main()
//
//=============================================================
int main()
{
    init();

    if (gXBus.start() == kXBusError_NoError) {
        gXBus.addServo(0x01, kXbusServoNeutral);

        gTimer.attach_us(&XbusIntervalHandler, kXBusStandardInterval * 1000);

        while(1) {
            buttonHandler();

            switch (gRotalyJob) {
                case kRotaly_Right:
                    rotaryRight();
                    break;

                case kRotaly_Left:
                    rotaryLeft();
                    break;

                case kRotaly_Stop:
                default:
                    break;          // Do nothing
            }

//           gCurrentPos += 20;
//            gXBus.setServo(0x01, gCurrentPos);
//            wait_ms(10);

            if (gDirty) {
                gOK2SendPacket = false;

                setCurrentValue();

                if (gSaveCurrentValue)
                    writeCurrentValue();

                if (gNextFunction != gCurrentFunction) {
                    gCurrentFunction = gNextFunction;
                    if (gCurrentFunction == 1)
                        gCurrentValue = gCurrentServoID;
                    else if (gCurrentFunction == 2)
                        gCurrentValue = gCurrentSubID;
                    else
                        getCurrentValue();
                }

                updateLCD();
                gXBus.setServo(ChannelID(gCurrentServoID, gCurrentSubID), gCurrentPos);

                gOK2SendPacket = true;
            }

            gDirty = false;
            gSaveCurrentValue = false;
            gRotalyJob = kRotaly_Stop;
        }

        gXBus.stop();
    }
}