Shop OBEX P1 Docs P2 Docs Learn Events
RemBoxBot project — Parallax Forums

RemBoxBot project

RsadeikaRsadeika Posts: 3,837
edited 2013-01-21 13:55 in Propeller 1
I have started a new project, RemBoxBot which is made out of cardboard; my prototypes are usually made out of cardboard. Since I am using two different boards, the thing that I am trying to accomplish is communication between the two, which at this point is not working. I am using a three wire connection between the two, where it has a common ground, and the 5v supply for the PSCU board comes from the DNA board. I am also using the serial in pinout which is on the PSCU board, so far no luck on the communication part. Must be some problem with my code, or my understanding of how the comm process should work. I guess I need some expert opinion on this.

The one unusual thing that I did notice is, in the slave program, when the datain cog is running it has an affect on how the servos run, they run in spurts. When I have the datain cog disabled, then the servos run as expected. I thought the cog was a separate entity, and should not affect the other cogs?

Ray

master(DNA_RTC board)
/**
 * @file RBBmaster.c
 * This is the main RBBmaster program start point.
 */
#include <propeller.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/sd.h>

extern _Driver _FileDriver;

/* When this is not implemented, then the thread works. */
//_Driver *_driverlist[] = {
//    &_FileDriver,
//    NULL
//};

FILE *cmdinfile;
FILE *stdinfile;
FILE *stdoutfile;

FILE *cmdout;

volatile int t1cmdout;

void *do_job1(void *arg)
{
    pthread_set_affinity_thiscog_np();
    pthread_detach(pthread_self());

/*                             Tx Rx */        
    cmdout = fopen("SSER:38400,16,16","r+");
    
    waitcnt(CLKFREQ + CNT);
    fprintf(stdout,"Thread Started\n");
    
    while(1)
    {
        fprintf(cmdout,"%c\n",t1cmdout);
        usleep(3000);
    }
}


void Help()
{
    fprintf(stdout, "This is the Help File.\n");
}

/* This routine returns a pointer to the first character that doesn't
   match val. */
char *SkipChar(char *ptr, int val)
{
    while (*ptr)
    {
        if (*ptr != val) break;
        ptr++;
    }
    return ptr;
}

/* This routine returns a pointer to the first character that matches val. */
char *FindChar(char *ptr, int val)
{
    while (*ptr)
    {
        if (*ptr == val) break;
        ptr++;
    }
    return ptr;
}

/* This routine extracts tokens from a string that are separated by one or
   more spaces.  It returns the number of tokens found. */
int tokenize(char *ptr, char *tokens[])
{
    int num = 0;

    while (*ptr)
    {
        ptr = SkipChar(ptr, ' ');
        if (*ptr == 0) break;
        if (ptr[0] == '>')
        {
            ptr++;
            if (ptr[0] == '>')
            {
                tokens[num++] = ">>";
                ptr++;
            }
            else
                tokens[num++] = ">";
            continue;
        }
        if (ptr[0] == '<')
        {
            ptr++;
            tokens[num++] = "<";
            continue;
        }
        tokens[num++] = ptr;
        ptr = FindChar(ptr, ' ');
        if (*ptr) *ptr++ = 0;
    }
    return num;
}

/* This routine searches the list of tokens for the redirection operators
   and opens the files for input, output or append depending on the 
   operator. */
int CheckRedirection(char **tokens, int num)
{
    int i, j;

    for (i = 0; i < num-1; i++)
    {
        if (!strcmp(tokens[i], ">"))
        {
            stdoutfile = fopen(tokens[i+1], "w");
            if (!stdoutfile)
            {
                perror(tokens[i+1]);
                stdoutfile = stdout;
                return 0;
            }
        }
        else if (!strcmp(tokens[i], ">>"))
        {
            stdoutfile = fopen(tokens[i+1], "a");
            if (!stdoutfile)
            {
                perror(tokens[i+1]);
                stdoutfile = stdout;
                return 0;
            }
        }
        else if (!strcmp(tokens[i], "<"))
        {
            stdinfile = fopen(tokens[i+1], "r");
            if (!stdinfile)
            {
                perror(tokens[i+1]);
                stdinfile = stdin;
                return 0;
            }
        }
        else
            continue;
        for (j = i + 2; j < num; j++) tokens[j-2] = tokens[j];
        i--;
        num -= 2;
    }
    return num;
}

/* This routine closes files that were open for redirection */
void CloseRedirection()
{
    if (stdinfile != stdin)
    {
        fclose(stdinfile);
        stdinfile = stdin;
    }
    if (stdoutfile != stdout)
    {
        fclose(stdoutfile);
        stdoutfile = stdout;
    }
}


