Lecture Sample Code

This collection of short Arduino sketches introduces a variety of programming concepts. The comments are minimal as these are intended to be starting points for explanation.

getting started

plots

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#include <Servo.h>

// 1. demonstrate use of Serial port for debugging output
// 2. demonstrate IDE graphing: see Tools/Serial Plotter
void setup()
{
  Serial.begin(115200);
}
void loop()
{
  Serial.println(sin(4 * 6.28 * 0.001 * millis()));
}

plotting

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// 1. use the Arduino IDE plotting utility to visualize an analog signal
// 2. demonstrate analogRead()

void setup()
{
   Serial.begin(115200);
}

void loop()
{
  int input = analogRead(A0);
  Serial.println(input);
  delay(20);
}

clocks

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 1. measure execution time
// 2. demonstrate the firmware clock
// 3. demonstrate debugging on the serial port

void setup()
{
  Serial.begin(115200);
}

long last_time = 0;

void loop()
{
  long now = micros();

  Serial.print(millis());
  Serial.print(" ");  

  Serial.print(micros());
  Serial.print(" ");

  Serial.println(now - last_time);

  last_time = now;
}

sos

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// Demonstration of the following:
// 1. digitalWrite() to the onboard LED
// 2. delay()
// 3. Morse code signaling
void setup()
{
  pinMode(13, OUTPUT);
}

void dot()
{
  digitalWrite(13, HIGH);
  delay(200);
  digitalWrite(13, LOW);
  delay(200);
}

void dash()
{
  digitalWrite(13, HIGH);
  delay(600);
  digitalWrite(13, LOW);
  delay(200);
}

void endchar()
{
  delay(400);
}

void loop()
{
  dot();   dot();  dot(); endchar();   // S
  dash(); dash(); dash(); endchar();   // O
  dot();   dot();  dot(); endchar();   // S
 
  delay(1000);
}

digitalio

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Demonstration of the following:
// 1. digitalRead() from external switch
// 2. digitalWrite() to external LED

const int SWITCH_PIN = 8;
const int LED_PIN = 4;

void setup()
{
  Serial.begin(115200);
  pinMode(LED_PIN, OUTPUT);
  pinMode(SWITCH_PIN, INPUT);
}

void loop()
{
  int value = digitalRead(SWITCH_PIN);

  Serial.println(value);
  digitalWrite(LED_PIN, value);

  delay(50);
}

sounds

tones

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 1. generate tones on a speaker on pin 5
// 2. demonstrate tone(), noTone(), delay()

const int SPEAKER_PIN = 5;

void setup()
{
  // empty body, tone() configures a pin for output
}
void loop()
{
  // play A4 "concert A"
  tone(SPEAKER_PIN, 440);  
  delay(1000);

  // silence
  noTone(SPEAKER_PIN);
  delay(1000);

  // play E5 perfect fifth using 3/2 "just intonation" ratio  
  tone(SPEAKER_PIN, 660);  
  delay(1000);
}

bit-bang-two-tone

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// 1. generate complex waveform on a speaker on pin 5
// 2. demonstrate execution speed, firmware clocks, bit-banging logic

const int SPEAKER_PIN = 5;

void setup()
{ 
  pinMode(SPEAKER_PIN, OUTPUT);
}
void loop()
{
  long now = micros();

  // 2274 usec period ~= 439.75 Hz ~= A4
  bool square1 = (now % 2274) < 1136;

  // 1516 usec period ~= 659.63 HZ ~= E5
  bool square2 = (now % 1516) < 758;
  
  digitalWrite(SPEAKER_PIN, square1 ^ square2);
}

scale

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// 1. generate chromatic tones on a speaker on pin 5
// 2. demonstrate for loops, int and float variables

const int SPEAKER_PIN = 5;

void setup()
{
}

void loop()
{
  float freq = 440.0;
  for (int i = 0; i < 24; i = i + 1) {
    tone(SPEAKER_PIN, freq);
    delay(200);
    freq = freq * 1.0595;
  }
  noTone(SPEAKER_PIN);
  delay(1000);
}

