Introducing Robotics 3.1…

Robotics 3.1 is an optional module available to final-year students of the level 7 Electrical & Control Engineering programme (DT009) in the Dublin Institute of Technology. The learning outcomes of the module are:

  • Explain, carry out analysis and solve problems associated with fundamental electrical and mechanical engineering science,
  • List, outline and discuss comparative features of robot technology,
  • Explain and compare the operation, characteristics, and application of robot actuators,
  • Design, build and test electric robot actuator control subsystems,
  • Explain and compare the operation, application and characteristics of robot environment sensors,
  • Design, build and test robot environment sensing subsystems,
  • Design, build and test computer and microcontroller controlled robot subsystems.

The module is very practically focused and involves implementing various robot subsystems. Each student also undertakes a mini-project in which he or she designs, builds and tests a small robotic system.

The revision material presented here is divided into the following sections:

  1. Introduction to robotic technology
  2. Fundamental electrical, mechanical and control principles
  3. The dsPIC microcontroller
  4. Actuators and power electronics

To assist in exam preparation, the structure of each section combines revision notes with additional content in question and answer format.

Standard Hardware Kit for Robotics 3.1

  • 1 ziploc bag
  • 1 geared dc motor
  • 1 stepper motor
  • 1 servo motor
  • 1 breadboard
  • 1 PICkit2
  • 1 USB to mini USB cable
  • 1 dsPIC30F4011 microcontroller
  • 1 SN754410NE quad half H-bridge IC
  • 2 BC237 NPN transistors (or similar)
  • 1 6-pin header
  • A few LEDs
  • A few resistors
  • 1 potentiometers
  • 1 4xAA battery holder
Posted in Uncategorized | Leave a comment

Millisecond timer for state machine using Timer 1 interrupt

//
// Timer interrupt example for dsPIC30F4011
// Written by Ted Burke - 16-11-2016
//
// This is a simple state machine with four
// states. The current state is indicated
// using two LEDs. All state transitions are
// triggered by time elapsed since the
// previous state transition, as measured
// using a millisecond counter which is
// incremented every 30000 instruction cycles
// by a Timer 1 interrupt service routine.
//

#include <xc.h>
#include <libpic30.h>

_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Clock speed = 7.5MHz x 16, i.e. 30 MIPS
_FWDT(WDT_OFF);                  // Watchdog timer off
_FBORPOR(MCLR_DIS);              // Disable reset pin

// These variables must be global because they
// are accessed by the main function and the ISR
int state = 1;        // state variable
int milliseconds = 0; // millisecond counter

// Timer 1 interrupt service routine (ISR)
void __attribute__((__interrupt__, __auto_psv__)) _T1Interrupt(void)
{
    _T1IF = 0;      // Clear Timer 1 interrupt flag
    milliseconds++; // Increment the millisecond counter
}

// This function resets the millisecond counter and changes state
void change_state(int n)
{
    milliseconds = 0;
    state = n;
}

int main()
{
    // Configure digital I/O
    TRISD = 0b1100; // RD0 and RD1 are the two LEDs
    
    // Configure Timer 1
    PR1 = 30000;          // Set the Timer 1 period to 1 ms (30000 * Tcy)
    TMR1 = 0;             // Reset Timer 1 counter
    _T1IE = 1;            // Enable Timer 1 interrupt
    T1CONbits.TCKPS = 0;  // Prescaler (0=1:1, 1=1:8, 2=1:64, 3=1:256)
    T1CONbits.TON = 1;    // Turn on Timer 1
    
    while(1)
    {
        if (state == 1)
        {
            // Display state on LEDs
            _LATD0 = 0;
            _LATD1 = 0;
            
            // Change state?
            if (milliseconds >= 500) change_state(2);
        }
        else if (state == 2)
        {
            // Display state on LEDs
            _LATD0 = 1;
            _LATD1 = 0;
            
            // Change state?
            if (milliseconds >= 500) change_state(3);
        }
        else if (state == 3)
        {
            // Display state on LEDs
            _LATD0 = 0;
            _LATD1 = 1;
            
            // Change state?
            if (milliseconds >= 2000) change_state(4);
        }
        else if (state == 4)
        {
            // Display state on LEDs
            _LATD0 = 1;
            _LATD1 = 1;
            
            // Change state?
            if (milliseconds >= 3000) change_state(1);
        }
    }
        
    return 0;
}
Posted in Uncategorized | Leave a comment