pthread_t thr[1];

/**
 * Main program function.
 */
int main(void)
{

    int num;
    char *tokens[20];
    uint8_t buffer[80];
    
    cmdinfile = stdin;
    stdinfile = stdin;
    stdoutfile = stdout;
    
    int i;
    pthread_create(&thr[i], NULL, do_job1, NULL);

    setvbuf(stdin, NULL, _IONBF, 0);    // no buffering stdin
    setvbuf(stdout, NULL, _IONBF, 0);   // no buffering stdout
    stdin->_flag |= _IOCOOKED;          // turn on echo
   
    waitcnt(CLKFREQ + CNT);
    printf("Start of program\n");
    
    while(1)
    {
        if (cmdinfile == stdin)
        {
            printf(">");
            fflush(stdout);
            gets(buffer);
        }
        else if (!fgets(buffer, 80, cmdinfile))
        {
            cmdinfile = stdin;
            continue;
        }
        num = tokenize(buffer, tokens);
        num = CheckRedirection(tokens, num);
        if (num == 0) continue;
        if (!strcmp(tokens[0], "help"))
            Help();
        else if(!strcmp(tokens[0], "gostop"))
            t1cmdout = 's';
        else if(!strcmp(tokens[0], "gofore"))
            t1cmdout = 'f';
        else
        {
            printf("Invalid command\n");
        }

       
    }    
    return 0;
}

slave(PSCU board)
/**
 * @file RBBslave.c
 * This is the main RBBslave program start point.
 */
#include <propeller.h>
#include <stdio.h>
#include <sys/thread.h>

FILE *cmdin;

#define STACK_SIZE 32

int LEFT_SERVO_PIN = 1;  
int RIGHT_SERVO_PIN = 0;

#define LEFT_CENTER 1500
#define RIGHT_CENTER 1500

#define PAUSE_DIVISOR 50

/* stacks for COGs */
static int LeftServoStack  [STACK_SIZE];
static int RightServoStack [STACK_SIZE];
static int DataInStack [STACK_SIZE];

/* per-thread library variables */
static _thread_state_t LeftThreadData;
static _thread_state_t RightThreadData;
static _thread_state_t DataInThreadData;

/* WheelServo COG variables */
int LeftServoSpeed;
int RightServoSpeed;
int LeftRotation;
int RightRotation;

int StopNoPulse = 0;  //1
static int MaxServoSpeed = 500;

void LeftServoThread(void *arg __attribute__((unused)))
{
    int pinmask = (1<<LEFT_SERVO_PIN);
    int center = LEFT_CENTER;
    int ustime = CLKFREQ/1000000;
    
    DIRA |= pinmask;

    for(;;) {
        /* start with signal off */
        OUTA &= ~pinmask;

        if(StopNoPulse && LeftServoSpeed == 0) {
            waitcnt(CLKFREQ/PAUSE_DIVISOR+CNT);
            LeftRotation = 0;
            continue;
        }

        if(LeftServoSpeed > MaxServoSpeed)
            LeftServoSpeed = MaxServoSpeed;
        if(LeftServoSpeed < -MaxServoSpeed)
            LeftServoSpeed = -MaxServoSpeed;

        /* move servo */
        LeftRotation = (LeftServoSpeed/2*center)/MaxServoSpeed+center;
                
        waitcnt(CLKFREQ/PAUSE_DIVISOR+CNT);
        OUTA |=  pinmask;
        waitcnt(ustime*LeftRotation+CNT);
        OUTA ^=  pinmask;

    }
}

void RightServoThread(void *arg __attribute__((unused)))
{

    int pinmask = (1<<RIGHT_SERVO_PIN);
    int center = RIGHT_CENTER;
    int ustime = CLKFREQ/1000000;
    
    DIRA |= pinmask;

    for(;;) {
        /* start with signal off */
        OUTA &= ~pinmask;

        if(StopNoPulse && RightServoSpeed == 0) {
            waitcnt(CLKFREQ/PAUSE_DIVISOR+CNT);
            RightRotation = 0;
            continue;
        }

        if(RightServoSpeed > MaxServoSpeed)
            RightServoSpeed = MaxServoSpeed;
        if(RightServoSpeed < -MaxServoSpeed)
            RightServoSpeed = -MaxServoSpeed;

        /* move servo */
        RightRotation = (-RightServoSpeed/2*center)/MaxServoSpeed+center;
        waitcnt(CLKFREQ/PAUSE_DIVISOR+CNT);
        OUTA |=  pinmask;
        waitcnt(ustime*RightRotation+CNT);
        OUTA ^=  pinmask;
    }
}

