Sunday, June 29, 2025

Affinity Photo Procedural Texture Filter

 Affinity Photo Procedural Texture Filter Examples

Affinity Help for PTF

List of PTF Functions

This is a list of all of the PTF functions I am aware of. Those used in linked videos are in bold.

Sign Related Functions

abs sign copysign

Rounding Related Functions

ceil floor fmod fraction fmod irem idiv round roundup rounddown trunc truncate whole

Trig Functions

sin cos tan acos asin atan atan2 pi

Power Related Functions

pow powr sq sqrt 

Statistical Functions

average max mid min

Specialized Math Functions

dim fma rgbtoi

Numeric Range Related Functions

tocui tohcui clamp clampmin clampmax saturate

Geometry and Vector Related Functions

cross dist dist_sq distance dot length length_squared norm normalise normalize

vec2 vec3 vec4 vec5 vec6 tovec3 tovec4 tovec5 tovec6

rev rotl rotr

swap 12 swap 13 swap23 swapxy swapxz swapyz swaprg swaprb swapgb

neg1 neg2 neg3 neg12 negx negy negz negxy negr negg negb negrg

debump

Interpolation Functions

lerp mix scurveinterp scerp sininterp serp cubicinterp cerp cubic scurveinterpolant

scint sininterpolant sint

Step Functions

mapcui step smoothstep smoothsteplin smoothstepsc smoothstepsin smoothstepcs smoothstepsq smoothstepsqi smoothstepcb smoothstepcbi smoothstepsin smoothstepsini smoothstepcr smoothstepcri smoothsteprt smoothsteprti 

stepn smoothstepn smoothstepnlin smoothstepnsc smoothstepncs smoothstepnsq smoothstepsqi smoothstepncb smoothstepncbi smoothstepnsini smoothstepncr smoothstepncri smoothstepncrt smoothstepnrti

Quantization

quantize quantizelin quantizesc quantizesin quantizecs

Oscillators

osc osci oscsc oscsin osccs osccubic oscsq oscsqi osccb osccbi oscpsin oscpsini osccr osccri oscrt oscrti

smoothosc smoothosclin smoothoscsin smoothosccs

osch oschi oschsc oschsin oschcs oschcubic oschsq oschsqi oschcb oschcbi oschpsin oschpsini oschcr oschcri oschrt oschrti

smoothosch smoothoschlin smoothoschsin smoothoschcs

Noise

noise noisei noisesc noisesin noisecs noisecubic noisesq noisesqi noisecb noisecbi noisepsin noisepsini noisecr noisecri noisert noiserti

noiseh noisehi noisehsc noisehsin noisehcs noisehcubic noisehsq noisehsqi noisehcb noisehcbi noisehpsin noisehpsini noisehcr noisehcri noisehrt noisehrti

perlin perlinsc perlinsin perlincubic perlincs

perlinh perlinhsc perlinhsin perlinhcubic perlinhcs

cellnoise cellnoise2 cellnoisedist cellnoiseedge

dir diri dirsc dirsin dircs 

udiri udir udirsc udirsin udircs

dir3 dir3i dir3sc dir3sin dir3cs

udir3 udir3i udirsc udir3sin udir3cs

Other functions

var

Reserved/Internal Variable Names

w h x y rx ry R G B pi

Operators

+ - * / . = ;

I am making a series of video tutorials for Affinity Photo's procedural texture filter. This page provides an index for the functions used in each video. 

var vec2 noisei cos sin smoothstep osc quantize perlinhcubic osc average


fraction oscsq

var vec2 pow noisei smoothstep osccr osci



var norm vec2 sqrt swapxy fraction  length step atan2 quantize 

rev rotl rotr swap12 swap13 swap23 swapxy swapxz swapyz swaprg swaprb swapgb neg1 neg2 neg3 neg12 negx negy negz negxy negr negg negb negrg

var vec2 cos sin vec3 oscsc osccri oschsc osci dirsc

var vec2 atan2 length cellnoise abs dirsc smoothstep

var vec2 atan length sin smoothstep


var vec2 fraction smoothstepcs length length max 

var vec2 step perlincubic cellnoisedist