melody

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 1. generate tones on a speaker on pin 5
// 2. demonstrate table lookup
// 3. demonstrate Serial debugging

const int SPEAKER_PIN = 5;

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

const float note_table[] = {
  440.0, 523.25, 659.26, 523.25, 659.26, 523.25/2, 440.0,
  659.26, 659.26*2, 523.25, -1.0 };

void loop()
{
  for (int i = 0; note_table[i] > 0.0 ; i = i + 1) {
    Serial.print("Note: ");
    Serial.println(note_table[i]);
    
    tone(SPEAKER_PIN, note_table[i]);
    delay(200);
  }
  noTone(SPEAKER_PIN);
  delay(500);
}

note-table

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 1. generate tones on a speaker on pin 5
// 2. demonstrate MIDI notes and equal temperament scales
// 3. use of a const byte table (unsigned 8 bit integers)

const int SPEAKER_PIN = 5;

const byte notes[] = {60, 62, 64, 65, 67, 69, 71, 72};
const int notes_len = sizeof(notes) / sizeof(byte);

const int   MIDI_A0 = 21;
const float freq_A0 = 27.5;

void setup()
{
  Serial.begin(115200);
}

void loop()
{
  for (int i = 0; i < notes_len; i = i + 1) {
    int note = notes[i];
    float freq = freq_A0 * pow(2.0, ((float)(note - MIDI_A0)) / 12.0);
    Serial.println(freq);
    tone(SPEAKER_PIN, freq);
    delay(500);
  }
  noTone(SPEAKER_PIN);
  delay(1000);
}

arpeggio

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// 1. generate tones on a speaker on pin 5
// 2. demonstrate functional abstraction
// 3. demonstrate MIDI notes and equal temperament scales
// 4. demonstrate for loop with multiple expressions
// 5. demonstate global constants with 'const float' and 'const int'

const int SPEAKER_PIN = 5;

void setup()
{
  Serial.begin(115200);
}

void loop()
{
  arpeggio(60, 3, 4);  // 60 is the MIDI number for note C4
  silence();
  arpeggio(60, 3, 8);
  arpeggio(85, -6, 8);
  silence();
  silence();
}

void arpeggio(int start, int interval, int length)
{

  for (int note = start, count = 0; count < length; note = note + interval, count = count + 1) {
    float freq = midi_to_freq(note);
    Serial.println(freq);
    tone(SPEAKER_PIN, freq);
    delay(200);
  }
}

const int   MIDI_A0 = 21;
const float freq_A0 = 27.5;
  
float midi_to_freq(int midi_note)
{
  return freq_A0 * pow(2.0, ((float)(midi_note - MIDI_A0)) / 12.0);
}

void silence(void)
{
  noTone(SPEAKER_PIN);
  delay(500);
}

tonestep

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 1. read a switch input on pin 9
// 2. generate tones on a speaker on pin 5
// 3. demonstrate a simple state machine
// 4. demonstrate Serial debugging

const int SWITCH_PIN  = 9;
const int SPEAKER_PIN = 5;

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

const float note_table[] = { 440.0, 523.25, 659.26, 523.25, 659.26, 523.25/2, 440.0,
			     659.26, 659.26*2, 523.25, -1 };

int nextnote = 0;

/// The loop function is called repeatedly by the Arduino system.  In this
/// example, it executes once per cycle of the switch input.
void loop()
{
  while(digitalRead(SWITCH_PIN) != 0) {
    // Busywait for the switch to be pressed.  Note that the body of the while
    // is empty, this just loops reading the switch input until it goes low.
  }

  // The following is executed once per switch cycle, right after the switch is pressed.
  float freq = note_table[nextnote];
  Serial.print("Note: ");
  Serial.println(freq);
  tone(SPEAKER_PIN, freq);

  // advance to the next note, looping at the end
  nextnote = nextnote + 1;
  if (note_table[nextnote] < 0) nextnote = 0;

  // Busywait for the switch to be released: loop until the switch input goes high.  
  while(digitalRead(SWITCH_PIN) == 0) {  }

  // The following is executed once, right after the switch is released.
  noTone(SPEAKER_PIN);
}