void DataInThread(void *arg __attribute__((unused)))
{
    int speed = 20;
    int t1datain;

/*                            Tx Rx        */        
    cmdin = fopen("SSER:38400,26,27","r+");

    setvbuf(cmdin, NULL, _IONBF, 0);    // no buffering stdin
//    setvbuf(cmdout, NULL, _IONBF, 0);   // no buffering stdout
    cmdin->_flag |= _IOCOOKED;          // turn on echo
        
    while(1)
    {
        fscanf(cmdin, "%c", &t1datain);
        
        switch(t1datain){
            case 's':
               botStop(); 
            break;
            case 'f':
                botForward(speed);
            break;
        }
        usleep(3010);
    }
}

void startServoThreads(void)
{
    int n;
    n = _start_cog_thread(LeftServoStack + STACK_SIZE, LeftServoThread, NULL, &LeftThreadData);
    
    n = _start_cog_thread(RightServoStack + STACK_SIZE, RightServoThread, NULL, &RightThreadData);
    
    n = _start_cog_thread(DataInStack + STACK_SIZE, DataInThread, NULL, &DataInThreadData);
    
}

void botStop(void)
{
    LeftServoSpeed = 0;
    RightServoSpeed = 0;
}

void botForward(int rate)
{
    LeftServoSpeed = rate;
    RightServoSpeed = rate;
}

void botReverse(int rate)
{
    LeftServoSpeed = -rate;
    RightServoSpeed = -rate;
}

void botSpeed(int rate)
{
    LeftServoSpeed = LeftServoSpeed >= 0 ? rate : -rate;
    RightServoSpeed = RightServoSpeed >= 0 ? rate : -rate;
}


/**
 * Main program function.
 */
int main(void)
{
    int speed = 20;
    
    char cmdstr[2];
    int cmd;
    
    setvbuf(stdin, NULL, _IONBF, 0);    // no buffering stdin
    setvbuf(stdout, NULL, _IONBF, 0);   // no buffering stdout
    stdin->_flag |= _IOCOOKED;          // turn on echo
        
    waitcnt(CLKFREQ + CNT);
    
    startServoThreads();
    
    printf("Threads started\n");
    
    for(;;) {
        putchar('>');
        
        fgets(cmdstr, 2, stdin);
        cmd = cmdstr[0];
        if(!cmd) {
            continue;
        }
        
        switch(cmd) {
            case 's':
                botStop();
                printf("\n");
            break;
            case 'f':
                botForward(speed);
                printf("Forward %d\n",speed);
            break;
            case 'b':
                botReverse(speed);
                printf("Backward %d\n",speed);
            break;
            case '-':
                if(speed >= 10) speed -= 10;
                printf("speed- %d\n",speed);
                botSpeed(speed);
            break;
            case '+':
                if(speed <= 90) speed += 10;
                printf("speed+ %d\n",speed);
                botSpeed(speed);
            break;
        }
    }
    return 0;
}