var vec2 vec3 sqrt fraction step max min smoothstep

var vec2 noiseh perlincubic



var vec2 atan2 floor osc length cos

var fraction vec2 atan2 floor osc length pow cos

var fraction vec2 atan2 osci pow cos floor length

var vec2 floor diri step length fraction

var vec2 atan2 floor smoothstep length cos

var vec2 clampmin clampmax osc smoothstep





Friday, June 14, 2019

Race Lights

This is used for an RC racing light tree.  It stays red until you push the button, then stays yellow for 1-3 seconds (randomly), then flashes all colors twice, then stays green until you push the button.  Weak pull-ups are enabled on pin 5 for the button.

/* 
 * File:   RaceLightsMain.c
 * Author: hmikelson
 *
 * Created on June 14, 2019, 1:26 PM
 */

#if defined(__XC)
    #include <xc.h>         /* XC8 General Include File */
#elif defined(HI_TECH_C)
    #include <htc.h>        /* HiTech General Include File */
#endif

#include <stdint.h>        /* For uint8_t definition */
#include <stdbool.h>       /* For true/false definition */
#include <stdlib.h>     /*rand()*/

#pragma config MCLRE=OFF,CP=OFF,WDTE=OFF,FOSC=INTOSCIO
#define _XTAL_FREQ 4000000
uint8_t sGPIO;

void init()
{
    //Configure GPIO Port
    ANSEL =  0b00000000;  //Configure all GPIO pins as digital
    TRISIO = 0b11101000;  //Set GP3 & 5 as input and the rest as outputs
    OPTION_REGbits.nGPPU = 0;
    WPU = 0b00100000;     //Enable weak pullups on GP5
    //Configuer AD Convertor
    ADCON0 = 0x00;        //AD disabled
    ADRESH = 0x00;        //Init the AD Register
    //Configure Comparator
    CMCON0 = 0xFF;   // Comparator is turned off
    CMCON1 = 0x00;   // Comparator is turned off
    //Interrupt configuration
    INTCON = 0x00;   //Disable all interrupts
}

void vdelay(int n)
{
    int i;
    for (i=0;i<=n;i++)
    {
     __delay_ms(150);
    }
}

void main()
{
uint8_t r, db_cnt;

 init();
 GPIO = 0b00000001;
 __delay_ms(100);
 GPIO = 0b00000010;
 __delay_ms(100);
 GPIO = 0b00000100;
 __delay_ms(100);
 GPIO = 0b00000000;                                      
 while(1)
  {
   GPIO = 0b00000001;
   __delay_ms(200);
   for (db_cnt = 0; db_cnt <= 10; db_cnt++)
    {
     __delay_ms(10);
     if (GPIObits.GP5 == 1)
      db_cnt = 0;
    }
   GPIO = 0b00000010;
   r = rand()%15;
   __delay_ms(250);
   vdelay(r);
   __delay_ms(250);
   GPIO = 0b00000001;
   __delay_ms(50);
   GPIO = 0b00000010;
   __delay_ms(50);
   GPIO = 0b00000100;
   __delay_ms(50);
   GPIO = 0b00000001;
   __delay_ms(50);
   GPIO = 0b00000010;
   __delay_ms(50);
   GPIO = 0b00000100;
   __delay_ms(50);
   GPIO = 0b00000100;
   __delay_ms(200);
   for (db_cnt = 0; db_cnt <= 10; db_cnt++)
    {
     __delay_ms(10);
     if (GPIObits.GP5 == 1)
      db_cnt = 0;
    }   
  }
}

Sunday, March 3, 2019

Back Up Robot

Code for autonomous robot with PIR motion detection and ultrasound distance sensor.  Distance sensing decreases the chance of the robot getting stuck.  Robot also plays sounds while moving.

/* 
 * File:   BackupBotMain.c
 * Author: hmikelson
 *
 * Created on January 12, 2019, 11:32 AM
 * 
 * This program is used to control a robot with PIC16f1825 microcontroller
 * Uses a customized circuit board with a 1 watt amplified speaker
 * high intensity LED
 * Ultrasound sensor, and PIR sensor
 * Two motors: Forward, backward, right, left, stop
 * 6V battery power
 * Gear driven wheels
 */

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