Two SCARA control examples from today’s class

This first example moves the SCARA’s end effector to the x,y point defined by the analog input voltages present on pins AN0 and AN1 respectively.

//
// dsPIC30F4011 SCARA Example
// In this example the x and y coordinates of the SCARA's end effector 
// are controlled by the analog voltages on AN0 and AN1 respectively.
// Written by Ted Burke
// Last updated 20-10-2016
//
 
#include <xc.h>
#include <math.h>
#include <stdio.h>
#include <libpic30.h>
 
// Configuration settings
_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, Fcy=30MHz
_FWDT(WDT_OFF);                  // Watchdog timer off
_FBORPOR(MCLR_DIS);              // Disable reset pin

// Function prototypes
unsigned int read_analog_channel(int n);

// Segment lengths in cm
const double L1 = 20.0;
const double L2 = 15.0;

int main()
{
    int Vx, Vy; // analog input voltages
    double x, y; // end effector position in cm
    
    // Configure AN0-AN8 as analog inputs
    ADCON3bits.ADCS = 15;  // Tad = 266ns, conversion time is 12*Tad
    ADCON1bits.ADON = 1;   // Turn ADC ON
 
    // Configure PWM for free running mode
    //
    //   PWM period = Tcy * prescale * PTPER = 0.33ns * 64 * PTPER
    //   PWM pulse width = (Tcy/2) * prescale * PDCx
    //
    PWMCON1 = 0x00FF;     // Enable all PWM pairs in complementary mode
    PTCONbits.PTCKPS = 3; // prescale=1:64 (0=1:1, 1=1:4, 2=1:16, 3=1:64)
    PTPER = 9375;         // 20ms PWM period (15-bit period value)
    PDC1 = 1406;          // 1.5ms pulse width on PWM channel 1
    PDC2 = 1406;          // 1.5ms pulse width on PWM channel 2
    PDC3 = 1406;          // 1.5ms pulse width on PWM channel 3
    PTMR = 0;             // Clear 15-bit PWM timer counter
    PTCONbits.PTEN = 1;   // Enable PWM time base
 
    // Setup UART
    U1BRG = 48;            // 38400 baud @ 30 MIPS
    U1MODEbits.UARTEN = 1; // Enable UART
 
    while(1)
    {
        // Read target position from potentiometers
        Vx = read_analog_channel(0); // 0-1023 represents 10 to 20 cm
        Vy = read_analog_channel(1); // 0-1023 represents 10 to 20 cm
        
        // convert into x,y coordinates in cm
        x = 10.0 + (10.0 * Vx / 1023.0);
        y = 10.0 + (10.0 * Vy / 1023.0);
        
        // Set SCARA position
        setSCARA(x, y);     
    }
 
    return 0;
}

//
// This function moves the end effector to the specified (x,y) point
//
void setSCARA(double x, double y)
{
    double S, E;
    
    // Inverse kinematique equations
    E = acos((x*x + y*y - L1*L1 - L2*L2) / (2*L1*L2));
    S = atan2(y,x) - acos((x*x + y*y + L1*L1 - L2*L2)
                           / (2*L1*sqrt(x*x + y*y)));
    
    // 937.5 PDC units per ms
    // 1ms < pw < 2ms -> 0 < S < 180
    // 1.0ms : 0deg, 1.5ms : 90deg, 2.0ms : 180deg 
    PDC1 = 937.5 * (1.0 + 1.0*S/M_PI);
    PDC2 = 937.5 * (1.0 + 1.0*E/M_PI);
}

//
// This function reads a single sample from the specified
// analog input. It should take less than 5us when the
// microcontroller is running at 30 MIPS.
// The dsPIC30F4011 has a 10-bit ADC, so the value
// returned is between 0 and 1023 inclusive.
//
unsigned int read_analog_channel(int channel)
{
    ADCHS = channel;          // Select the requested channel
    ADCON1bits.SAMP = 1;      // Start sampling
    __delay32(30);            // 1us delay @ 30 MIPS
    ADCON1bits.SAMP = 0;      // Start Converting
    while (!ADCON1bits.DONE); // Should take 12 * Tad = 3.2us
    return ADCBUF0;
}

This second example moves the SCARA’s end effector through a repeating sequence of four pre-defined x,y coordinates, stopping for 1 second at each point.