servos

metronome

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// demo use of a library, hobby servo output
#include <Servo.h> 

Servo your_chosen_servo_name;

void setup()
{
  your_chosen_servo_name.attach(9);
}

void loop()
{
  your_chosen_servo_name.write(45);
  delay(500);

  your_chosen_servo_name.write(135);
  delay(500);
}

sine-servo

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <Servo.h>

Servo indicator;
const int SERVO_PIN = 6;

void setup()
{
  Serial.begin(115200);
  indicator.attach(SERVO_PIN);
}

// global step counter
int step = 0;

void loop()
{
  // Perform a smooth sinusoidal movement around the center.
  float phase = step * (2*M_PI/60);
  float angle = 90 + 90*sin(phase);
  step = step + 1;
  
  indicator.write(angle);   // degrees
  Serial.println(angle);    
  delay(50);                // milliseconds
}

sine-metronome

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// demo use of a trajectory generator function
#include <Servo.h> 

const int SERVO_PIN = 9;
Servo wiggling_servo;

void setup(void)
{
  Serial.begin(115200);
  wiggling_servo.attach(SERVO_PIN);
}


void loop(void)
{
  // Perform a smooth movement around the center several times.
  for (int i = 0; i < 4; i = i+1) {

    // Define a few constants governing the motion.  Note that this example
    // uses a C++ style of declaration which looks more like a normal variable
    // declaration, but whose value cannot be changed.
    const float center    = 90.0;     // in degrees
    const float magnitude = 30.0;     // in degrees
    const float period    =  4.0;     // in seconds, duration of cycle
    const float interval  =  0.020;   // in seconds, duration of each step

    int cycle_steps = period / interval;
    
    for (int step = 0; step < cycle_steps; step++) {
      // Compute the 'phase angle' for the sine function.  Note that the sin()
      // function requires an angle in radians.
      float phase = step * (2*M_PI/cycle_steps);
      
      // Compute the angle to send to the servo.
      float angle = center + magnitude * sin(phase);
      wiggling_servo.write(angle);

      // Wait for one sampling period.
      delay(1000*interval);
    }
  }
  Serial.println("cycle done.");
}

table-metronome

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// demo use of a lookup table
#include <Servo.h> 

const int SERVO_PIN = 9;
Servo svo;

void setup(void)
{
  svo.attach(SERVO_PIN);
}

const int angles[12] = { 45, 0, 135, 0, 90, 0, 90, 45, 135, 90, 180, 0 };

void loop(void)
{
  for (int idx = 0; idx < 12; idx = idx + 1) {
    svo.write(angles[idx]);
    delay(500);
  }
}

shm-servo

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// 1. demonstrate use of a differential equation generator function
// 2. demonstrate use of a function as motion primitive

#include <Servo.h> 

const int SERVO_PIN = 9;
Servo svo;

// ================================================================
// Simple Harmonic Motion oscillator, e.g. unit-mass on spring with damping.

const float k1 = 4*M_PI*M_PI;   // 1 Hz; freq = (1/2*pi) * sqrt(k/m); k = (freq*2*pi)^2
const float b1 = 2.0;           // default damping
const float dt = 0.02;          // integration time step (same as command rate)

float q    = 0.0;         // initial position
float qd   = 0.0;         // initial velocity

// ================================================================

void setup(void)
{
  Serial.begin(115200);
  svo.attach(SERVO_PIN);
}

// ================================================================
void loop()
{
  ringing_servo(90.0, k1, b1, 1.5);
  ringing_servo(45.0, k1, b1, 1.5);
  ringing_servo(90.0, k1, b1, 2.5);
}
// ================================================================
// Create a simple harmonic motion around position 'q_d' using spring constant 'k' and
// damping 'b' for 'duration' seconds.
void ringing_servo(float q_d, float k, float b, float duration)
{
  while (duration > 0.0) {
    // calculate the derivatives
    float qdd = k * (q_d - q) - b * qd;

    // integrate one time step
    q  += qd  * dt;
    qd += qdd * dt;

    // update the servo
    svo.write(q);
      
    // print the output for plotting
    Serial.println(q);

    // delay to control timing
    delay((int)(1000*dt));
    duration -= dt;
  }
}