#pragma config MCLRE=OFF,CP=OFF,WDTE=OFF,FOSC=INTOSC
#define _XTAL_FREQ 16000000
unsigned char sPORTA=0b00000000, sPORTC=0b00000000, pwmax=63;

void init()
{
 //Configure GPIO Port
 //RA0=BI2,RA1=BI1,RA2=Stby,RC0=AI1,RC1=AI2,RC2=PWMA&B
 //RC3=PIR,RC4=Trig,RC5=Echo,RA3=NA,RA4=Audio,RA5=LED
 //ANSELC= 0b00000000; //Must disable analog inputs to read digital in
 TRISA = 0b11000000;  //O=all
 TRISC = 0b11101000; //I=3,5
 OSCCONbits.IRCF = 0b1111;
 OSCCONbits.SCS = 0b00;
 //Enable analog input on C3
 ANSELCbits.ANSC3 = 1;
 ADCON0 = 0b00011101; //Channel (CHS4:0 bits 6-2),ADON bit 1 enable Analog
 ADCON1bits.ADCS = 0b111; // clock select dedicated osc 
 ADCON1bits.ADNREF = 0; //neg ref
 ADCON1bits.ADPREF = 0; //config + voltage with vdd
 ADCON1bits.ADFM = 1; //format left justified
 ADRESH = 0x00;        //Init the AD Register
}

void vdelay(int n)
 {
  int i;
  for (i=0;i<=n;i++)
   {
    __delay_us(5);
   }
 }

// Read voltage from input
int read_v()
 {
  int val,v1,v2;
  __delay_ms(1);
  ADCON0bits.GO_nDONE = 1;
  while(ADCON0bits.GO_nDONE == 1);
  return (ADRESH<<8) + ADRESL;
 }

/* 
 * Get distance from ultra sound sensor
 * Sensor on pins C4 Trig, C5 Echo
 * 
 */
int getdist()
 {
  int i=0;
  sPORTC = sPORTC & 0b11101111;
   PORTC = sPORTC;
   __delay_us(40);
  sPORTC = sPORTC | 0b00010000;
   PORTC = sPORTC;
   __delay_us(10);
  sPORTC = sPORTC & 0b11101111;
   PORTC = sPORTC;
  while((PORTCbits.RC5 == 0) && (i<5000)) //Wait but not forever
   {
    i++;
   }
  i=0;
  while ((PORTCbits.RC5 == 1) && (i<1000)) //Wait but not forever
   {
    i++;
   }
  return i;
 }

// Drive robot forward
void RobotFd(int time, unsigned char speed)
 {
  int i, j;
  for (i=0;i<time;i++)
   {
    for (j=0;j<pwmax;j++)
     {
      if (j<speed)
       {
         PORTA = 0b00111110;  // LED,Aud,MCLR,En,BI2,BI1
        sPORTC=0b00000110 | sPORTC;
        sPORTC=0b11111110 & sPORTC;
         PORTC = sPORTC;  // Eco,Trg,PIR,PWM,AI1,AI2
        vdelay(pwmax/speed);
       }
      else
       {
         PORTA = 0b00000110;
        sPORTC = 0b00000010 | sPORTC;
        sPORTC = 0b11111010 & sPORTC;
         PORTC = sPORTC;
        vdelay(pwmax/speed);
       }       
     }    
   }
 }

// Move Robot backward
void RobotBk(int time, unsigned char speed)
 {
  int i, j;
  for (i=0;i<time;i++)
   {
    for (j=0;j<pwmax;j++)
     {
      if (j<speed)
       {
         PORTA = 0b00111101;
        sPORTC = 0b00000101 | sPORTC;
        sPORTC = 0b11111101 & sPORTC;
         PORTC = sPORTC;
        vdelay(pwmax/speed);
       }
      else
       {
         PORTA  = 0b00000101;
        sPORTC = 0b00000001 | sPORTC;
        sPORTC = 0b11111001 & sPORTC;
         PORTC = sPORTC;
        vdelay(pwmax/speed);
       }       
     }      
   }
 }