//
// dsPIC30F4011 SCARA Example
// This example steps through four pre-defined (x,y) points repeatedly.
// Written by Ted Burke
// Last updated 20-10-2016
//
 
#include <xc.h>
#include <math.h>
#include <stdio.h>
#include <libpic30.h>
 
// Configuration settings
_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, Fcy=30MHz
_FWDT(WDT_OFF);                  // Watchdog timer off
_FBORPOR(MCLR_DIS);              // Disable reset pin

// Function prototypes
unsigned int read_analog_channel(int n);

// Segment lengths cm
const double L1 = 20.0;
const double L2 = 15.0;

int main()
{
    int Vx, Vy; // analog input voltages
    double x, y; // end effector position in cm
    
    // Configure AN0-AN8 as analog inputs
    ADCON3bits.ADCS = 15;  // Tad = 266ns, conversion time is 12*Tad
    ADCON1bits.ADON = 1;   // Turn ADC ON
 
    // Configure PWM for free running mode
    //
    //   PWM period = Tcy * prescale * PTPER = 0.33ns * 64 * PTPER
    //   PWM pulse width = (Tcy/2) * prescale * PDCx
    //
    PWMCON1 = 0x00FF;     // Enable all PWM pairs in complementary mode
    PTCONbits.PTCKPS = 3; // prescale=1:64 (0=1:1, 1=1:4, 2=1:16, 3=1:64)
    PTPER = 9375;         // 20ms PWM period (15-bit period value)
    PDC1 = 1406;          // 1.5ms pulse width on PWM channel 1
    PDC2 = 1406;          // 1.5ms pulse width on PWM channel 2
    PDC3 = 1406;          // 1.5ms pulse width on PWM channel 3
    PTMR = 0;             // Clear 15-bit PWM timer counter
    PTCONbits.PTEN = 1;   // Enable PWM time base
 
    // Setup UART
    U1BRG = 48;            // 38400 baud @ 30 MIPS
    U1MODEbits.UARTEN = 1; // Enable UART
 
    double x[] = {10.0, 12.0, 13.5, 10.0};
    double y[] = {10.0, 18.0, 20.0, 15.0};
    
    // This is the main loop that steps through the points
    int n = 0;
    while(1)
    {
        setSCARA(x[n], y[n]);
        n = n + 1;
        if (n == 4) n = 0;
        __delay32(30000000); // 1 second delay at each point
    }
 
    return 0;
}

//
// This function moves the end effector to the specified (x,y) point
//
void setSCARA(double x, double y)
{
    double S, E;
    
    // Inverse kinematique equations
    E = acos((x*x + y*y - L1*L1 - L2*L2) / (2*L1*L2));
    S = atan2(y,x) - acos((x*x + y*y + L1*L1 - L2*L2)
                           / (2*L1*sqrt(x*x + y*y)));
    
    // 937.5 PDC units per ms
    // 1ms < pw < 2ms -> 0 < S < 180
    // 1.0ms : 0deg, 1.5ms : 90deg, 2.0ms : 180deg 
    PDC1 = 937.5 * (1.0 + 1.0*S/M_PI);
    PDC2 = 937.5 * (1.0 + 1.0*E/M_PI);
}

//
// This function reads a single sample from the specified
// analog input. It should take less than 5us when the
// microcontroller is running at 30 MIPS.
// The dsPIC30F4011 has a 10-bit ADC, so the value
// returned is between 0 and 1023 inclusive.
//
unsigned int read_analog_channel(int channel)
{
    ADCHS = channel;          // Select the requested channel
    ADCON1bits.SAMP = 1;      // Start sampling
    __delay32(30);            // 1us delay @ 30 MIPS
    ADCON1bits.SAMP = 0;      // Start Converting
    while (!ADCON1bits.DONE); // Should take 12 * Tad = 3.2us
    return ADCBUF0;
}
Posted in Uncategorized | Leave a comment

Stepper motor reference position example from today’s class

//
// Stepper control example for dsPIC30F4011
// Written by Ted Burke
// Last updated 13-10-2016
//

#include <xc.h>
#include <libpic30.h>
#include <stdio.h>

_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Clock speed = 7.5MHz x 16, i.e. 30 MIPS
_FWDT(WDT_OFF);                  // Watchdog timer off
_FBORPOR(MCLR_DIS);              // Disable reset pin

#define STEP_DELAY 150000

// Function prototype for step functions and analog read
void step_forward();
void step_back();
void steps(int count);
unsigned int read_analog_channel(int channel);

