vrijdag 26 juni 2015

Software Setup

In the previous post we prepared a radio controlled boat to operate on an Arduino Uno board. Now we can start to program it. Usually the recipes for Arduino will include a lot of delay functions, which basically stops the programme for a certain amount of time, and thus leaves the boat uncontrollable. The solution presented here will use a simple form of multi-tasking, by means of the Timer) function.It also uses the 'Tabs' option of the Arduino IDE to enhance a modular approach, even though the code is predominantly written in ANSI-C.

Note: the full software is available on GitHub.

Software Setup

First we create a new Arduino project called rc_boat.  We open the Arduino IDE and select

File ?New, and call the file rc_boat (or something else if you prefer).

 The main function always contains a setup() function for initialisation, and a loop() for the actual control. We now replace the default (barebones) code with the following:

//Global variabeles
unsigned int centis = 0; //centi- seconds
byte seconden = 0; //seconds
byte minuten = 0; //minutes
int alarm = 0;

void setup() {

   //Set up Radio Control
   RCP_Init();
   RCD_Init();
   State_Init();
   Autonomous_Init();
  
  //Initialise LEDS
  TopLed_Init();
  LedControl_Init();
  LedControl_Disco( HIGH );
  TopLed_Out( HIGH ); 
  LedControl_OnBoard( HIGH ); 

  //Let the LEDs blink for a second
  delay(1000);
 
  TopLed_Out( LOW  );
  LedControl_Disco( LOW ); 
  LedControl_OnBoard( LOW ); 

  cli();//deactivate interrupts
  tmr0_init();
  sei();//Activate interrupts

//Initialise the motor and rudder control
  Motor_Init();
  Rudder_Init();
}

void loop() {
  State_Control();
  //LedControl_Disco( HIGH );
  delay(100);
}


The code is currently still quite abstract, but the general idea is to:
  • Initialise the Radio controller and other stuff
  • Initialise the LEDs and let them burn for a second
  • Set up the Timer for multi-tasking
  • Initialise the motor and rudder controllers
  • Run the programme (loop).
We can now begin to fill in the details. First add a Timer function. In order to do so, we add a 'new tab' to the programme, with the ?button on the right hand side of the IDE, and call it Timer0. The code is as follows

 //Constants
#define CMR_SECONDE 100 //Count to 10 to time every second
#define CMR_MINUUT 5901 //Count to 609 om time every minute

static byte secondCounter = 0;        //Seconds counter
static unsigned int minuteCounter = 0; //16-bits minute counter

//Initialise timer 0;
void tmr0_init(){
  TCCR0A = 0;   // TCCR0A register = 0
  TCCR0B = 0;   // TCCR0B as well
  TCNT0  = 0;   // Reset the counter
  OCR0A = 156;  // CMR = 156
  TCCR0A |= (1 << WGM01); //CTC mode
  TCCR0B |= (1 << CS02) | (1 << CS00);//Prescaler = 1024  
  TIMSK0 |= (1 << OCIE0A); // Activate interrupt Timer 0
}

/**
 * Respond to an interrupt of timer 0
 */
ISR(TIMER0_COMPA_vect){//timer0 interrupt
  RCP_Update();
  RCD_Update();
  State_Update();
  TopLed_Update();

  centis++;
  secondCounter++; //count up every interrupt
  minuteCounter++; // count up every interrupt
 
  //Monitor_Puls();
  if( secondCounter == CMR_SECONDE ){
    Autonomous_Update();
    secondCounter = 0;
    seconden = ( ++seconden ) % 60;
  }
  if( minuteCounter == CMR_MINUUT ){
    minuteCounter = 0;
    minuten = ( ++minuten ) % 60;
  }
}


The timer is programmed to fire every 10 msec, after which two counters -for seconds and minutes-  count up. Some of the control software is updated every 10 milliseconds, like RC, State or  TopLed.  But the code that controls the Autonomy is updated every second. The tmr_init code is called in the setup of the main programme. This should be enough to activate the timer.

From this point on, all we need to do is to activate the various controllers. For instance, the boat has two LEDs, one of which is mounted under the deck. This LED, called TopLED is activated on pin 5 of Arduino's port D:

#define LED_TOP 5 //Output PortD pin 5

/**
 * Initialise the Top LED
 */
void TopLed_Init(){
  pinMode( LED_TOP, OUTPUT);//Set the pin for output
}

/**
 * Update the top led through the timer interrupt
 */
static boolean led_on = false;
void TopLed_Update(){
  byte status = State_GetState();
  switch( status ){
    case AUTONOMOUS:
      if(( counter % AUTO_BLINK ) == 0 )
        led_on = !led_on;
     break;
    case BLOCKED:
      if(( counter % BLOCK_BLINK ) == 0)
        led_on = !led_on;
      break;
    default:
      led_on = true;
  }
  TopLed_Out( led_on );
}

byte TopLed_TOP(){
  return LED_TOP;
}

void TopLed_Out( boolean signal ){
   digitalWrite( LED_TOP, signal );
}


This code has three things that make a recurring pattern for all the controllers:
  • The functions all start with the name of the tab (TopLed_xxx)
  • The code contains an Init function that is called by the setup() of the main function
  • The code contains an Update function that is called by the timer. In this particular case, the timer is able to blink fast or slow, depending on the state of the boat.
Don't delve into the Update function too deeply, we will return to this in the next post. Likewise, the other LED, and the LED that is mounted on the Arduino UNO board (pin 13) is controlled by the following tab:
define LED_DISCO 6 //set up disco LED on pint 6
#define LED_ONBOARD 13 //On board LEd is pin 13

void LedControl_Init(){
  pinMode( LED_DISCO, OUTPUT );
  pinMode( LED_ONBOARD, OUTPUT);
}

byte LedControl_Disco(){
  return LED_DISCO;
}

byte LedControl_OnBoard(){
  return LED_ONBOARD;
}

void LedControl_Disco( boolean signaal ){
  digitalWrite( LED_DISCO, signaal );
}

void LedControl_OnBoard( boolean signaal ){
   digitalWrite( LED_ONBOARD, signaal );


In this particular case, the LED's do not use the timer, so a LedControl_Update() is not necessary.

In the next post, we will make the software a bit more complex, by allowing the boat to switch beteen manual and autonomous control.

Geen opmerkingen:

Een reactie posten