// Move the robot right for time at speed.
void RobotRt(int time, unsigned char speed)
 {
  int i, j;
  for (i=0;i<time;i++)
   {
    for (j=0;j<pwmax;j++)
     {
      if (j<speed)
       {
         PORTA = 0b00111110;
        sPORTC = 0b00000101 | sPORTC;
        sPORTC = 0b11110101 & sPORTC;
         PORTC = sPORTC;
        vdelay(pwmax/speed);
       }
      else
       {
         PORTA = 0b00000110;
        sPORTC = 0b00000001 | sPORTC;
        sPORTC = 0b11111001 & sPORTC;
         PORTC = sPORTC;
        vdelay(pwmax/speed);
       }        
     }        
   }
 }

//Move the Robot Left for given time and speed.
void RobotLt(int time, unsigned char speed)
{
 int i, j;
 for (i=0;i<time;i++)
  {
   for (j=0;j<pwmax;j++)
    {
     if (j<speed)
      {
        PORTA = 0b00111101;
       sPORTC = 0b00000110 | sPORTC;
       sPORTC = 0b11111110 & sPORTC;
        PORTC = sPORTC;
       vdelay(pwmax/speed);
      }
     else
      {
        PORTA = 0b00000101;
       sPORTC = 0b00000010 | sPORTC;
       sPORTC = 0b11111010 & sPORTC;
        PORTC = sPORTC;        
       vdelay(pwmax/speed);
      }      
    }     
  }
}

// Robot stops for the given amount of time
void RobotSt(int time)
{
    int i;
    for (i=0;i<time;i++)
     {
      PORTA = 0b00000100;
      sPORTC = 0b00000100 | sPORTC;
      sPORTC = 0b11111100 & sPORTC;
      PORTC = sPORTC;
      __delay_ms(10);
     }

}

void main()
 {
  int mt=100,dist=1000,i;
  unsigned char rspeed, raction, rtime, nacts=30, pir;
  init();

  RobotFd(200,pwmax/1.5);
  RobotRt(200,pwmax/1.5);
  RobotBk(200,pwmax/1.5);
  RobotLt(200,pwmax/1.5);
  while(1)
   {
    while (nacts==0)
     {
      RobotSt(200);
      pir = read_v();
      if (pir>50)
       {
        nacts = 30;
       }           
     }
    dist = getdist();
    if (dist<300)
     {
      RobotBk(mt,pwmax/2);
      RobotRt(mt,pwmax/2);
     }
    else
    {
     RobotFd(mt,pwmax/2);
    }
    nacts = nacts - 1;
    raction=(rand() % 5);
    rtime=(rand() % mt)/2+mt/2;
    rspeed=pwmax/((rand() % 15)+1)+pwmax/5;
    switch (raction)
     {
      case 1:
       RobotFd(rtime,rspeed);
       break;
      case 2:
       RobotBk(rtime,rspeed);
       break;
      case 3:
       RobotLt(rtime,rspeed);
       break;
      case 4:
       RobotRt(rtime,rspeed);
       break;
      default:
       RobotSt(rtime);
       break;
      }
  }
 }

Sunday, November 4, 2018

This program creates a lighting effect that includes a very slow fade, strobe lights, and flashing lights.  It uses a 12f683 and pin 3 for input so you need to provide a pull up resistor (10k) and a pull down resistor (1k) when you push the button.  It  does not use an interrupt so you have to wait until the routine gets around to checking on the button, in other words you may have to hold the button down for a while especially during the slow cross fade.  Use a TIP31 for the LEDs (9V->LED->R->TIP31->Gnd) and a high current 7805 power regulator.  9V 2 A DC power supply.

/* 
 * File:   ls5main.c
 * Author: Hans Mikelson
 *
 * Created on December 17, 2014, 8:59 AM
 */

#if defined(__XC)
    #include <xc.h>         /* XC8 General Include File */
#elif defined(HI_TECH_C)
    #include <htc.h>        /* HiTech General Include File */
#endif

#include <stdint.h>        /* For uint8_t definition */
#include <stdbool.h>       /* For true/false definition */
#include <stdlib.h>        /* includes rand() */

