Changes to Sumovore.h and Sumovore.c for 2011

by Dan Peirce B.Sc.

Oct. 21, 2010 -- (rev. Oct 27, 2010)

new files (simple line follower project) Robot/main.c | Robot/motor_control.c | Robot/motor_control.h | Robot/sumovore.c  | Robot/sumovore.h  | Robot/interrupts.c | Robot/interrupts.hRobot/simple_curve_follower.hex


Two new files were added to support the low voltage detect <LVD> feature. Interrupts.c and interrupts.h.

I have also changed sumovore.c and sumovore.h so that the low voltage detect, brownout reset, stack overflow reset and watchdog timer features are now enabled. This will force the students to change batteries if the PIC starts to detect low voltage conditions (which could otherwise make code execution unreliable). The stack overflow will reset the PIC if it detects that the hardware stack actually becomes full (unlikely unless the code has recursive function calls). The watchdog timer will reset the processor if it is allowed to timeout (could happen if the processor goes into an undefined state or if there is an unexpected endless loop in the code).

One difference with these new files (and a updated main.c) is that when the robot is turned on (or if any sort of reset occurs ) initially it will sit still with LED1 and LED2 flashing alternately (a clear indication of a reset). If the reset was a normal Power On Reset normal code execution will occur after a few seconds. If the reset was a result of a brownout or low voltage detection or something else the LEDs will indicate the cause and the robot will do nothing else until a power on reset has occurred!

One change is that when the robot turns on led1 and led2 flash alternately for a few seconds. If no other LED's go on at that time this indicates a normal Power On Reset  <POR>.
If the LED's keep flashing then a code should be displayed to show the problem

LED
3  4  5
0  0  1  Brown Out Reset   <BOR>      (fixed error in table March 3, 2011)
0  1  0  Low Voltage Detect   <LVD>
0  1  1  <not defined> should not get this
1  0  0  WatchDog Timer reset  <WDT>
1  0  1  Stack Overflow   <SCKFUL>
1  1  1  RESET task <reset>  (say a software reset -- this one has not been tested)

If a communication cable is attached to the robot messages will also be sent to a PC ( <POR>, <LVD>, <BOR>... ).

As it stands now the robots themselves will tell us when BOR and/or LVD's start to occur. This will start to occur as the batteries become depleted. If they happen frequently it is time to change the batteries.  If they happen very infrequently then one may want to continue using the same batteries a little longer but at least one will know the issue at a given time was a brownout or LVD and not a program error. I don't think they will occur at all with completely fresh batteries (based on the testing I was able to do).

I'd suggest that if a BOR or a LVD were to occur during a competition that the students be permitted to redo that run.

For the older version 1.0 of the robots the addition of  22 microFarad capacitor to the output of that regulator seems to solve problems of inconsistent PIC behavior that sometimes occur when the motors are started up at less than 100% duty cycle. Bob has replaced all of the older robots in Surrey but I have 8 of them still in use in Richmond. Exploring the issues of what was going on with the unreliable code execution was facilitated by the creation of a diagnostic program, and the realization that the version 1.1 robots did not have the same issue as the version 1.0 robots (2009 was the first year I had any of the version 1.1 robots in operation). So far as I can tell the addition of the 22 microFard capacitor makes the older robots as reliable as the new ones. I bring this up here because prior to this modification attempting to use less than 100% duty cycle on the version 1.0 robots would probably have made them significantly less reliable than leaving both motors at 100% and this would have implication regarding keeping the robot running smoothly. Not all of the robots are modified yet. The robot types are easy to identify when looking at the main board.



My new main.c (for the simple line follower project) looks like this:


#include <stdio.h>
#include <p18f4525.h>
#include "sumovore.h"
#include "motor_control.h"
#include "interrupts.h"
 

// main acts as a cyclical task sequencer
void main(void)
{

    initialization(); // function from sumovore.c
                      // it sets up pwm (using timer2),
                      // IO pins, the ADC, the
                      // USART and the default
                      // threshold
    printf("\n\rKwantlen APSC1299 simple curve follower -- with error codes\n\r");
    ClrWdt();         // defined in <p18f4525.h>

    while(1)
    {
        check_sensors();    // from sumovore.c
        set_leds();         // function from sumovore.c
                     // each LED indicates a sensor
                     // value. If you need to use the LED's for
                     // a different purpose change this line
                     // and make your own LED setting function
        motor_control();    // function from motor_control.c
        ClrWdt();           // defined in <p18f4525.h>
        if(lvd_flag_set())  LVtrap();
    }
}