event loops

non-blocking

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 1. Blink the onboard Arduino LED on pin 13.
// 2. Demonstrate a non-blocking event loop.
// 3. Demonstrate micros() and timing calculations.
// 4. Note the absence of delay().  For comparison, see blink.ino.

void setup(void)
{
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop(void)
{
  static unsigned long last_update_clock = 0;

  unsigned long now = micros();
  unsigned long interval = now - last_update_clock;
  last_update_clock = now;

  static long led_blink_timer = 0;
  static bool led_blink_state = false;
  const long led_blink_interval = 500000;
 
  led_blink_timer -= interval;
  if (led_blink_timer <= 0) {
    led_blink_timer += led_blink_interval;

    led_blink_state = !led_blink_state;
    digitalWrite(LED_BUILTIN, led_blink_state);
  }
}
  

delay-with-poll

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
void setup(void)
{
  pinMode(LED_BUILTIN, OUTPUT);
}

/****************************************************************/
void delay_and_poll(long microseconds)
{
  unsigned long last_update_clock = micros();
  
  while (microseconds > 0) {
    unsigned long now = micros();
    unsigned long interval = now - last_update_clock;
    last_update_clock = now;
    microseconds -= interval;

    static long led_blink_timer = 0;
    static bool led_blink_state = false;
    const long led_blink_interval = 500000;

    led_blink_timer -= interval;
    if (led_blink_timer <= 0) {
      led_blink_timer += led_blink_interval;
      led_blink_state = !led_blink_state;
      digitalWrite(LED_BUILTIN, led_blink_state);
    }
  }
}

/****************************************************************/
void loop(void)
{
  // entering state 0
  delay_and_poll(1000000);

  // entering state 1
  delay_and_poll(1000000);

  // entering state 2
  delay_and_poll(1000000);

  // entering state 3
  while (true) delay_and_poll(1000000);
}

responsive-delay

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// 1. Demonstrate polling hardware inputs while waiting.

const int SPEAKER_PIN = 5;
const int SWITCH_PIN  = 3;

void setup(void)
{
  Serial.begin(115200);
  pinMode(SWITCH_PIN, INPUT);
}

void loop(void)
{
  // start the main script
  Serial.println("siren...");
  play_siren();

  // always wait for a brief silence before repeating
  Serial.println("silence.");
  noTone(SPEAKER_PIN);
  delay(1000);
}


void play_siren(void)
{
  // begin an interruptible sequence
  for (int i = 0; i < 3; i++) {
    tone(SPEAKER_PIN, 622);
    if (cond_delay(300)) return;
  
    tone(SPEAKER_PIN, 440);
    if (cond_delay(300)) return;
  }
}

// A conditional delay. This will wait for the given number of milliseconds
// unless the switch is pressed.  Returns false if time is reached or true if
// interrupted.

bool cond_delay(int milliseconds)
{
  unsigned long last_update_clock = millis();
  
  while (milliseconds > 0) {
    unsigned long now = millis();
    unsigned long interval = now - last_update_clock;
    last_update_clock = now;
    milliseconds -= interval;

    // check if the switch input has gone low (active-low switch circuit)
    if (digitalRead(SWITCH_PIN) == 0) return true;
  }
  return false;
}

state machines

state-machine

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
// 1. Simultaneous blink the onboard Arduino LED on pin 13 and play a melody in pin 5.
// 2. Demonstrate a non-blocking event loop with multiple tasks.
// 3. Demonstrate micros() and timing calculations.
// 4. Demonstrate switch-case state machine structure.

void setup(void)
{
  pinMode(LED_BUILTIN, OUTPUT);
}

/****************************************************************/
void loop(void)
{
  static unsigned long last_update_clock = 0;

  unsigned long now = micros();
  unsigned long interval = now - last_update_clock;
  last_update_clock = now;

  // simultaneously run several independent tasks
  poll_led(interval);
  poll_melody(interval);
}

/****************************************************************/
// State variables for the LED blinker.
long led_blink_timer = 0;
bool led_blink_state = false;
const long led_blink_interval = 500000;

void poll_led(unsigned long interval)
{
  // This task uses the decrementing timer idiom (led_blink_timer).
  
  led_blink_timer -= interval;
  if (led_blink_timer <= 0) {
    // Reset the LED timer.
    led_blink_timer += led_blink_interval;

    // Toggle the LED to blink it.
    led_blink_state = !led_blink_state;
    digitalWrite(LED_BUILTIN, led_blink_state);
  }
}

/****************************************************************/
// State variables for the melody player.
int  melody_index = 0;
long melody_elapsed = 0;

const int SPEAKER_PIN = 5;
const int NOTE_FS4 = 370;
const int NOTE_C4 = 262;

void poll_melody(unsigned long interval)
{
  // This task uses the incrementing timer idiom (melody_elapsed).  The elapsed
  // time value is increased on each cycle, then reset at state transitions.
  melody_elapsed += interval;

  // Following is a state machine implemented using switch-case.  This example
  // executes state 0-5 in sequence then remains in state 5.  Each state
  // transition is conditioned purely on elapsed time; transitions have the side
  // effect of changing the speaker pitch.  Note that in a more general case
  // each state could transition to any other state or be conditioned on sensor
  // values.
  
  switch(melody_index) {
  case 0:
    // Initialization state: start the speaker tone and immediately transition to state 1.
    melody_elapsed = 0;
    melody_index += 1;
    tone(SPEAKER_PIN, NOTE_FS4);
    break;

  case 1:
  case 3:
    // Allow a tone to play for an interval, then change the tone and advance.
    if (melody_elapsed > 1000000) {
      melody_elapsed = 0;      
      melody_index += 1;
      tone(SPEAKER_PIN, NOTE_C4);
    }
    break;

  case 2:
  case 4:
    // Allow a tone to play for an interval, then change the tone and advance.    
    if (melody_elapsed > 1000000) {
      melody_elapsed = 0;      
      melody_index += 1;
      tone(SPEAKER_PIN, NOTE_FS4);
    }
    break;

  case 5:
  default:
    // terminal state: script is done
    noTone(SPEAKER_PIN);
    break;
  }
}

signal processing

smoothing

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/****************************************************************/
void setup(void)
{
  Serial.begin(115200);
}

/****************************************************************/
void loop(void)
{
  static unsigned long last_update_clock = 0;

  unsigned long now = micros();
  unsigned long interval = now - last_update_clock;
  last_update_clock = now;

  const long sample_interval = 10000;   // 10 msec, 100 Hz sampling
  static long sample_timer = 0;
  
  sample_timer -= interval;
  if (sample_timer <= 0) {
    sample_timer += sample_interval;

    int raw_value = analogRead(0);                       // read the current input 
    float calibrated = ((float)raw_value) / 1024.0;      // scale to normalized units 

    static float smoothed_value = 0.0;                   // filtered value of the input
    float difference   =  calibrated - smoothed_value;   // compute the 'error'
    smoothed_value     += 0.1 * difference;              // apply a constant gain to move the smoothed value toward the reading

    Serial.println(smoothed_value);
  }
}

ringfilter

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/****************************************************************/
void setup(void)
{
  Serial.begin(115200);
}

/****************************************************************/
void loop(void)
{
  static unsigned long last_update_clock = 0;

  unsigned long now = micros();
  unsigned long interval = now - last_update_clock;
  last_update_clock = now;

  const long sample_interval = 10000;   // 10 msec, 100 Hz sampling
  static long sample_timer = 0;
  
  sample_timer -= interval;
  if (sample_timer <= 0) {
    sample_timer += sample_interval;

    int raw_value = analogRead(0);
    float calibrated = ((float)raw_value) / 1024.0;

    ringfilter_put(calibrated);

    float velocity = ringfilter_deriv(0.01);
    
    float quadratic_params[3];
    ringfilter_fit_quadratic(quadratic_params);

    Serial.print("v: "); Serial.print(velocity);
    Serial.print(" q: "); Serial.print(quadratic_params[0]);
    Serial.print(" "); Serial.print(quadratic_params[1]);
    Serial.print(" "); Serial.println(quadratic_params[2]);
  }
}

feedback

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// 1. apply proportional feedback using a dual H-bridge driver and analog position sensor
// 2. demonstrate non-blocking event-loop structure
// 3. demonstrate DRV8833 motor driver pulse width modulation
// 4. demonstrate a smoothing filter on an analog input

// Define DRV8833 control pin wiring as per CKS-1 shield board.
const int MOT_A1_PIN = 5;
const int MOT_A2_PIN = 6;
const int MOT_B1_PIN = 10;
const int MOT_B2_PIN = 9;

const int POS_SENSOR_PIN = A0;

/****************************************************************/
void setup(void)
{
  // Configure the four DRV8833 control lines and set them to a quiescent state.
  pinMode(MOT_A1_PIN, OUTPUT);
  pinMode(MOT_A2_PIN, OUTPUT);
  pinMode(MOT_B1_PIN, OUTPUT);
  pinMode(MOT_B2_PIN, OUTPUT);

  digitalWrite(MOT_A1_PIN, LOW);
  digitalWrite(MOT_A2_PIN, LOW);
  digitalWrite(MOT_B1_PIN, LOW);
  digitalWrite(MOT_B2_PIN, LOW);

  // Start the serial port for the console.
  Serial.begin(115200);
}

/****************************************************************/
void loop(void)
{
  static unsigned long last_update_clock = 0;

  unsigned long now = micros();
  unsigned long interval = now - last_update_clock;
  last_update_clock = now;

  poll_feedback_loop(interval);
}

/****************************************************************/
// Polling function for the feedback process: reads an analog position sensor at
// regular sampling intervals, calculates a new motor speed and configures the
// DRV8833 motor driver PWM outputs.

const long sample_interval = 10000;  // 10 msec, 100 Hz sampling
long sample_timer = 0;

float position = 0.0;     // filtered value of the input (unit normalization)
float target = 0.5;       // target position (unit normalization)

void poll_feedback_loop(unsigned long interval)
{
  sample_timer -= interval;
  if (sample_timer <= 0) {
    sample_timer += sample_interval;

    int raw_value = analogRead(POS_SENSOR_PIN);          // read the current input 
    float calibrated = ((float)raw_value) / 1024.0;      // scale to normalized units 

    // first-order smoothing filter to reduce noise in the position estimate
    float difference = calibrated - position;  // compute the 'error' in the sensor reading
    position += 0.2 * difference;              // apply a constant gain to move the smoothed value toward the reading

    // calculate a proportional position control update
    float position_error = target - position;     // compute the position error
    float control_output = 2.0 * position_error;  // apply a proportional position gain

    int control_pwm = constrain((int)(256.0 * control_output), -255, 255);
    set_motor_pwm(control_pwm, MOT_A1_PIN, MOT_A2_PIN);
  }
}

/****************************************************************/
// Set the current speed and direction for either of the DRV8833 channels.
//
// Parameters:
//  pwm     : integer velocity ranging from -255 to 255.
//  IN1_PIN : either MOT_A1_PIN or MOT_B1_PIN
//  IN2_PIN : either MOT_A2_PIN or MOT_B2_PIN
//
// (Note: uses 'fast-decay' mode: coast not brake.)

void set_motor_pwm(int pwm, int IN1_PIN, int IN2_PIN)
{
  if (pwm < 0) {  // reverse speeds
    analogWrite(IN1_PIN, -pwm);
    digitalWrite(IN2_PIN, LOW);

  } else { // stop or forward
    digitalWrite(IN1_PIN, LOW);
    analogWrite(IN2_PIN, pwm);
  }
}

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

shm-metronome

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// demo use of a differential equation generator function
#include <Servo.h> 

const int SERVO_PIN = 9;
Servo svo;

// ================================================================
// Simple Harmonic Motion oscillator, e.g. unit-mass on spring with damping.

const float k    = 4*M_PI*M_PI;   // 1 Hz; freq = (1/2*pi) * sqrt(k/m); k = (freq*2*pi)^2
const float b    = 1.0;           // damping
const float q_d  = 90.0;          // neutral spring position
const float dt   = 0.01;          // integration time step

float q    = 0.0;         // initial position
float qd   = 0.0;         // initial velocity

// ================================================================

void setup(void)
{
  Serial.begin(115200);
  svo.attach(SERVO_PIN);
}

// ================================================================
void loop()
{
  // calculate the derivatives
  float qdd = k * (q_d - q) - b * qd;

  // integrate one time step
  q  += qd  * dt;
  qd += qdd * dt;

  // update the servo
  svo.write(q);

  // logic to reset the oscillator after a cycle has completed
  if (fabs(qd) < 0.1 && fabs(q_d - q) < 0.1) q = 0.0;
      
  // print the output for plotting
  Serial.println(q);

  // delay to control timing
  delay((int)(1000*dt));
}

miscellaneous

numbers

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// Demonstration of the following:
// 1. properties of Arduino Uno numeric types
// 2. use of Serial port for debugging output
// 3. properties of Arduino numbers

// Include optional floating-point numeric constants.
#include <float.h>

void setup()
{
  Serial.begin(115200);
}

void loop()
{
  int   normal = 0;          // 16 bit integer, values range from -32768 to 32767
  long  large  = 0;          // 32 bit integer, values range from -2147483648 to 2147483647
  float number = 0.0;        // 32 bit float, positive values range as high as 3.4028235E+38

  Serial.print("bytes in an int:  "); Serial.println(sizeof(normal));
  Serial.print("bytes in a long:  "); Serial.println(sizeof(large));
  Serial.print("bytes in a float: "); Serial.println(sizeof(number));

  // ----- int : 16 bits -------------------------------------------
  normal = 0x7fff;
  Serial.print("Maximum int value: ");
  Serial.println(normal);

  // use the properties of twos-complement arithmetic to roll over to negative numbers
  normal = normal + 1;
  Serial.print("Minimum int value: ");
  Serial.println(normal);

  normal = LOW;
  Serial.print("Value of LOW: ");
  Serial.println(normal);

  normal = HIGH;
  Serial.print("Value of HIGH: ");
  Serial.println(normal);
  
  // ----- long : 32 bits -------------------------------------------  
  large = 0x7fffffff;
  Serial.print("Maximum long value: ");
  Serial.println(large);

  // use the properties of twos-complement arithmetic to roll over to negative numbers
  large = large + 1;
  Serial.print("Minimum int value: ");
  Serial.println(large);

  // ----- float: 32 bits -------------------------------------------
  number = 0.123456789;
  Serial.print("0.123456789 with float precision: ");
  Serial.println(number, 10);  // 10 decimal places

  number = M_PI;
  Serial.print("Value of pi as a float: ");
  Serial.println(number, 10);

  Serial.println("Please note, the print function does not work as expected for very large or small numbers:");
  
  number = FLT_MAX;
  Serial.print("Maximum positive float value: ");
  Serial.println(number, 10);

  number = FLT_MIN;
  Serial.print("Minimum positive float value: ");
  Serial.println(number, 10);
  
  delay(1000);
}

rocker

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// 1. rock the toy with a servo
// 2. demonstrate the Servo library

#include <Servo.h>

const int ARDUINO_LED = 13;

const int SERVO1_PIN = 23;  // on the Mega Pinball Shield

const int PHOTO1_PIN = A0;  // on the Mega Pinball Shield

const int TILT_X_PIN = A8;  // on the Mega Pinball Shield
const int TILT_Y_PIN = A9;  // on the Mega Pinball Shield
const int TILT_Z_PIN = A10; // on the Mega Pinball Shield 

Servo rocker_servo;

void setup()
{
  pinMode(ARDUINO_LED, OUTPUT);
  rocker_servo.attach(SERVO1_PIN);
  Serial.begin(115200);
}

int lower = 60;
int upper = 80;
int pause1 = 100;
int pause2 = 500;

void loop()
{
  digitalWrite(ARDUINO_LED, HIGH);

  rocker_servo.write(lower);
  delay(pause1);

  digitalWrite(ARDUINO_LED, LOW);  
  rocker_servo.write(upper);
  delay(pause2);

  int photo1 = analogRead(PHOTO1_PIN);
  int tilt_x = analogRead(TILT_X_PIN);
  int tilt_y = analogRead(TILT_Y_PIN);
  int tilt_z = analogRead(TILT_Z_PIN);

  Serial.print("Photo1: "); Serial.print(photo1); Serial.print(" ");
  
  Serial.print("Servo lower upper pause1 pause2: ");
  Serial.print(lower); Serial.print(" ");
  Serial.print(upper); Serial.print(" ");
  Serial.print(pause1); Serial.print(" ");
  Serial.print(pause2); Serial.print(" ");
      
  Serial.print("Tilt XYZ: ");
  Serial.print(tilt_x); Serial.print(" ");
  Serial.print(tilt_y); Serial.print(" ");
  Serial.println(tilt_z);

  if (Serial.available() > 0) {
    lower = Serial.parseInt();
    upper = Serial.parseInt();
    pause1 = Serial.parseInt();
    pause2 = Serial.parseInt();
    while(Serial.available() > 0) Serial.read();
  } 
}

new

switch-counter-servo

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <Servo.h> 

const int SERVO_PIN = 6;
const int SWITCH_PIN = 10;

Servo svo;

void setup(void)
{
  pinMode(SWITCH_PIN, INPUT);
  svo.attach(SERVO_PIN);
}

bool previously_pressed = false;
int angle = 0;
  
void loop(void)
{
  bool input = digitalRead(SWITCH_PIN);

  if (input) {
    // if the switch has not been pressed
    if (previously_pressed) {
      
    
  if (switchPressed) {
  // wait for the switch to be pressed
  while (digitalRead(SWITCH_PIN))  {
    // do nothing
  }

  while 
  

    
  for (int idx = 0; idx < 12; idx = idx + 1) {
    svo.write(angles[idx]);
    delay(500);
  }
}

iteration

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// Demonstration of the following:
// 1. essential program structure and logic
// 2. logic using if () {}
// 3. iteration using loop(), while(){}, and for(){}
// 4. use of Serial port for debugging output

void setup()
{
  Serial.begin(115200);
}

int count = 32700;

// The following shows several possible loop functions, each demonstrating
// different features.  The '#if 0/#endif' pairs are instructions to the
// compiler to ignore an entire block of code.

#if 0
void loop()
{
  count = count + 1;
  Serial.println(count);
  delay(100);
}
#endif


#if 0
void loop()
{
  count = count + 1;  
  Serial.println(count);
  if (count == 32767) {
    count = 32700;
  }
  delay(100);
}
#endif


#if 0
void loop()
{
  while (count < 32767) {
    count = count + 1;  
    Serial.println(count);
    delay(100);    
  }
  count = 32700;
}
#endif

#if 0
void loop()
{
  for (count = 32700; count < 32767; count = count+1) {
    Serial.println(count);
    delay(100);    
  }
}
#endif



  
  

tilt-ball-demo

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// 1. demonstrate a tilt ball switch as digital input
// 2. generate tones on a speaker on pin 5

const int SPEAKER_PIN = 5;
const int SWITCH_PIN = 2;

void setup()
{
  pinMode(SWITCH_PIN, INPUT);
  Serial.begin(115200);
}
void loop()
{
  if (digitalRead(SWITCH_PIN)) {
    noTone(SPEAKER_PIN);    // silence
    Serial.println("1");
  } else {
    tone(SPEAKER_PIN, 440); // play A4 "concert A"
    Serial.println("0");
  }
}