#pragma config MCLRE=OFF,CP=OFF,WDTE=OFF,FOSC=INTOSCIO
#define _XTAL_FREQ 4000000
uint8_t sGPIO, gr1=0, gr2=0;  // Global shadow register and random variables

void init()
{
    //Configure GPIO Port
    ANSEL =  0b00000000;  //Configure all GPIO pins as digital
    TRISIO = 0b110001000;  //Set GP3 as input the rest as outputs
    OPTION_REGbits.nGPPU = 0;
    WPU = 0b00000000;     //Disable weak pullups
    //Configuer AD Convertor
    ADCON0 = 0x00;        //AD disabled
    ADRESH = 0x00;        //Init the AD Register
    //Configure Comparator
    CMCON0 = 0xFF;   // Comparator is turned off
    CMCON1 = 0x00;   // Comparator is turned off
    //Interrupt configuration
    INTCON = 0x00;   //Disable all interrupts
}

void vdelay(int n) //Variable time delay
{
    int i;
    for (i=0;i<=n;i++)
    {
     __delay_us(100);
    }
}

void xfade(int n)  //Cross fade between two global random #s
{                  //n controls the very slow fade time
    int j, k, i;
        for (j=0;j<255;j++)
         {
          for (i=0;i<n;i++)
           {
            for (k=0;k<255;k++)
             {
              if (j<k)
               {
                GPIO=gr2;
               }
              else
               {
                GPIO=gr1;
               }
             }
           }
         }
        gr2 = gr1;
        gr1 = rand() & rand();
}

void strobe(int n)  //Create a strobing cross fade
{
    int j, k, i;
        for (j=0;j<63;j++)
         {
          for (i=0;i<1;i++)
           {
            for (k=0;k<63;k++)
             {
              if (j<k)
               {
                GPIO=gr2;
                vdelay(n);
               }
              else
               {
                GPIO=gr1;
                vdelay(n);
               }
             }
           }
         }
        gr2 = gr1;
        gr1 = rand() & rand();
}

void main()
{
    int i=1;
    init();
    GPIO = 0b00000000;

    while(1)
    {
     if (GPIObits.GP3 == 0)
      {
       i=(i+1) % 9;
       GPIO = 0b00000000;
       vdelay(10000);
      }
     switch (i)
      {
       case 1:                  //Medium flash
        GPIO = rand() & rand(); 
        vdelay(4000);
        break;
       case 2:                  //Fast flash 
        GPIO = rand() & rand();
        vdelay(2000);
        break;
       case 3:
           xfade(1);
        break;
       case 4:
           xfade(8);
        break;
       case 5:
           xfade(32);
        break;
       case 6:
           strobe(4);
        break;
       case 7:
           strobe(8);
        break;
       case 8:
           strobe(32);
        break;
      default:                    // Slow flash
       GPIO = rand() & rand();
       vdelay(8000);
       break;
      }
    }
}

Thursday, November 1, 2018

LED Strobe Light

This code is for a 12f683 pic, connected to TIP31 transistors and white LEDs.  It generates a variety of strobe effects.  Randomly it will create either darkness (none), synchronized strobe on both channels, random strobe on both channels, the duration of the on pulse and off pulse also varies randomly.  This makes a great Halloween effect.

/*
 * File:   strobemain.c
 * Author: hmikelson
 *
 * Created October 2016
 */

#if defined(__XC)
    #include <xc.h>         /* XC8 General Include File */
#elif defined(HI_TECH_C)
    #include <htc.h>        /* HiTech General Include File */
#endif

#include <stdint.h>        /* For uint8_t definition */
#include <stdbool.h>       /* For true/false definition */
#include <stdlib.h>     /*rand()*/

#pragma config MCLRE=OFF,CP=OFF,WDTE=OFF,FOSC=INTOSCIO
#define _XTAL_FREQ 4000000
uint8_t sGPIO;