sumovore.c has a number of new functions:


void PORtask(void)  // rev. June 18, 2010
{
    unsigned long count1=0, count2=0;
    StatusReset();       // sets flags /POR and /BOR
                         //  comment corrected Feb. 25, 2011
    printf("<POR>");
    setLED1(1);
    setLED2(0);
    setLED3(0);
    setLED4(0);
    setLED5(0);
    while(count1<10u)       //trap here
    {
        ClrWdt();
        if (count2==30000u)
        {
            count2=0;
            count1++;
            setLED1(1);
            setLED2(0);
        }
        else if (count2==15000u)
        {
            setLED1(0);
            setLED2(1);
        }
        count2++;
    }
}

void BORtask(void)  // rev. June 18, 2010
{
    StatusReset();       // sets flags /POR and /BOR
                         // comment corrected Feb. 25, 2011
    printf("<BOR>");
    setLED1(0);
    setLED2(0);
    setLED3(0);
    setLED4(0);
    setLED5(1);
    gtrap();    // trap code here until POR
}

void WDTtask(void)  // rev. April 30, 2010
{
    printf("<WDT TO>");
    setLED1(1);
    setLED2(0);
    setLED3(1);
    setLED4(0);
    setLED5(0);
    gtrap();    // trap code here until POR
}

void STKFULtask(void)    // rev. April 30, 2010
{
                           // An error on the hardware stack
    STKPTRbits.STKFUL = 0; //  caused a reset!
    printf("<STKFUL>");    //  continue
    setLED1(1);
    setLED2(0);
    setLED3(1);
    setLED4(0);
    setLED5(1);
    gtrap();    // trap code here until POR
}

void RESETtask(void)    // rev. April 30, 2010
{

    printf(" <reset> "); // may modify this to count # of POR
    setLED1(1);
    setLED2(0);
    setLED3(1);
    setLED4(1);
    setLED5(1);
    gtrap();    // trap code here until POR
}

// this function sets up the low voltage
//  detect feature of the PIC18F4525
//   sets HLVDIP to a high priority interupt
void openLVD(void)
{
    RCONbits.IPEN = 1;
    HLVDCONbits.HLVDEN = 1; // HLVDEN enabled

    IPR2bits.HLVDIP = 1; // sets HLVD to high priority
    HLVDCONbits.VDIRMAG = 0; // interupt occures if voltage below
                             //  trip point
    HLVDCONbits.HLVDL3 = 1; // set to about 4.59 volts
    HLVDCONbits.HLVDL2 = 1;
    HLVDCONbits.HLVDL1 = 1;
    HLVDCONbits.HLVDL0 = 0;
    PIR2bits.HLVDIF = 0; // ensure interupt is clear
    PIE2bits.HLVDIE = 1; // enables HLVD interupt
    INTCONbits.GIEH = 1; // globle enable of interupts
}

void LVtrap(void)
{
    printf("\\<LVD>");
    openPORTD();  // set as outputs for LED's
    setLED1(1);
    setLED2(0);
    setLED3(0);
    setLED4(1);
    setLED5(0);
    gtrap();    // trap code here until POR
}

void gtrap(void)
{
    unsigned long count=0;

    while(1)       //trap here
    {
        ClrWdt();
        if (count==30000u)
        {
            count=0;
            setLED1(1);
            setLED2(0);
        }
        else if (count==15000u)
        {
            setLED1(0);
            setLED2(1);
        }
        count++;
    }
}



and changes to the initilization() function