int main()
{
    // Configure digital I/O
    TRISD = 0b0000; // One digital output for each winding
    LATD  = 0b0000; // Initially, all windings are off
    
    // Setup UART
    U1BRG = 48;            // 38400 baud @ 30 MIPS
    U1MODEbits.UARTEN = 1; // Enable UART
 
    // Configure AN0-AN8 as analog inputs
    ADCON3bits.ADCS = 15;  // Tad = 266ns, conversion time is 12*Tad
    ADCON1bits.ADON = 1;   // Turn ADC ON
 
    // Move to reference position by stepping until the analog
    // voltage from the colour sensor exceeds a threshold
    while(read_analog_channel(0) < 512) step_forward();
    
    // Stay still for 2 seconds
    __delay32(60000000);
    
    // Then start ticking once every second (approx)
    while(1)
    {
        steps(34);
        __delay32(30000000);
    }
    
    return 0;
}

// This function moves the stepper motor through
// the steps specific in the "count" argument.
// Positive values result in forward steps.
// Negative values result in backwards steps.
void steps(int count)
{
    while (count > 0)
    {
        step_forward();
        count--;
    }
    
    while (count < 0)
    {
        step_back();
        count++;
    }
}

void step_forward()
{
    if      (LATD == 0b0001) LATD = 0b0010;
    else if (LATD == 0b0010) LATD = 0b0100;
    else if (LATD == 0b0100) LATD = 0b1000;
    else                     LATD = 0b0001;
    
    __delay32(STEP_DELAY);
}

void step_back()
{
    if      (LATD == 0b0001) LATD = 0b1000;
    else if (LATD == 0b0010) LATD = 0b0001;
    else if (LATD == 0b0100) LATD = 0b0010;
    else                     LATD = 0b0100;
    
    __delay32(STEP_DELAY);
}

// This function reads a single sample from the specified
// analog input. It should take less than 5us when the
// microcontroller is running at 30 MIPS.
// The dsPIC30F4011 has a 10-bit ADC, so the value
// returned is between 0 and 1023 inclusive.
unsigned int read_analog_channel(int channel)
{
    ADCHS = channel;          // Select the requested channel
    ADCON1bits.SAMP = 1;      // Start sampling
    __delay32(30);            // 1us delay @ 30 MIPS
    ADCON1bits.SAMP = 0;      // Start Converting
    while (!ADCON1bits.DONE); // Should take 12 * Tad = 3.2us
    return ADCBUF0;
}
Posted in Uncategorized | Leave a comment

Great video about the 28BYJ-48 stepper motor

I just came across this excellent video about the 28BYJ-48 stepper motor by Bret Stateham. It does a really outstanding job of explaining what’s going on inside that metal case! Thanks to Cormac McConigley for bringing this to my attention.

Posted in Uncategorized | Leave a comment

Timer Interrupt examples for dsPIC30F4011

This post features two timer interrupt examples for the dsPIC30F4011 microcontroller.

The first example just illustrates the bare essentials of setting up a Timer 1 interrupt and using it to increment a millisecond counter variable. The interrupt service routine (ISR), _T1Interrupt(), runs every 1ms. It simply resets the interrupt flag bit and then increments a global variable, ms_time. When ms_time reaches 1000 it is reset to 0. The main function switches an LED on or off depending on the value of ms_time. The net result is that the LED flashes on for 500ms and then off for 500ms over and over again.

//
// dsPIC30F4011 simple timer interrupt example
// Written by Ted Burke, Last updated 30-11-2015
//
 
#include <xc.h>
#include <libpic30.h>

// Configuration settings
_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, i.e. 30 MIPS
_FWDT(WDT_OFF);                  // Watchdog timer off
_FBORPOR(MCLR_DIS);              // Disable reset pin

int ms_time = 0; // used to count milliseconds

// Timer 1 interrupt service routine (ISR)
void __attribute__((__interrupt__, __auto_psv__)) _T1Interrupt(void)
{
    // Clear Timer 1 interrupt flag
    IFS0bits.T1IF = 0;
 
    // Increment the millisecond count
    ms_time = ms_time + 1;
    if (ms_time == 1000) ms_time = 0;
}