void init()
{
    //Configure GPIO Port
    ANSEL =  0b00000000;  //Configure all GPIO pins as digital
    TRISIO = 0b11001000;  //Set GP3 as input and the rest as outputs
                    // GP0 = eye 1, GP2 = eye 2, GP5 = speaker, GP4 = piezo
    OPTION_REGbits.nGPPU = 0;
    WPU = 0b00000100;     //Enable weak pullups on GP2
    //Configuer AD Convertor
    ADCON0 = 0x00;        //AD disabled
    ADRESH = 0x00;        //Init the AD Register
    //Configure Comparator
    CMCON0 = 0xFF;   // Comparator is turned off
    CMCON1 = 0x00;   // Comparator is turned off
    //Interrupt configuration
    INTCON = 0x00;   //Disable all interrupts
}

void vdelay(int n)
{
    int i;
    for (i=0;i<=n;i++)
    {
     __delay_us(1);
    }
}

void strobe1(int r)
{
 int i,n;
 n=200/r;
 for (i=0;i<n;i++)
  {
   GPIO = 0b11000011;
   vdelay(100);
   GPIO = 0b11000000;
   vdelay(r*1000);
  }
}

void strobe2(int r)
{
 int i,n;
 n=200/r;
 for (i=0;i<n;i++)
  {
   GPIO = 0b11000011;
   vdelay(200);
   GPIO = 0b11000000;
   vdelay(r*1000);
  }
}

void strobe3(int r)
{
 int i,n,r1;
 n=200/r;
 for (i=0;i<n;i++)
  {
   r1 = rand()%16;
   GPIO = 0b11000011;
   vdelay(100);
   GPIO = 0b11000000;
   vdelay(r1*1000);
  }
}

void strobe4(int r)
{
 int i,n,r1;
 n=200/r;
 for (i=0;i<n;i++)
  {
   r1 = rand()%16;
   GPIO = rand();
   vdelay(100);
   GPIO = 0b11000000;
   vdelay(r1*500);
  }
}

void darkness(void) // PWM sweep high f to low f
{
 GPIO = 0b11000000;
 __delay_ms(2000);
}

void main()
{
uint8_t r,r2;

 init();

 while(1)
  {
   r=rand()%8;
   //r=2;
   r2 = rand()%32+1;
   switch (r)
    {
     case 1:
     strobe1(r2);
     break;

     case 2:
     strobe2(r2);
     break;

     case 3:
     strobe3(r2);
     break;

     case 4:
     strobe4(r2);
     break;

     default:
     darkness();
    }
  }
}

 

Sunday, September 9, 2018

Robot Code

This is the operating code for a robot I built called Dumbot.  It only has a motion sensor and moves randomly.  The code generates three random numbers: speed, time, movement type.  There are five different movement types: Forward, backward, turn right, turn left, and stop.  There is a check routine at the  beginning: Forward, right, backward, left.  To check to make sure the motors are installed properly.  This code was tested on a PIC16F1825, using hobby motors from Sparkfun and the brushed motor controller breakout board from Sparkfun.  A switched battery holder with three double A batteries from Jameco was used.  The wheels and frame were 3D printed.  An LED output and an audio output were included.

/* 
 * File:   R06Main.c
 * Author: hmikelson
 *
 * Created on September 4, 2018, 6:11 PM
 */

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

#pragma config MCLRE=OFF,CP=OFF,WDTE=OFF,FOSC=INTOSC
#define _XTAL_FREQ 16000000
unsigned char sPORTA, sPORTC, pwmax=31;

void init()
{
    //Configure GPIO Port
    TRISA = 0b110000000;  //Set all Output
    TRISC = 0b110001000; //Set up pin 3 for input
    OSCCONbits.IRCF = 0b1111;
    OSCCONbits.SCS = 0b00;
    //OPTION_REG = 0b01111111; //Global enable weak pullups
    //WPUC = 0b00001000;     //Enable weak pullups with a 1
    // Set up analog input
    ANSELCbits.ANSC3 = 1;
    ADCON0 = 0b00011101; //Channel (CHS4:0 bits 6-2),ADON bit 1 enable Analog
    ADCON1bits.ADCS = 0b111; // clock select dedicated osc 
    ADCON1bits.ADNREF = 0; //neg ref
    ADCON1bits.ADPREF = 0; //config + voltage with vdd
    ADCON1bits.ADFM = 1; //format left justified
    ADRESH = 0x00;        //Init the AD Register
    ADRESL = 0x00;       // I don't think this is needed

    //OSCCONbits.SPLLEN = 0b1;
}