void initialization(void)
{
    RCONbits.IPEN = 1;      // rev. April 30, 2010
    INTCONbits.GIEH = 0;    // rev. April 30, 2010
    INTCONbits.GIEL = 0;    // rev. April 30, 2010

    set_osc_32MHz();  // to change the internal oscillator frequency (see osc.h osc.c)
    openPORTCforUSART();

    OpenUSART( USART_TX_INT_OFF & USART_RX_INT_OFF & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_CONT_RX & USART_BRGH_HIGH,
             16 );            // for 19200 bit per second
                               // (32000000/115200/16)-1 = 16
                  // actual buad rate is 32000000/(16*(16+1)) = 117647 baud (note a 2% error in frequency)
      // see http://en.wikibooks.org/wiki/Serial_Programming/Typical_RS232_Hardware_Configuration#Oscillator_.26_Magic_Quartz_Crystal_Values
 

    openPORTD();
    PORTD = 0;  // TURN ALL LED'S OFF

    if( isPOR() ) PORtask();        // rev. April 30, 2010
    else if (isBOR() ) BORtask();
    else if(isWDTTO() ) WDTtask();
    else if(STKPTRbits.STKFUL) STKFULtask();
    else RESETtask();

    openPORTCforPWM();

    openPORTA();
    openPORTB();
    openPORTE();
 

    openLVD();
 
 

    OpenADC(ADC_FOSC_32 & ADC_RIGHT_JUST & ADC_6_TAD , ADC_CH1 & ADC_INT_OFF & ADC_VREFPLUS_VDD & ADC_VREFMINUS_VSS, AN0_AN4);
// AN0-AN4 is defined in sumovore.h the others are defined in adc.h (C18 library)

    RmotorGoFwd = NO;  // NO is defined as 0b0 in sumovore.h
    RmotorGoFwdCmp = NO;
    LmotorGoFwd = NO;
    LmotorGoFwdCmp = NO;
//  PWMperiod = [(period)+1]x 4 x Tosc x TMR2
//  period Tosc     TMR2Pre  pwm_period  freq
//  255     3.13E-08 16    5.12E-04  1.95E+03

    OpenTimer2(TIMER_INT_OFF & T2_PS_1_16 & T2_POST_1_1);  // TMR2 prescale is 16
    OpenPWM1(199);           // TPWM = (199+1)*4*(31.25 ns)*16
                             //      = 0.400 ms   or 2500 Hz
    OpenPWM2(199);
    SetDCPWM1(0);            // TDC  = 64*(31.25 ns)*16
                             //      = 0.032 ms
                             //      = 0% * TPWM  (800 will give 100%)
    SetDCPWM2(0);
    threshold = THRESHOLD_DEFAULT;

}


Changes to Sumovore.h and Sumovore.c for 2010

by Dan Peirce B.Sc.

Nov 17, 2009

new files  Robot/main.cRobot/motor_control.cRobot/motor_control.hRobot/sumovore.c Robot/sumovore.hsimple_curve_follower.mcpsimple_curve_follower.mcwsimple_curve_follower.hex


My new main.c looks like this:

#include "sumovore.h"
#include "motor_control.h"

// main acts as a cyclical task sequencer
void main(void)
{
    initialization(); // function from sumovore.c
                      // it sets up pwm (using timer2),
                      // IO pins, the ADC, the
                      // USART and the default
                      // threshold
    // can change threshold from default value here!
    //  threshold = {an unsigned int value}

    while(1)
    {
        check_sensors();
        set_leds();     // function from sumovore.c
                     // each LED indicates a sensor
                     // value. If you need to use the LED's for
                     // a different purpose change this line
                     // and make your own LED setting function
        motor_control(); // function from motor_control.c
    }
}

I noticed that now that we moved the definitions of check_sensors() and set_leds() to sumovore.c we did not need most of the #include directives that used to be in this file. I removed the unneeded directives. That got me thinking and I moved all the #pragma lines to the top of sumovore.c. This means the robot and PIC dependent stuff is all in sumovore.c and sumovore.h.
In this form main.c, motor_control.c and motor_control.h can be compiler, robot and IC independent.

This very simple version of main.c has the advantage of not containing extra junk.

I have added comments to sumovore.h

// ********************************************************************
// this file sumovore.h is for use with the solarbotics sumovore
//   and the PIC18F4525 and microchip 18C compiler
 

//  By Dan Peirce B.Sc.
//  For Kwantlen Polytechnic University
//  rev. Nov. 17 new function like macro's defined for LED's
//  rev. May 22, 2009 for brainboard 2
//  some comments revised March 5, 2007
//  rev. March 13, 2007
//  rev. March 2, 2007

// *******************************************************************

#define setLED1(a) PORTDbits.RD0=~a  // When a = ON or OFF,
#define setLED2(a) PORTDbits.RD1=~a  //  setLEDn(ON) turns on LEDn
#define setLED3(a) PORTDbits.RD2=~a  //  setLEDn(OFF) turns off LEDn
#define setLED4(a) PORTDbits.RD3=~a  // a could also be any char or integer
#define setLED5(a) PORTDbits.RD4=~a  // but only the least significant
                                     // bit will be used.