int main(void)
{
    _TRISC14 = 0;   // RC14 (pin 16) controls an LED
    
    // Configure Timer 1
    // Set PR1 and TCKPS to cause interrupt every 1ms
    PR1 = 30000;          // Set the Timer 1 period to 1ms
    T1CONbits.TCKPS = 0;  // Prescaler (0=1:1, 1=1:8, 2=1:64, 3=1:256)
    IEC0bits.T1IE = 1;    // Enable Timer 1 interrupt
    T1CONbits.TON = 1;    // Turn on Timer 1

    // Now just use ms_time value to make an LED flash
    while(1)
    {
        if (ms_time < 500) _LATD14 = 0; // LED off
        else _LATD14 = 1;               // LED on
    }
}

This second example is more complicated. In this case, the timer ISR not only increments the millisecond counter, ms_time, but it also looks after stepping the stepper motor backwards or forwards until it reaches a target angle determined by the global variable stepper_target. The timer ISR runs every 1ms, which is more frequent than the maximum stepping frequency of the stepper, so I used a little counter trick in the ISR to only step the motor every 3rd time an interrupt occurs. Of course, the stepper only steps when its current position is different from the target angle.

The actual sequence of stepper positions is determined by a simple state machine with four states. There’s nothing particularly significant about the angles I chose here – I just wanted to illustrate the principle of controlling stepper angle just by assigning a value to a global step counter variable and then leaving the timer ISR to do the job of moving the stepper to that angle one step at a time.

Here’s the full C code:

//
// dsPIC30F4011 stepper motor timer interrupt example
// Written by Ted Burke, Last updated 30-11-2015
//
 
#include <xc.h>
#include <libpic30.h>

// Configuration settings
_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, i.e. 30 MIPS
_FWDT(WDT_OFF);                  // Watchdog timer off
_FBORPOR(MCLR_DIS);              // Disable reset pin

int state = 1;            // State variable for state machine
int ms_time = 0;          // Counts milliseconds in current state

int stepper_target = 0;   // Assign a value to this to set stepper angle
int stepper_position = 0; // Used to count steps towards target value
int count = 0;            // Counts timer interrupts - step every 4th time

void change_state(int);   // Updates state variable and resets ms_time
void step_forward();      // Steps forward and increments stepper_position
void step_back();         // Steps backwards and decrements stepper_position
void led(int);            // Switch LED on or off

int main(void)
{
    // Digital outputs
    _TRISC14 = 0;   // RC14 (pin 16) controls an LED
    TRISD = 0b0000; // RD0-3 control the stepper motor
    
    // Configure Timer 1
    // Set PR1 and TCKPS to cause interrupt every 1ms
    PR1 = 30000;          // Set the Timer 1 period to 1ms
    T1CONbits.TCKPS = 0;  // Prescaler (0=1:1, 1=1:8, 2=1:64, 3=1:256)
    IEC0bits.T1IE = 1;    // Enable Timer 1 interrupt
    T1CONbits.TON = 1;    // Turn on Timer 1
    
    // This simple state machine moves the stepper
    // through a repeating sequence of 4 positions.
    // The state changes every 5 seconds.
    while(1)
    {
        if (state == 1)
        {
            led(1);                // LED on
            stepper_target = 0;    // stepper at 0 degrees
            if (ms_time >= 5000) change_state(2);
        }
        else if (state == 2)
        {
            led(0);                // LED off
            stepper_target = 1024; // stepper at 180 degrees
            if (ms_time >= 5000) change_state(3);
        }
        else if (state == 3)
        {
            led(1);                // LED on
            stepper_target = 1536; // stepper at 270 degrees
            if (ms_time >= 5000) change_state(4);
        }
        else if (state == 4)
        {
            led(0);                // LED off
            stepper_target = 512;  // stepper at 90 degrees
            if (ms_time >= 5000) change_state(1);
        }
    }
}

// Timer 1 interrupt service routine (ISR)
void __attribute__((__interrupt__, __auto_psv__)) _T1Interrupt(void)
{
    // Clear Timer 1 interrupt flag
    IFS0bits.T1IF = 0;
 
    // Increment the millisecond count
    ms_time = ms_time + 1;
    
    // Stepping every 1ms would be too often for the stepper,
    // so only step once every 3 interrupts.
    count = count + 1;
    if (count == 3)
    {
        // This only happens every 3rd interrupt - i.e. once every 3ms
        count = 0;
        if (stepper_position < stepper_target) step_forward();
        if (stepper_position > stepper_target) step_back();
    }
}