void vdelay(int n)
{
    int i;
    for (i=0;i<=n;i++)
    {
     __delay_us(100);
    }
}

int read_v()
// Read voltage from input
 {
    int val,v1,v2;
    __delay_ms(1);
    ADCON0bits.GO_nDONE = 1;
    while(ADCON0bits.GO_nDONE == 1);
    v1 = ADRESH;
    v2 = ADRESL;
    val = (v1<<8) + v2;
    return val;
 }

// Drive robot forward
void RobotFd(int time, unsigned char speed)
{
    int i, j;
    for (i=0;i<time;i++)
    {
        for (j=0;j<pwmax;j++)
        {
            if (j<speed)
            {
                PORTA = 0b00111110;  // 
                PORTC = 0b00010110;  // Enable on pin 4
                vdelay(pwmax/speed);
            }
            else
            {
                PORTA = 0b00000110; // I think there is a  clock output on pin 4 which I don't know how to disable
                PORTC = 0b00010010; // Enable on pin 4
                vdelay(pwmax/speed);
            }
            
        }
        
    }
}

// Drive Robot backward
void RobotBk(int time, unsigned char speed)
{
    int i, j;
    for (i=0;i<time;i++)
    {
        for (j=0;j<pwmax;j++)
        {
            if (j<speed)
            {
                PORTA = 0b00111101;
                PORTC = 0b00010101;
                vdelay(pwmax/speed);
            }
            else
            {
                PORTA = 0b00000101;
                PORTC = 0b00010001;
                vdelay(pwmax/speed);
            }
            
        }
        
    }
}
void RobotRt(int time, unsigned char speed)
{
    int i, j;
    for (i=0;i<time;i++)
    {
        for (j=0;j<pwmax;j++)
        {
            if (j<speed)
            {
                PORTA = 0b00111110;
                PORTC = 0b00010101;
                vdelay(pwmax/speed);
            }
            else
            {
                PORTA = 0b00000110;
                PORTC = 0b00001001;
                vdelay(pwmax/speed);
            }
            
        }
        
    }
}
void RobotLt(int time, unsigned char speed)
{
    int i, j;
    for (i=0;i<time;i++)
    {
        for (j=0;j<pwmax;j++)
        {
            if (j<speed)
            {
                PORTA = 0b00111101;
                PORTC = 0b00110110;
                vdelay(pwmax/speed);
            }
            else
            {
                PORTA = 0b00000101;
                PORTC = 0b00001010;
                vdelay(pwmax/speed);
            }
            
        }
        
    }
}

void RobotSt(int time)
{
    int i;
    for (i=0;i<time;i++)
    {
    PORTA = 0b00000100;
    PORTC = 0b00001100;
    __delay_ms(10);
    }

}

void main()
 {
  int rmode, rtime, volts,mt=31;
  unsigned char rspeed, nactions=0;
  init();
  RobotFd(100,pwmax/2);
  RobotSt(1);
  RobotRt(100,pwmax/2);
  RobotSt(1);
  RobotBk(100,pwmax/2);
  RobotSt(1);
  RobotLt(100,pwmax/2);
  RobotSt(1);
  while(1)
   {
     if (nactions > 0)
     {
         rmode=(rand() & 7) + 1;
         nactions=nactions-1;
     }
     else
     {
         rmode = 0;
     }
     rtime = (rand() & 7)+1;
     rspeed = rand() & pwmax;
     switch (rmode)
      {
       case 1:
        RobotFd(rtime*mt,rspeed);
        RobotSt(1);
        break;
       case 2:
        RobotBk(rtime*mt,rspeed);
        RobotSt(1);
        break;
       case 3:
        RobotRt(rtime*mt,rspeed);
        RobotSt(1);
        break;
       case 4:
        RobotLt(rtime*mt,rspeed);
        RobotSt(1);
       break;
       case 0:
        RobotSt(1);
        volts = read_v();
        if (volts>50)
         {
            nactions = 10;
            //blink(volts);
         }           
       break;
       default:
           RobotSt(10);
        break;
      }
   }
 }