#define set_all_LEDs(a)  PORTD=(((~a)&0b00011111)|(PORTD&0b11100000))
     // in set_all_LEDs(a) a can be any 5 bit value or variable
     // if a has more than 5 bit the most significant bits will
     // be ignored

#define    LeftIR  !PORTDbits.RD5   // RD5 is pin 28
#define    RightIR !PORTDbits.RD6   // RD6 is pin 29
            // Note that the IR detectors output low when an object
            //     is detected so the not "!" of the pin is used
            //  in the define to maintain positive logic

#define    EnableRmotor  PORTCbits.RC2    // pin_c2  -- Enable Right motor
#define    EnableLmotor  PORTCbits.RC1    // pin_c1  -- Enable Left motor
#define    RmotorGoFwd   PORTCbits.RC5    // rev for bb2  -- Right motor forward
#define    RmotorGoFwdCmp PORTEbits.RE0   // rev for bb2  -- Right motor forward complement
#define    LmotorGoFwd   PORTCbits.RC0    // rev for bb2  -- Left motor forward
#define    LmotorGoFwdCmp PORTEbits.RE1   // rev for bb2  -- Left motor forward complement

#define    RLS_LeftCH0      ADC_CH0    // AN0  (left reflective line sensor)
#define    RLS_CntLeftCH1   ADC_CH1    // AN1  (center left reflective line sensor)
#define    RLS_CenterCH2    ADC_CH2    // AN2  (center reflective line sensor)
#define    RLS_CntRightCH3  ADC_CH3    // AN3  (center right reflective line sensor)
                    // Pin RA4 No connection
#define    RLS_RightCH4     ADC_CH4    // AN4  (right reflective line sensor)
                                       // note PortA is only 6 bits!

#define YES       0b1        // used to turn on an individual bit
#define NO        0b0        // used to turn off an individual bit
#define ON        0b1
#define OFF       0b0

#define AN0_AN4    0B1010  // used for configuration of PCFG3:PCFG0
                           // A/D port Configuration Control Bits
                           // these determine which pins are analog inputs
                           // see page 224 of PIC18F4525 datasheet

#define THRESHOLD_DEFAULT 512u

struct sensors
{
    unsigned     Left:1;
    unsigned  CntLeft:1;
    unsigned   Center:1;
    unsigned CntRight:1;
    unsigned    Right:1;
    unsigned :3;
};

union sensor_union
{
    unsigned char B;
    struct sensors b;
};

void initialization(void);  // defined in sumovore.c

unsigned int adc(unsigned char channel);  // defined in sumovore.c

enum motor_speed_setting { rev_fast, rev_medium, rev_slow, stop, slow, medium, fast };

enum motor_selection { left, right };

void set_motor_speed(enum motor_selection the_motor, enum motor_speed_setting motor_speed, int speed_modifier);
                 // defined in sumovore.c
void motors_brake_all( void );
void set_leds(void);
void check_sensors(void);

extern union sensor_union SeeLine;
 

I also removed some old comments from sumovore.c that were no longer consistant with the way it is set up. There was an old comment about the expectation that PWM would be used in a future versions of the file. PWM was included a long time ago. I also removed the initialization of the motor enable lines because that is not done by the PWM (and also has been that way for a long time).
 

// File sumovore.c by Dan Peirce B.Sc.

// Kwantlen Polytechnic University
// apsc1299

// rev. Nov. 17 2009 to make use of new LED macro's,
//        to incorparate #pragma lines and
//        to point to osc.h in Functions folder
// rev. june 2009 for dynamic braking
// rev. May 22, 2009 to refect changes for BB2
// rev. March 13, 2007
// rev. March 2, 2007
#pragma config WDT = OFF
#pragma config OSC = INTIO67  // allows osc1 (pin 13) and osc2 (pin 14) to be used as inputs
                              // note there is a crystal attached to these pins on the
                              // brainboard
#pragma config MCLRE = OFF
#pragma config LVP = OFF
// #pragma config lines must come before #include "sumovore.h" as sumovore.h redefines OFF!!!

#include <p18F4525.h>
#include <usart.h>
#include <stdio.h>
#include <adc.h>
#include <pwm.h>
#include <timers.h>
#include "..\Functions\osc.h"
#include "sumovore.h"
 

void openPORTCforPWM(void);
void openPORTCforUSART(void);
void openPORTA(void);
void openPORTB(void);
void openPORTD(void);
void openPORTE(void);