// This function updates the global state variable and resets
// the millisecond counter.
void change_state(int n)
{
    state = n;
    ms_time = 0;
}

// Move stepper motor forward one full step
void step_forward()
{
    if      (LATD == 0b0001) LATD = 0b0010;
    else if (LATD == 0b0010) LATD = 0b0100;
    else if (LATD == 0b0100) LATD = 0b1000;
    else if (LATD == 0b1000) LATD = 0b0001;
    else LATD = 0b0001;
    stepper_position = stepper_position + 1;
}

// Move stepper motor back one full step
void step_back()
{
    if      (LATD == 0b0001) LATD = 0b1000;
    else if (LATD == 0b0010) LATD = 0b0001;
    else if (LATD == 0b0100) LATD = 0b0010;
    else if (LATD == 0b1000) LATD = 0b0100;
    else LATD = 0b0001;
    stepper_position = stepper_position - 1;
}

void led(int on)
{
    if (on) _LATC14 = 1;
    else _LATC14 = 0;
}

dsPIC

Posted in Uncategorized | 1 Comment

Stepper robot example from today’s class

//
// stepperbot.c - Stepper robot example from class
// Left motor is on RD-3, right motor is on RE0-3
//
// Written by Ted Burke - last updated 17-11-2015
//

#include <xc.h>
#include <libpic30.h>
 
// Configuration settings
_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, Fcy=30MHz
_FWDT(WDT_OFF);                  // Watchdog timer off
_FBORPOR(MCLR_DIS);              // Disable reset pin

void forward(float);
void turn_left(float);
void turn_right(float);
void left_step_forward();
void left_step_back();
void right_step_forward();
void right_step_back();

const float mm_per_step = 0.2356;
const float degrees_per_step = 0.225;

int main()
{
    // Set up which pins are which
    TRISD = 0b1111111111110000;
    TRISE = 0b1111111111110000;
    
    while(1)
    {
        // Forward around half octagon
        forward(480);
        turn_right(45);
        forward(480);
        turn_right(45);
        forward(480);
        turn_right(45);
        forward(480);
        turn_right(180); // U turn
        
        // Back to beginning
        forward(480);
        turn_left(45);
        forward(480);
        turn_left(45);
        forward(480);
        turn_left(45);
        forward(480);
        turn_left(180); // U turn
    }

    return 0;
}

void forward(float millimetres)
{
    int steps = millimetres / mm_per_step;
    while(steps > 0)
    {
        left_step_forward();
        right_step_forward();
        __delay32(60000);
        steps = steps - 1;
    }
}

void turn_left(float degrees)
{
    int steps = degrees / degrees_per_step;
    while(steps > 0)
    {
        left_step_back();
        right_step_forward();
        __delay32(60000);
        steps = steps - 1;
    }
}

void turn_right(float degrees)
{
    int steps = degrees / degrees_per_step;
    while(steps > 0)
    {
        left_step_forward();
        right_step_back();
        __delay32(60000);
        steps = steps - 1;
    }
}

void left_step_forward()
{
    if      (LATD == 0b0001) LATD = 0b0010;
    else if (LATD == 0b0010) LATD = 0b0100;
    else if (LATD == 0b0100) LATD = 0b1000;
    else if (LATD == 0b1000) LATD = 0b0001;
    else LATD = 0b0001;
}

void left_step_back()
{
    if      (LATD == 0b0001) LATD = 0b1000;
    else if (LATD == 0b0010) LATD = 0b0001;
    else if (LATD == 0b0100) LATD = 0b0010;
    else if (LATD == 0b1000) LATD = 0b0100;
    else LATD = 0b0001;
}

void right_step_forward()
{
    if      (LATE == 0b0001) LATE = 0b0010;
    else if (LATE == 0b0010) LATE = 0b0100;
    else if (LATE == 0b0100) LATE = 0b1000;
    else if (LATE == 0b1000) LATE = 0b0001;
    else LATE = 0b0001;
}
void right_step_back()
{
    if      (LATE == 0b0001) LATE = 0b1000;
    else if (LATE == 0b0010) LATE = 0b0001;
    else if (LATE == 0b0100) LATE = 0b0010;
    else if (LATE == 0b1000) LATE = 0b0100;
    else LATE = 0b0001;
}
Posted in Uncategorized | Leave a comment

State Machine Challenge

20151103_173655

robot_track

Image | Posted on by | Leave a comment