Free Trial

Safari Books Online is a digital library providing on-demand subscription access to thousands of learning resources.

  • Create BookmarkCreate Bookmark
  • Create Note or TagCreate Note or Tag
  • PrintPrint
Share this Page URL
Help

4. Project: Clock > Program the Robot

Program the Robot

Once you’ve built the clock, it’s time to program it! Plug in your Arduino and upload the program code found in the Bricktronics library (found on http://wayneandlayne.com/bricktronics if you haven’t snagged it already!)

The clock code follows a general form which is seen throughout this book. First, information about the environment is gathered. Second, we determine a reaction. Third, we react until we gather more information about the environment.

We do this in the clock with a main loop that only iterates every hundred milliseconds or so, and if the code in the loop executes faster than that, it idles until the next iteration. We’ve found this to be a useful code framework for mechatronics.

The libraries used are the Time library, which brings POSIX-style time structs to Arduino, and the Bricktronics libraries.

The main loop checks to see if the time-setting buttons have been pushed, and then it calculates where the minute and hour hands should be. It sets those positions using the PID calls, and waits for the next main loop.

#include <Wire.h>
#include <Adafruit_MCP23017.h>
#include <Bricktronics.h>
#include <Time.h>

#define TIME_STEP 100
time_t t;

Bricktronics brick = Bricktronics();
PIDMotor h = PIDMotor(&brick, 1);
PIDMotor m = PIDMotor(&brick, 2);
Button hour_button = Button(&brick, 1);
Button minute_button = Button(&brick, 2);

void setup()
{
  Serial.begin(115200); 
  Serial.println("starting!");

  brick.begin();
  m.begin();
  h.begin();
  hour_button.begin();
  minute_button.begin();
}

void digitalClockDisplay() 
{
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
}
void printDigits(int digits) 
{
  Serial.print(":");
  if (digits < 10)
  {
    Serial.print('0');
  }
  Serial.print(digits);
}

void increment_minute()
{
  adjustTime(60);
  Serial.println("Advance minute pressed");
}

void increment_hour()
{
  adjustTime(3600);
  Serial.println("Advance hour pressed");
}

void check_buttons() 
{
  static char last_minute_status = HIGH;
  static char last_hour_status = HIGH;

  char minute_status = minute_button.is_pressed();
  char hour_status = hour_button.is_pressed();

  if (minute_status == HIGH && last_minute_status == LOW)
  {
   increment_minute();
  }

  if (hour_status == HIGH && last_hour_status == LOW)
  {
   increment_hour();
  }

  last_minute_status = minute_status;
  last_hour_status = hour_status;
}


void loop() 
{
  long next_loop = millis() + TIME_STEP; 
  check_buttons(); 
  t = now(); 
  int full_hours = hour(t) % 12;
  int minute_position; 
  minute_position = minute(t)*6 + 360*full_hours; _
  int m_pos;
  m_pos = -3 * 2 * minute_position; 

  int hour_position; 
  hour_position = (hour(t) % 12) * 30 + minute(t)/2; 
  int h_pos = 2 * 5 * hour_position; 
  digitalClockDisplay();
  Serial.println();

  m.go_to_pos(m_pos);
  h.go_to_pos(h_pos); 

  while (millis() < next_loop)
  {
    h.update();
    m.update();
    delay(50);
  }
}
  1. We use the USB serial port for debugging our Arduino code. It allows us to send information from the Arduino to the computer.

  2. digitalClockDisplay() prints out the time to the serial port.

  3. printDigits() is a helper function for digitalClockDisplay().

  4. check_buttons() handles most of the logic of the clock, outside of moving the hands. It is only called once each time loop() runs, which is every 100 ms, so debouncing (adding additional program logic to handle electrical noise in button presses) the buttons isn’t really necessary in this application.

  5. loop() runs over and over again. It handles moving the hands, as well as reading the buttons.

  6. next_loop is used for the inner PID loop, which runs for TIME_STEP.

  7. check_buttons() checks the minute and hour buttons for presses.

  8. t holds the current time in a time_t struct.

  9. minute_position is the desired position of the minute hand (in degrees) for the current time, where 0 degrees is at the 12:00 position and increases in a clockwise manner.

  10. To convert from minutes to degrees on a clock, you multiply by 6. For example, 15 minutes*6 = 90 degrees.

  11. m_pos is the position we want the minute hand motor to go to. Because of gearing, this is not just minute_position!

  12. The negative sign is here because of the direction the motor is mounted in. The 3 is based on the gear ratio: there is an 8-tooth gear on the motor, geared to a 24-tooth gear which is connected to the hand. This is a 3:1 ratio, so we need to move our motor three degrees for every one degree we want the minute hand to go. The 2 is because we read two steps per degree.

  13. hour_position is the desired position of the hour hand (in degrees) for the current time, where 0 degrees is at the 12:00 position and increases in a clockwise manner.

  14. To get the position of the hour hand, we have to move the hand 30 degrees for every full hour, and then move the hour hand proportionally for how far the minute hand has gone. So, for example, 6:00 would work out to be exactly 180 degrees (hour hand pointing at the 6). And at 1:30, the hour hand will be at exactly 45 degrees.

  15. There is an 8-tooth gear driving a 24-tooth gear, for a 3:1 ratio and then that 24-tooth gear is driving a 40-tooth gear, for a 1.667:1 ratio. This works out to a 5:1 ratio overall. The reason for the 2 in the equation is that we read two steps per degree.

  16. The program will continue to try to get the hands to the right positions for about 100 ms.

  • Safari Books Online
  • Create BookmarkCreate Bookmark
  • Create Note or TagCreate Note or Tag
  • PrintPrint