union sensor_union SeeLine = 0;
unsigned int threshold;    // value compared to adc result
 

void initialization(void)
{
    set_osc_32MHz();  // to change the internal oscillator frequency (see osc.h osc.c)
    openPORTCforUSART();

    OpenUSART( USART_TX_INT_OFF & USART_RX_INT_OFF & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_CONT_RX & USART_BRGH_HIGH,
             16 );            // for 19200 bit per second
                               // (32000000/19200/16)-1 = 103.17
                  // actual buad rate is 32000000/(16*(103+1)) = 19230.8 baud

    openPORTCforPWM();

    openPORTA();
    openPORTB();
    openPORTD();
    openPORTE();
    PORTD = 0;  // TURN ALL LED'S OFF
 

    OpenADC(ADC_FOSC_32 & ADC_RIGHT_JUST & ADC_6_TAD , ADC_CH1 & ADC_INT_OFF & ADC_VREFPLUS_VDD & ADC_VREFMINUS_VSS, AN0_AN4);
// AN0-AN4 is defined in sumovore.h the others are defined in adc.h (C18 library)

    RmotorGoFwd = NO;  // NO is defined as 0b0 in sumovore.h
    RmotorGoFwdCmp = NO;
    LmotorGoFwd = NO;
    LmotorGoFwdCmp = NO;
//  PWMperiod = [(period)+1]x 4 x Tosc x TMR2
//  period Tosc     TMR2Pre  pwm_period  freq
//  255     3.13E-08 16    5.12E-04  1.95E+03

    OpenTimer2(TIMER_INT_OFF & T2_PS_1_16 & T2_POST_1_1);  // TMR2 prescale is 16
    OpenPWM1(199);           // TPWM = (199+1)*4*(31.25 ns)*16
                             //      = 0.400 ms   or 2500 Hz
    OpenPWM2(199);
    SetDCPWM1(0);            // TDC  = 64*(31.25 ns)*16
                             //      = 0.032 ms
                             //      = 0% * TPWM  (800 will give 100%)
    SetDCPWM2(0);
    threshold = THRESHOLD_DEFAULT;

}

//***********************************************************************************
//                          openPORTCforUSART()
//***********************************************************************************
void openPORTCforUSART(void)
{
  TRISCbits.TRISC6 = 0;  // set TX (RC6) as output
  TRISCbits.TRISC7 = 1;  // and RX (RC7) as input
}

//***********************************************************************************
//                          openPORTCforPWM()
//***********************************************************************************
void openPORTCforPWM(void)
{
    TRISCbits.TRISC0 = 0; // Direction Left M
    TRISCbits.TRISC1 = 0; // Enable Left M
    TRISCbits.TRISC2 = 0; // Enable Right M
    TRISCbits.TRISC3 = 0; // I2C SCL
    TRISCbits.TRISC4 = 0; // I2C SDA
    TRISCbits.TRISC5 = 0; // Direction Right M
    // TRISC6 and TRISC 7 initialized in openPORTCforUSART()
}

//***********************************************************************************
//                          openPORTA()
//***********************************************************************************
void openPORTA(void)
{
    TRISA = 0B11101111; // RA0/AN0, RA1/AN1, RA2/AN2, RA3/AN3, RA5/AN4 SET AS INPUTS
                        // RA4 not used set as output
                        // bits RA6 and RA7 are left as inputs (crystal still attached
                        //  on sumovore)
}

//***********************************************************************************
//                          openPORTB()
//***********************************************************************************
void openPORTB(void)
{
    TRISB = 0B11000000; // PORTB mostly not used
                        // reserve pins 39 (RB6/PGC) and 40 (RB7/PGD)
                        // as inputs to avoid conflict if ISP and PICkit2
}

//***********************************************************************************
//                          openPORTD()
//***********************************************************************************
void openPORTD(void)
{
    TRISD = 0b01100000; // RD7 not connected
    // RD6 is IR Right, RD5 is IR Left, RD4 is LED5, RD3 is LED4
    // RD2 is LED3, RD1 is LED2 and RD0 is LED1
}

//***********************************************************************************
//                          openPORTE()
//***********************************************************************************
void openPORTE(void)
{
    TRISE = 0b000; // all outputs
                   // E0 and E1 are now used for motor direction and
                   // dynamic braking
                   // E2 is not used
}
 
 