Comments

  • jazzedjazzed Posts: 11,803
    edited 2013-01-11 16:15
    Rsadeika wrote: »
    The one unusual thing that I did notice is, in the slave program, when the datain cog is running it has an affect on how the servos run, they run in spurts. When I have the datain cog disabled, then the servos run as expected. I thought the cog was a separate entity, and should not affect the other cogs?

    A pure pthread started with pthread_create(...) does not run by itself in a COG. Pthreads is an advanced subject not recommended for a beginner.

    A cogstart function is a C function that runs on top of an LMM interpreter. The cogstart just happens to use the pthread data struct for stack and other communications, but it is not a pthread.

    The only ways to make a COG run pure code by itself (without some interpreter) is by using PASM, GAS, or COGC.

    Everything we could think of that you need to know about libraries and drivers is referenced here.
    https://sites.google.com/site/propellergcc/documentation/libraries

    The order of the _Driver struct list entries is important.
    The default serial driver is the Simple Serial Driver device named SSER
    The current alternate serial driver is the Full Duplex Serial Driver named FDS
    There is a NULL driver you can use if you don't want a serial driver.
    /* This is a list of all drivers we can use in the
     * program. The default _InitIO function opens stdin,
     * stdout, and stderr based on the first driver in
     * the list (the serial driver, for us)
     */
    _Driver *_driverlist[] = {
      &_SimpleSerialDriver, // or &_FullDuplexSerialDriver
      &_FileDriver,
      NULL
    };
    

    You or anyone else can define your own driver that has special functions.
  • RsadeikaRsadeika Posts: 3,837
    edited 2013-01-12 05:50
    So, what have I learned so far? In the RemoteBot and RemBoxBot programs I have dealt with drivers and threads. For the drivers, it pertains to specifically serial drivers, and for threads, it would be cog thread and pthread.

    For the serial drivers, Simple Serial(SSER) is the default, meaning you do not have to use an 'extern' call or set up a driver list structure. This driver is half duplex, and does not need another cog start to work. Very simple and straight forward.

    The Full Duplex Serial(FDS), needs to use an 'extern' call plus a drivers list structure in order to work. This driver is full duplex, and it does set up in another cog. This is a little more complex, but you should expect that because it is full duplex.

    For the threads, I have been exposed to the cog thread, which behaves a lot like a cognew, in the Spin world, but it is still handled as a thread. This can run in an LMM/CMM mode, but not in XMM/XMMC mode. This type of thread is not severely limited by a blocking function(sleep, or waitcnt), so it can be used to run the servo code, which relies on the waitcnt function to work correctly. But their are some limitations, as I found out in my RemBoxBot program. When I introduced another cog thread that contained an fgets function, that seems to have an affect on how the servo functions would work.

    The pthread, an advanced subject, can work in CMM/LMM/XMM/XMMC modes, but is hampered by the blocking functions(sleep or waitcnt). But in my programs, the servo code to be exact, it will not work because of the waitcnt blocking affect. The pthread is nice, because you can use all available memory, but it has its limitations.

    It will be interesting to see what PropGCC for the P2 will look like. Will a lot of the limitations that I have been experiencing so far, go away with the new chip and the new PropGCC? But when you think about it, Spin will have to be improved, to use the extra memory capabilities, so the new Spin might be able to use LMM/XMM/XMMC modes? Will be able to start and use threads in the new Spin? Will I end up severely hampered by the inability to choose between Spin or PropGCC for a programming choice?

    Ray
  • jazzedjazzed Posts: 11,803
    edited 2013-01-12 08:20
    Rsadeika wrote: »
    For the threads, I have been exposed to the cog thread, which behaves a lot like a cognew, in the Spin world, but it is still handled as a thread. This can run in an LMM/CMM mode, but not in XMM/XMMC mode.

    Theoretically COG "threads" started with cogstart or _start_cog_thread could be made to run in XMM/XMMC mode if the thread function is set to run from hub memory using the HUBTEXT attribute. All functions called by the thread would also need to be set to run in hub memory. This needs to be tested.
    Rsadeika wrote: »
    When I introduced another cog thread that contained an fgets function, that seems to have an affect on how the servo functions would work.

    This refers to COG "threads" started with cogstart .... There should not be any interaction with fgets if the IO device is set to non-buffered operation as described several times before.
    Rsadeika wrote: »
    It will be interesting to see what PropGCC for the P2 will look like. Will a lot of the limitations that I have been experiencing so far, go away with the new chip and the new PropGCC?

    Propeller GCC for P2 will be very much like P1 Propeller GCC except running faster in all memory models.
    Rsadeika wrote: »
    Will I end up severely hampered by the inability to choose between Spin or PropGCC for a programming choice?

    There has been some discussion of using spin2cpp in a C or C++ project to integrate SPIN and C. The names of SPIN functions may be different though. This could probably be done today, but I haven't tested it. My priority however is finishing updates to SimpleIDE for education.
  • jazzedjazzed Posts: 11,803
    edited 2013-01-12 09:06
    jazzed wrote: »
    Theoretically COG "threads" started with cogstart or _start_cog_thread could be made to run in XMM/XMMC mode if the thread function is set to run from hub memory using the HUBTEXT attribute. All functions called by the thread would also need to be set to run in hub memory. This needs to be tested.

    Well, theoretically not. The XMM machine is not loaded into HUB RAM like the LMM machine is. I'll make an issue for the P2 phase to keep track.
  • David BetzDavid Betz Posts: 14,516
    edited 2013-01-14 05:31
    jazzed wrote: »
    Well, theoretically not. The XMM machine is not loaded into HUB RAM like the LMM machine is. I'll make an issue for the P2 phase to keep track.
    I think we need to be careful of how we resolve this issue. I think it would be a bad idea to just grab 2K bytes of hub memory in every XMM program just in case someone wants to call _start_cog_thread. What I'll probably do is make the COG image available only if that function is actually used in a program. Then you only lose 2K of hub memory if you are actually starting other C threads. Of course, Steve's comment about HUBTEXT will still apply. Any C code that you start using _start_cog_thread will have to be in hub memory and also any functions that it calls. There is currently no way to share the external memory interface between COGs. That could be added as another issue I guess but I think the cache thrashing we'd see if we enabled that feature might make it less than useful.
  • RsadeikaRsadeika Posts: 3,837
    edited 2013-01-14 08:29
    I narrowed the communication problem between the two boards down to the serial pinout on the PSCU board. After staring at the PSCUsb_A schematic, I am having a big problem trying to decipher what kind of data the serial pin is expecting. Now if it is inverted, or such, how do I do that using SSER or FDS? I know that in the Spin version of FDS, you can select 0,1, or 2, I believe, to achieve this. How is this, or something like that done in C version of SSER or FDS? The PSCU board uses 74VHC1G66 and TXS0101 chips to deal with the serial pins, not a hardware person, I have never come across these, so I am not sure what these chips are doing.

    Ray
  • jazzedjazzed Posts: 11,803
    edited 2013-01-15 10:15
    Rsadeika wrote: »
    I narrowed the communication problem between the two boards down to the serial pinout on the PSCU board. After staring at the PSCUsb_A schematic, I am having a big problem trying to decipher what kind of data the serial pin is expecting. Now if it is inverted, or such, how do I do that using SSER or FDS? ...

    I swear I saw code that makes it possible to invert the sense of the serial lines. Did I dream it?

    This question has come up before and we have not provided a good answer.
    Meanwhile, you could try the FDSerial port I posted in another thread.

    FDSerial for Propeller-GCC
  • ersmithersmith Posts: 6,054
    edited 2013-01-15 12:03
    jazzed wrote: »
    I swear I saw code that makes it possible to invert the sense of the serial lines. Did I dream it?
    Not quite. The full duplex serial cog has that ability, of course, and there's even a parameter in some of the low level C code to expose it; but unfortunately that's a private function, and there's no way to access that functionality from fopen().

    We can change that in a future release, but for now it'll be necessary to use a different driver, either the one jazzed posted a link to or a conversion of FullDuplexSerial using spin2cpp.

    Eric
  • RsadeikaRsadeika Posts: 3,837
    edited 2013-01-16 06:06
    I finally got a communications link between the two boards working. I am using the FDSerial port that jazzed referenced to, but be aware that in order to make it work, you need to add:
    extern _Driver _FullDuplexSerialDriver;
    
    _Driver *_driverlist[] = {
        &_FullDuplexSerialDriver,
        NULL
    };
    
    just having:
    _Driver *_driverlist[] = {
        NULL
    };
    
    does not work, I guess that driverlist problem has not been fixed. Now, to build the program back up, and see if I can get those servos to move when commanded from an external board.

    I guess in order to communicate with the PSCU board, you need to do the FdSerial_tx/FdSerial_rx commands, I guess the fputs()/fgetc() stuff is not working for me, at least not with the PSCU/DNA-RTC boards .

    Ray
  • RsadeikaRsadeika Posts: 3,837
    edited 2013-01-16 07:42
    Yes, I got the servos to move forward. This is the absolute basic programs to get the servos to start and stop, and communicate between two boards. If somebody wants to test it out on there own setup, I would like to get some feedback. It is to bad that the SSER or FDS drivers do not have the equivalent commands as found in the FdSerial.c program.

    Ray

    RBBmaster
    /**
     * @file RBBmaster.c
     * This is the main RBBmaster program start point.
     */
    #include <propeller.h>
    #include <stdio.h>
    #include "FdSerial.h"
    
    extern _Driver _FullDuplexSerialDriver;
    
    _Driver *_driverlist[] = {
        &_FullDuplexSerialDriver,
        NULL
    };
    
    //FILE *cmdout;
    
    int high(int WCpin)
    {
        unsigned int bits = 1 << WCpin;
        DIRA |= bits;
        OUTA |= bits;
        return 0;
    }
    
    int low(int WCpin)
    {
        unsigned int mask = 1 << WCpin;
        DIRA |= mask;
        OUTA &= ~mask;
        return 0;
    }
    
    /**
     * Main program function.
     */
    int main(void)
    {
        int cout;
        printf("Before serial start\n");
    
    /*                              Tx Rx         */    
    //    cmdout = fopen("SSER:2400,13,35","w");
    /***********************************************/
    /*                 Rx Tx Mode Baud        */
        FdSerial_start(35,13,0,   2400);
        
        waitcnt(CLKFREQ + CNT);
        printf("Start of program\n");
        
        while(1)
        {
            cout = getc(stdin);
            if (cout == 'f')
    
                FdSerial_tx('f');
            if (cout == 's')
                FdSerial_tx('s');   
        }   
        return 0;
    }
    

    RBBslave
    /**
     * @file RBBslave.c
     * This is the main RBBslave program start point.
     */
    #include <propeller.h>
    #include <stdio.h>
    #include <sys/thread.h>
    #include <FdSerial.h>
    
    extern _Driver _FullDuplexSerialDriver;
    
    _Driver *_driverlist[] = {
        &_FullDuplexSerialDriver,
        NULL
    };
    
    #define STACK_SIZE 32
    
    int LEFT_SERVO_PIN = 1;  
    int RIGHT_SERVO_PIN = 0;
    
    #define LEFT_CENTER 1500
    #define RIGHT_CENTER 1500
    
    #define PAUSE_DIVISOR 50
    
    /* stacks for COGs */
    static int LeftServoStack  [STACK_SIZE];
    static int RightServoStack [STACK_SIZE];
    static int DataInStack [STACK_SIZE];
    
    /* per-thread library variables */
    static _thread_state_t LeftThreadData;
    static _thread_state_t RightThreadData;
    
    /* WheelServo COG variables */
    int LeftServoSpeed;
    int RightServoSpeed;
    int LeftRotation;
    int RightRotation;
    
    int StopNoPulse = 0;  //1
    static int MaxServoSpeed = 500;
    
    void LeftServoThread(void *arg __attribute__((unused)))
    {
        int pinmask = (1<<LEFT_SERVO_PIN);
        int center = LEFT_CENTER;
        int ustime = CLKFREQ/1000000;
        
        DIRA |= pinmask;
    
        for(;;) {
            /* start with signal off */
            OUTA &= ~pinmask;
    
            if(StopNoPulse && LeftServoSpeed == 0) {
                waitcnt(CLKFREQ/PAUSE_DIVISOR+CNT);
                LeftRotation = 0;
                continue;
            }
    
            if(LeftServoSpeed > MaxServoSpeed)
                LeftServoSpeed = MaxServoSpeed;
            if(LeftServoSpeed < -MaxServoSpeed)
                LeftServoSpeed = -MaxServoSpeed;
    
            /* move servo */
            LeftRotation = (LeftServoSpeed/2*center)/MaxServoSpeed+center;
                    
            waitcnt(CLKFREQ/PAUSE_DIVISOR+CNT);
            OUTA |=  pinmask;
            waitcnt(ustime*LeftRotation+CNT);
            OUTA ^=  pinmask;
    
        }
    }
    
    void RightServoThread(void *arg __attribute__((unused)))
    {
    
        int pinmask = (1<<RIGHT_SERVO_PIN);
        int center = RIGHT_CENTER;
        int ustime = CLKFREQ/1000000;
        
        DIRA |= pinmask;
    
        for(;;) {
            /* start with signal off */
            OUTA &= ~pinmask;
    
            if(StopNoPulse && RightServoSpeed == 0) {
                waitcnt(CLKFREQ/PAUSE_DIVISOR+CNT);
                RightRotation = 0;
                continue;
            }
    
            if(RightServoSpeed > MaxServoSpeed)
                RightServoSpeed = MaxServoSpeed;
            if(RightServoSpeed < -MaxServoSpeed)
                RightServoSpeed = -MaxServoSpeed;
    
            /* move servo */
            RightRotation = (-RightServoSpeed/2*center)/MaxServoSpeed+center;
            waitcnt(CLKFREQ/PAUSE_DIVISOR+CNT);
            OUTA |=  pinmask;
            waitcnt(ustime*RightRotation+CNT);
            OUTA ^=  pinmask;
        }
    }
    
    void startServoThreads(void)
    {
        int n;
        n = _start_cog_thread(LeftServoStack + STACK_SIZE, LeftServoThread, NULL, &LeftThreadData);
        
        n = _start_cog_thread(RightServoStack + STACK_SIZE, RightServoThread, NULL, &RightThreadData);
            
    }
    
    void botStop(void)
    {
        LeftServoSpeed = 0;
        RightServoSpeed = 0;
    }
    
    void botForward(int rate)
    {
        LeftServoSpeed = rate;
        RightServoSpeed = rate;
    }
    
    void botReverse(int rate)
    {
        LeftServoSpeed = -rate;
        RightServoSpeed = -rate;
    }
    
    void botSpeed(int rate)
    {
        LeftServoSpeed = LeftServoSpeed >= 0 ? rate : -rate;
        RightServoSpeed = RightServoSpeed >= 0 ? rate : -rate;
    }
    
    int high(int WCpin)
    {
        unsigned int bits = 1 << WCpin;
        DIRA |= bits;
        OUTA |= bits;
        return 0;
    }
    
    int low(int WCpin)
    {
        unsigned int mask = 1 << WCpin;
        DIRA |= mask;
        OUTA &= ~mask;
        return 0;
    }
    
    
    /**
     * Main program function.
     */
    int main(void)
    {
        int speed = 20;
        startServoThreads();
    
    /*                        Baud Tx Rx   read  */
    //    cmdin = fopen("SSER:2400,35,27","r");
        int cin;
    /*                 Rx Tx Mode Baud   */    
        FdSerial_start(27,35,0,   2400);
    
    //    botForward(speed);
    //    sleep(4);
    //    botStop();
                    
        while(1)
        {
            cin = FdSerial_rxtime(25);
            if (cin == 'f')
                botForward(speed);
            if (cin == 's')
                botStop();
        }
    
        return 0;
    }
    
  • jazzedjazzed Posts: 11,803
    edited 2013-01-16 08:10
    What is pin 35?
    ... does not work, I guess that driverlist problem has not been fixed. ....

    Please explain your expectation.

    Thanks,
    --Steve
  • RsadeikaRsadeika Posts: 3,837
    edited 2013-01-16 08:36
    The FdSerial_start() will not except 'NULL' as a pin designation so I just use 35 as a null. When I insert your code, the program does not run correctly with your driverlist structure, the program compiles, but... When I comment out the driverlist structure, the program runs, but the FdSerial() does not work. For me, the way I have it setup, it just works. So, I am not sure as to what the problem is, at some point I will double check it again.

    Ray
  • jazzedjazzed Posts: 11,803
    edited 2013-01-16 09:16
    Rsadeika wrote: »
    The FdSerial_start() will not except 'NULL' as a pin designation so I just use 35 as a null.

    I see. Very clever. My advice is that clever things should usually be commented.
    Rsadeika wrote: »
    When I insert your code, the program does not run correctly with your driverlist structure, the program compiles, but... When I comment out the driverlist structure, the program runs, but the FdSerial() does not work.

    Making the first entry of the driver structure NULL turns off the standard console as noted in the comments.
    Rsadeika wrote: »
    For me, the way I have it setup, it just works. So, I am not sure as to what the problem is, at some point I will double check it again.

    Yes, it should work like that. I can only assume that you ended up with an invalid configuration somewhere along the way. For example, we can not use FdSerial on the same IO as the standard console (P30/31) without turning the console off. The FdSerial pins must be different.

    If you want to turn off the console and still have other standard IO devices, the first entry should be _NullDriver which is different from NULL (NULL terminates the driver setup list).


  • kuronekokuroneko Posts: 3,623
    edited 2013-01-16 15:52
    Rsadeika wrote: »
    The FdSerial_start() will not except 'NULL' as a pin designation so I just use 35 as a null.
    How do you know that 35 is really ignored (and not simply interpreted as 3, %001_00011)?
  • RsadeikaRsadeika Posts: 3,837
    edited 2013-01-18 08:01
    Below I have my latest RemBoxBot program, but it has a problem that I can not pin down. When I have the RBBmaster program loaded to ram, and run in the terminal mode, the program seems to work as expected. Using my terminal program, I can access the XBee, and basically do the basic commands. The problem that is cropping up is, when I "Burn Project" to the EEPROM, it shows up as being loaded correctly, with no errors. Then when I start up the robot, my terminal program, to access the XBee, seems like it is not connected to the DNA board, but nothing in the hardware has changed. The settings are, starting with Board Type: DNA, C, XMMC, -Os Size. So it works as expected when in the programming mode, but it does not work when it is loaded to the EEPROM. Is this strictly a problem with the DNA-RTC board?

    The other thing that I noticed, in programming mode, if I change the board type to DNA-SDLOAD the program no longer works correctly. In fact that occurs in all the board types, except for just the DNA selection. Is this a problem with the cfg file? I downloaded the latest from the DNA-RTC web site.

    I need some help with this one.

    Thanks

    Ray
  • jazzedjazzed Posts: 11,803
    edited 2013-01-18 10:24
    Ray, there are some things that can be done to debug this.

    Assumption 1. always consider hardware without modifications as not bad.
    That is, until you know that the software works perfectly, unmodified hardware is innocent.

    Assumption 2. Any modified hardware may be mistakenly assembled.
    Check the connections for open/short circuits.

    Assumption 3. Something about the way the program starts is causing the problem.
    There are differences in timing between RAM start and EEPROM start. Check if that's an issue.

    Assumption 4. It is possible but unlikely that the EEPROM may not be correctly written.
    We can use some tools to read and compare the EEPROM to binaries.
    I don't have any such tools right now, and I don't have time to write them.
    Focus on assumption 1 through 3 for now or find a way to dump the EEPROM.

    BTW, I see you are still using waitcnt with pthreads. This is a big no-no as mentioned before.
  • RsadeikaRsadeika Posts: 3,837
    edited 2013-01-18 12:12
    BTW, I see you are still using waitcnt with pthreads. This is a big no-no as mentioned before.
    That is really bad habit I picked up. I changed it to a usleep(3000). I think I found the problem, and the problem is the DNA-RTC board. I removed the DNA-RTC board and used my C3 board, and it works as expected. The C3 is lacking an RTC, which I wanted to include in my RBBmaster program, since there is no way of determining the voltage on the batteries, I wanted to use a built in clock to count off about four hours and then turn on a red LED to let me know it is time to charge up the batteries. I guess I could program a softRTC in the C3, but then every time you power off, you have to reset the clock on the next power on, and you lose track of the time elapsed, PIA.

    As for the DNA-RTC, I am starting to lose faith in the product, but there is no close replacement for the board configuration. What I liked about the board was access to 5V on the header, the flash RAM, the screw down power block, the RTC, and of course the SD. Now if somebody had a fully assembled expansion board for the QuickStart, with the same configuration, and I put an emphasis on assembled, not kit, that could be a winner.

    The reason I am not just using the C3 for the servos, and the master program, I still do not know how to mix the cog threads that the servos need, and a pthread that the access to the XBee needs. There are other things that need to be done, which will force me to use a two board setup. This prototype robot is starting to look like a complete mess with all kinds of wires sticking out, and boards that look like they belong in another project.

    So, on to working with the C3 board, until I run into a problem with that board, then I do not know what I will do next...

    Ray
  • RsadeikaRsadeika Posts: 3,837
    edited 2013-01-18 13:18
    My DNA-RTC board is dead, I am now getting the dreaded "error: no propeller chip on port 'COMxx'". So I guess the DNA-RTC board could not stand up to the rigors of robot life. I have to find a comparable board that can deal with the problems the DNA-RTC board could not. I guess for the time being, the C3 will have to suffice.

    Ray
  • jazzedjazzed Posts: 11,803
    edited 2013-01-19 09:01
    Rsadeika wrote: »
    My DNA-RTC board is dead, I am now getting the dreaded "error: no propeller chip on port 'COMxx'".

    I'm sorry to hear that. I'm curious though. Can you describe your typical connections with power, servos, and other devices?
  • RsadeikaRsadeika Posts: 3,837
    edited 2013-01-19 11:31
    I have a Parallax li-ion battery pack which powers the PSCU board, servo part, and the DNA board, now the C3 board. The only other thing I have is the Parallax XBee board, which gets powered from the DNA(C3) board. I had some resistors on the data lines between the XBee board and the main board, just in case. The PSCU board three pin serial connector was being powered from the DNA(C3) board, the data line does not require a resistor. So I am not sure that it would have been a power surge that did in the DNA board.

    Since I am using the C3 board now, and it has the flash ram, and the SRAM, how do you make use of the SRAM via some C code? Is there any C example code for using the SRAM?

    I think the next thing I might try is adding access to the SD card in the RBBmaster program. Since there is an SD library, does it have commands similar to what you would find in the FSRW program? I like Dave Hine's filetest program, but I wonder if there is a different way of writing to the SD card?

    Ray
  • jazzedjazzed Posts: 11,803
    edited 2013-01-21 09:18
    Rsadeika wrote: »
    Since I am using the C3 board now, and it has the flash ram, and the SRAM, how do you make use of the SRAM via some C code? Is there any C example code for using the SRAM?

    The XMM-SPLIT memory model uses Flash and SRAM on the C3 for code and data.
  • RsadeikaRsadeika Posts: 3,837
    edited 2013-01-21 10:44
    My DNA-RTC board is now being called Lazarus. I switched over to my Windows 7 PC, I wanted to give the DNA-RTC one last shot, and it is now working. So can I trust this board, or is this just a last gasp at life. I am really not sure what is going on now, one minute it was working, then it seemed like it died, now it seems like it is working again.

    Ray
  • jazzedjazzed Posts: 11,803
    edited 2013-01-21 13:55
    Rsadeika wrote: »
    My DNA-RTC board is now being called Lazarus. I switched over to my Windows 7 PC, I wanted to give the DNA-RTC one last shot, and it is now working. So can I trust this board, or is this just a last gasp at life. I am really not sure what is going on now, one minute it was working, then it seemed like it died, now it seems like it is working again.

    Ever heard of RCA? RCA stands for the Radio Corporation of America. There is another meaning of RCA in Silicon Valley (and other) engineering circles: that is, Root Cause Analysis.

    If you can't do a Root Cause Analysis of the problem, the DNA-RTC board may continue to fail intermittently.

    I didn't see anything in your usage description that would cause an issue. Perhaps there is a loose pin on the board or a voltage regulation problem? If you can isolate some error as a perfect explanation of the cause of your problem and fix it, then you're probably Ok.
Sign In or Register to comment.