Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Some problems with Arduino protothreads

I'm doing a project about controlling two sensors (ultrasonic and infrared), managing them with Arduino. The IR receiver has a filter system inside, so it receives at the frequency of 36 kHz. I use the module srf04 to handle the ultrasonic stuff. If I do a program which has to control only one sensor, it works. But I have to interpolate the two signals into one result. So I used protothreads! But it doesn't work... What's the error?

Here is the code:

#include <pt.h>

int iro = 8, iri = 4, us = 12, distanza, us_vcc = 13, ir_vcc = 7;
long durata;

static struct pt pt1, pt2, pt3;

static int irthread(struct pt *pt) {
  PT_BEGIN(pt);
  while(1) {
    PT_WAIT_UNTIL(pt, 1>0);
    digitalWrite(iro, HIGH);
    delayMicroseconds(9);
    digitalWrite(iro, LOW);
    delayMicroseconds(9);
  }
  PT_END(pt);
}

static int usthread(struct pt *pt) {
  static unsigned long timer = 0;
  PT_BEGIN(pt);
  while(1) {
    PT_WAIT_UNTIL(pt, millis() - timer > 200);
    timer = millis();
    pinMode(us, OUTPUT);
    digitalWrite(us, LOW);
    delayMicroseconds(5);
    digitalWrite(us, HIGH);
    delayMicroseconds(10);
    digitalWrite(us, LOW);
    pinMode(us, INPUT);
    durata = pulseIn(us, HIGH);
    distanza = durata/58;
  }
  PT_END(pt);
}

static int leggithread(struct pt *pt) {
  static unsigned long timer = 0;
  PT_BEGIN(pt);
  while(1) {
    PT_WAIT_UNTIL(pt, millis() - timer > 200);
    timer = millis();
    Serial.print(distanza);
    Serial.print("cm ");
    if (digitalRead(iri) == LOW)
      Serial.println("ir si");
    else
      Serial.println("ir no");
  }
  PT_END(pt);
}

void setup() {
  pinMode(iro, OUTPUT);
  pinMode(iri, INPUT);
  pinMode(us_vcc, OUTPUT);
  digitalWrite(us_vcc, HIGH);
  pinMode(ir_vcc, OUTPUT);
  digitalWrite(ir_vcc, HIGH);
  Serial.begin(9600);

  PT_INIT(&pt1);
  PT_INIT(&pt2);
  PT_INIT(&pt3);
}

void loop() {
  irthread(&pt1);
  usthread(&pt2);
  leggithread(&pt3);
}

The single parts of code of each thread works.


Update

I solved my problem (eliminated irthread()) and the code is now like this:

#include <pt.h>

int iro = 8, iri = 4, us = 12, distanza, us_vcc = 13, ir_vcc = 7;
long durata;

static struct pt pt1, pt2;

static int usthread(struct pt *pt) {
  static unsigned long timer = 0;
  PT_BEGIN(pt);
  while(1) {
    PT_WAIT_UNTIL(pt, millis() - timer > 200);
    timer = millis();
    pinMode(us, OUTPUT);
    digitalWrite(us, LOW);
    delayMicroseconds(5);
    digitalWrite(us, HIGH);
    delayMicroseconds(10);
    digitalWrite(us, LOW);
    pinMode(us, INPUT);
    durata = pulseIn(us, HIGH);
  }
  PT_END(pt);
}

static int leggithread(struct pt *pt) {
  static unsigned long timer = 0;
  PT_BEGIN(pt);
  while(1) {
    PT_WAIT_UNTIL(pt, millis() - timer > 200);
    timer = millis();
    distanza = durata/58;
    Serial.print(distanza);
    Serial.print("cm ");
    if(digitalRead(iri) == LOW)
      Serial.println("ir si");
    else
      Serial.println("ir no");
  }
  PT_END(pt);
}

void setup() {
  pinMode(iro, OUTPUT);
  tone(iro, 36000);
  pinMode(iri, INPUT);
  pinMode(us_vcc, OUTPUT);
  digitalWrite(us_vcc, HIGH);
  pinMode(ir_vcc, OUTPUT);
  digitalWrite(ir_vcc, HIGH);
  Serial.begin(9600);

  PT_INIT(&pt1);
  PT_INIT(&pt2);
}

void loop() {
  usthread(&pt1);
  leggithread(&pt2);
}

Now the problem is the ultrasonic sensor. If I control it in a single program without protothreads it can reach objects to a distance of 3 meters. Now even if I put something at 1 meter the "distanza" is 15 cm max. What is the error?

like image 664
Antonio Avatar asked Jun 03 '11 18:06

Antonio


1 Answers

The timers in leggithread() and usthread() interferes with each other. They use the same variable, timer. When time is up, after about 200 milliseconds since last time, in, say leggithread(), the variable is reset. It means the condition in the other function, usthread() (that is called right after), will be false even though the condition there was about to be true. Thus at least another 200 milliseconds will pass before usthread() can do work (outputting a 10 microsecond pulse on port 12).

There is no guarantee that both functions will be called. If you are unlucky only one of them may be called if it is a deterministic system (driven from the same clock, the microcontroller's crystal).

It could be random which one is called or there could be some aliasing between several frequencies (for instance, one frequency represented by the number of executed instructions for each loop - that frequency will change when the program is changed).

If you want both leggithread() and usthread() doing work five times per second then they should each have an independent timer, using separate variables, for example, timer1 and timer2.

like image 194
Peter Mortensen Avatar answered Oct 21 '22 06:10

Peter Mortensen