void set_motor_speed(enum motor_selection the_motor, enum motor_speed_setting motor_speed, int speed_modifier)
{
    const static int motor_speeds[] = { -800, -600, -400, 0, 400, 600, 800};
    int duty_cycle;
    enum e_direction {reverse,forward} dir_modifier= forward;

    duty_cycle = motor_speeds[ motor_speed ] + speed_modifier;
    if ( duty_cycle < 0 )
    {
        dir_modifier = reverse;
        duty_cycle = -1 * duty_cycle;
    }
    if ( duty_cycle > 800 ) duty_cycle = 800;

    if (the_motor == left)
    {
        SetDCPWM2((unsigned int) duty_cycle );
        if ( dir_modifier == reverse ) LmotorGoFwd = NO;
        else LmotorGoFwd = YES;
        LmotorGoFwdCmp = !LmotorGoFwd;
    }
    else
    {
        SetDCPWM1((unsigned int) duty_cycle );
        if ( dir_modifier == reverse ) RmotorGoFwd = NO;
        else RmotorGoFwd = YES;
        RmotorGoFwdCmp = !RmotorGoFwd;
    }
}

void motors_brake_all( void )  // created june 26, 2009
{
    SetDCPWM1(800u ); // enable motors 100% for braking
    SetDCPWM2(800u ); //
    LmotorGoFwdCmp = NO; // ground all direction lines
    LmotorGoFwd = NO;  // motor terminals will have dead short
    RmotorGoFwdCmp = NO;
    RmotorGoFwd = NO;

}

unsigned int adc(unsigned char channel)
{
    SetChanADC( channel );
    ConvertADC();
    while( BusyADC() );

    return ReadADC();
}

// ****************************************************************
//                          check_sensors
// ****************************************************************
void check_sensors(void)
{
        SeeLine.b.Left = ( adc(RLS_LeftCH0) > threshold );      // adc() prototye in sumovore.h
        SeeLine.b.CntLeft = ( adc(RLS_CntLeftCH1) > threshold );   // adc() code in sumovore.c
        SeeLine.b.Center = ( adc(RLS_CenterCH2) > threshold );    //  ledx turns on when corresponding
        SeeLine.b.CntRight = ( adc(RLS_CntRightCH3) > threshold );  //    reflective sensore sees a line
        SeeLine.b.Right = ( adc(RLS_RightCH4) > threshold );
}
// ******************************************************************
 

// ****************************************************************
//                          set_leds
// ****************************************************************
void set_leds(void)
{
        setLED1(SeeLine.b.Left);
        setLED2(SeeLine.b.CntLeft);
        setLED3(SeeLine.b.Center);
        setLED4 (SeeLine.b.CntRight);
        setLED5(SeeLine.b.Right);
}
// ****************************************************************
 




Nov. 13, 2009

My current version of sumovore.c and sumovore.h.
 sumovre.c -- with changes for Brainboard 2 and dynamic braking
sumovre.h  -- with changes for Brainboard 2 and dynamic braking

If corrections additions are required I will update these files.




Oct. 08, 2009
With the new files students will have more choices for the motor_speed parameter   (2009 pages 45, 140):
enum motor_speed_setting { rev_fast, rev_medium, rev_slow, stop, slow, medium, fast };
The new set_motor_speed() function sets LmotorGoFwd and RmotorGoFwd  (based on if it is a forward or reverse speed) so the students don't actually have to manipulate those direction variables themselves. Also the robots have been modified to allow for dynamic braking (more on this down below). This means that there are now four direction lines defined rather than two.

Changes resulting from using the new mother boards will be transparent to the students apart from the macro definitions shown on page 139. The new macro's look like

#define    EnableRmotor  PORTCbits.RC2    // pin_c2  -- Enable Right motor
#define    EnableLmotor  PORTCbits.RC1    // pin_c1  -- Enable Left motor
#define    RmotorGoFwd   PORTCbits.RC5    // rev for bb2  -- Right motor forward
#define    RmotorGoFwdCmp PORTEbits.RE0   // rev for bb2  -- Right motor forward complement
#define    LmotorGoFwd   PORTCbits.RC0    // rev for bb2  -- Left motor forward
#define    LmotorGoFwdCmp PORTEbits.RE1   // rev for bb2  -- Left motor forward complement
A modification to the brain board and robot allows one to use dynamic braking. This should allow batteries to be used over a wider part of the discharge curve (braking by reversing the motors draws down old batteries a great deal). Dynamic braking occurs when the motor leads are shorted together. This can be achieved by grounding both sides of the motor. A modification to the robot and brainboard permit the grounding of both sides of the motor. From the student perspective they can simply use a new function declaired in sumovore.h.
 
