Day 6: (Sep 17) Event Loop Programming

Notes for 2018-09-17. See also the Fall 2018 Calendar.

Notes from Day 5 and Demo 2

  • I’m still reviewing Background Research posts. Please check that your embedded videos are actually working; several are coming up blank.
  • For some of you, let’s work toward fully owning the human justifications.
  • Please attach CAD files as a zip, that’s the easiest way for me review them.
  • Please think more about conveying the action through good video technique.
  • Always: work smarter, not harder.

Agenda

  1. Administrative
    • Please be sure to follow up on Act 153 clearances: I’ll need copies of your PACA and PATCH results, please schedule and attend a fingerprinting session, and please scan and submit your FBI clearance letter when it arrives.
    • Please raise your hand or send me an email if you want a SolidWorks license key and installation instructions.
  2. Assignments
  3. In-class
    1. Demo 3 review. This time we’ll play out an exercise in critique.
      1. Each pair will demo and explain their conversation devices to another pair. We’ll take 5 minutes for this before starting the checkoff round.
      2. During the checkoff review, the authors will operate the devices, but a third party will explain and defend the work. If something comes up which wasn’t originally discussed, the third party will improvise a reasonable answer based on their own judgement and imagination.
      3. The authors will have a chance to clarify their intentions at the end.
      4. The following prompt questions may help spark your inquiries:
        1. What is the language of the conversation?
        2. How does the physical form of the communication create symbolic meaning?
        3. How does the temporal flow of the gestures expose a grammar?
        4. In what ways does the behavior express or simulate intelligence?
    2. Introduce demo 4 and next group assignments.
    3. Demo auto-format operation in Arduino IDE.
    4. Discuss strategies for mixing scripted and reactive behaviors in Arduino C++.
    5. Periodically: each table should confer and generate a question.

Lecture code samples

Non-blocking event loop

 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
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);
  }
}
  

Non-blocking event loop with 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
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);
  }

  // following is a state machine implemented using switch-case
  static int state_index = 0;
  static long elapsed_time = 0;
  switch(state_index) {
  case 0:
    elapsed_time += interval;
    if (elapsed_time > 1000000) {
      elapsed_time = 0;
      state_index = 1;
    }
    break;

  case 1:
    elapsed_time += interval;
    if (elapsed_time > 1000000) {
      elapsed_time = 0;      
      state_index = 2;
    }
    break;

  case 2:
    elapsed_time += interval;
    if (elapsed_time > 1000000) {
      elapsed_time = 0;      
      state_index = 3;
    }
    break;

  case 3:
  default:
    // terminal state: script is done
    elapsed_time += interval;    
    break;
  }
}

Non-blocking polling within delay function

 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);
}

Interruptible delay function

 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
const int SWITCH_PIN = 8;
const int BEEPER_PIN = 7;

void setup(void)
{
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(SWITCH_PIN, INPUT);
  pinMode(BEEPER_PIN, OUTPUT);
  digitalWrite(BEEPER_PIN, LOW);
}

/****************************************************************/
int responsive_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);
    }

    if (digitalRead(SWITCH_PIN)) return 1;
  }
  return 0;
}

/****************************************************************/
void loop(void)
{
  // entering state 0
  if (responsive_delay_and_poll(1000000)) goto react;

  // entering state 1
  if (responsive_delay_and_poll(1000000)) goto react;

  // entering state 2
  if (responsive_delay_and_poll(1000000)) goto react;

  // entering state 3
  while (true) responsive_delay_and_poll(1000000);

 react:
  digitalWrite(BEEPER_PIN, HIGH);
  while (responsive_delay_and_poll(1000));

  responsive_delay_and_poll(500000);
  digitalWrite(BEEPER_PIN, LOW);
}