void motors_brake_all( void );

The function is defined in sumovore.c

void motors_brake_all( void )  // created june 26, 2009
{
    SetDCPWM1(800u ); // enable motors 100% for braking
    SetDCPWM2(800u ); //
    LmotorGoFwdCmp = NO; // ground all direction lines
    LmotorGoFwd = NO;  // motor terminals will have dead short
    RmotorGoFwdCmp = NO;
    RmotorGoFwd = NO;

}


Some variable names were improved (changed)  page 140.

void check_sensors(void)
{
        SeeLine.b.Left = ( adc(RLS_LeftCH0) > threshold );      // adc() prototye in sumovore.h
        SeeLine.b.CntLeft = ( adc(RLS_CntLeftCH1) > threshold );   // adc() code in sumovore.c
        SeeLine.b.Center = ( adc(RLS_CenterCH2) > (threshold) );    //  ledx turns on when corresponding
        SeeLine.b.CntRight = ( adc(RLS_CntRightCH3) > threshold );  //    reflective sensore sees a line
        SeeLine.b.Right = ( adc(RLS_RightCH4) > (threshold) );
}
void set_leds(void)
{
        LED1 = !SeeLine.b.Left;
        LED2 = !SeeLine.b.CntLeft;
        LED3 = !SeeLine.b.Center;
        LED4 = !SeeLine.b.CntRight;
        LED5 = !SeeLine.b.Right;
}


The inversion on the LEDx assingments is requried because the LED's on the new brain board are wired from the output pin to +5. On the old boards they were wired between the output pin and ground.

Note the the definition of SeeLine has changed to a union so that individual bits can be set (as shown up above) or the entire byte can be accessed at once using SeeLine.B. An Example:
   test = SeeLine.B & 0b00010001;     // mask off  inner three sensors SeeLine.B is an unsigned char
   switch (test)                     // use both outer sensors only in this switch statment

declaration is as follows (in sumovore.h) :

struct sensors
{
    unsigned     Left:1;
    unsigned  CntLeft:1;
    unsigned   Center:1;
    unsigned CntRight:1;
    unsigned    Right:1;
    unsigned :3;
};

union sensor_union
{
    unsigned char B;
    struct sensors b;
};

extern union sensor_union SeeLine;


The declarations allow all files that include sumovore.h to make use of SeeLine. SeeLine can only be defined once and that is in sumovore.c

union sensor_union SeeLine;
Note that "Edge" has been dropped from the names in the sensor structure since Edge makes little sense here and just makes the varible names longer. Solarbotics uses "Edge" in the designations because the sumovore is primarally sold as a minisumo robot and in that event the reflective sensors are used to detect the edge of the minisumo ring.

Macro's are shown on page 139 for the Reflective Line Sensors (RLS). I have changed the names as follows:

#define    RLS_LeftCH0      ADC_CH0    // AN0  (left reflective line sensor)
#define    RLS_CntLeftCH1   ADC_CH1    // AN1  (center left reflective line sensor)
#define    RLS_CenterCH2    ADC_CH2    // AN2  (center reflective line sensor)
#define    RLS_CntRightCH3  ADC_CH3    // AN3  (center right reflective line sensor)
                    // Pin RA4 No connection
#define    RLS_RightCH4     ADC_CH4    // AN4  (right reflective line sensor)
                                       // note PortA is only 6 bits!
Those names are long but they don't get used in more than one place and they are very descriptive indicating that this is an input from a RLS, a description of which channel (center...) and an indication of which channel of the ADC is used.


I have suggested giving the students a simpler version of simple_curve_follower.c. Simpler algorithm but a little more structure to make it more obvious where to put their code. The structure in this example project would also encourage the students to write the code they add in a modular form using functions.

The very simple control that works only with a very simple oval track is provided by the following function

void very_simple_control(void)
{
     if ( SeeLine.b.Center )straight_fwd();
     else if ( SeeLine.b.CntLeft || SeeLine.b.Left) turn_left();
     else if ( SeeLine.b.CntRight || SeeLine.b.Right)turn_right();
}
This code can only follow gentle curves.