Objecten ontwijken.

Ik heb een robotje gemaakt die autonoom rond moet gaan rijden. Eerst stond de ultrasoon-sensor gewoon vast op het robotje en werkte alles prima. Echter heb je bij ultrasoon het probleem dat als je een object onder een hoek nadert dat je geen en/of een verkeerde waarde krijgt.
Daarom heb ik de ultrasoon sensor op een servo gemonteerd zodat die "rond" kan kijken.

Ik krijg gewoon prima waarden dus dat probleem is opgelost. Maar ik krijg het niet goed voor elkaar dat hij ook echt goed kan beslissen welke kant die op gaat.

Hoe de code nu werkt:

Servo draait naar 45, 90 en 135 graden en doet op alle waarden een ultrasoon meting en slaat deze op.
Mocht een waarde groter zijn dan 1000 dan is die ongeldig en zet hem op 300.

// Rotate pan-servo and measure distance on 45, 90 and 135 degrees.
  for( int i = 0; i < 3; i++ )
  {
    panservo.write(degs[i]);
    delay(300);
    distance[i] = ultrasonic.Ranging(CM);
    if (distance[i] > 1000)
    {
      distance[i] = 300;
    }      
  }

Daarna gaat hij vergelijken welke waarden het grootste is en gaat dan naar de grootste waarde

// Decide which distance is the furthest.
  if (distance[0] <= distance[1] && distance[1] >= distance[2]) // 90 degrees is greatest
  {
    lcd.setCursor(0,3);
    lcd.print("Direction: Forward");
    leftservo.write(180);
    rightservo.write(0);
    delay(1000);
  }
  else if (distance[0] >= distance[1] && distance[1] >= distance[2]) // 45 degrees is greatest
  {
    lcd.setCursor(0,3);
    lcd.print("Direction: Left");
    leftservo.write(0);
    rightservo.write(0);
    delay(1000);
  }
  else if (distance[0] <= distance[1] && distance[1] <= distance[2]) // 135 degrees is greatest
  {
    lcd.setCursor(0,3);
    lcd.print("Direction: Right");
    leftservo.write(180);
    rightservo.write(180);
    delay(1000);
  }
  else if (distance[0] > distance[1] && distance[1] < distance[2]) // 90 degrees is smallest
  {
    if (distance[0] <= distance[2])
    {
      lcd.setCursor(0,3);
      lcd.print("Direction: Return");
      leftservo.write(0);
      rightservo.write(180);
      delay(1000);
    }
  }

Het grootste probleem nu is dat ie maar zelden ook echt een actie onderneemt, vaak scant hij wel z'n waarden en krijgt ook goede meting. Maar gaat niet rijden en scant gewoon weer opnieuw...

Zie ik iets over het hoofd?

Je gebruikt in iedere if >= en <=. Doordat je de ene keer >= en de volgende keer <= gebruikt zijn ze allebei waar. Dor de if-elsif constructie wordt dan alleen de eerste conditionele set statements uitgevoerd.

Maak voor jezelf even een tabelletje en kijk waar je <= en waar je < moet gebruiken. Idem voor >= en >.

Het lijkt dus fout te gaan op de grenswaarden. Dat moet je goed beredeneren/ontwerpen.

Succes, Karel

Ik kom er niet uit... Ik heb diverse dingen geprobeerd maar krijg niet het gewenste resultaat. Ik heb even flowchart gemaakt zodat het wat makkelijker lezen is voor iedereen. Ik verwacht geen kant een klaar script maar ik kom gewoon niet uit m'n if-loop. De robot maakt geen goede beslissingen terwijl de waarden duidelijk zijn. Ook blijft hij regelmatig "scannen" terwijl er duidelijk een afstand het verste is...

Stealth
De flowchart -die niet echt een flowchart is- komt niet overeen met de code. In de code heb je namelijk 4 acties en in de flowchart maar 3 (Achteruit ontbreekt)

Ik heb volgende vragen

  1. Wat staat er op de LCD?
  2. Krijgen de servo's hun voeding van het Arduino board?
  3. Zijn er nog ander plaatsen in je code waar je de servo's aanspreekt?
  4. Ben je zeker dat de servo's aan de juiste pinnen hangen?

In de stukjes code die je deelt wordt de robot altijd in beweging gesteld. Indien de robot niet beweegt is dat omdat

  • hij niet kan bewegen
  • of omdat arduino nooit aan die code komt
  • of omdat er ergens anders in de code deze acties ongedaan worden gemaakt
  • of een combinatie van deze en of andere zaken.

Met vriendelijke groet.
Jantje

Jantje:
Ik heb volgende vragen

  1. Wat staat er op de LCD?
  2. Krijgen de servo's hun voeding van het Arduino board?
  3. Zijn er nog ander plaatsen in je code waar je de servo's aanspreekt?
  4. Ben je zeker dat de servo's aan de juiste pinnen hangen?
  1. Op Het LCD worden de waardes geprint die de sensor terug geeft, deze kloppen ook gewoon.
  2. Servo's worden apart gevoed door 4 AA's, Uno door een 9v batterij. GND is gedeeld om problemen te voorkomen.
  3. Nee, de servo's worden alleen in de if loop aangesproken
  4. 100% zeker, werken gewoon naar behoren. Als ik een sketch laad die alleen de servo's aanstuurt werkt dit gewoon vlekkeloos.

Hieronder de complete sketch:

#include <Servo.h>
#include "Ultrasonic.h"
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

Ultrasonic ultrasonic(12,13); //(trig,echo)
LiquidCrystal_I2C lcd(0x27,20,4);
Servo panservo;
Servo leftservo;
Servo rightservo;

byte degs[] = { 45, 90, 135 };
int distance[ 3 ] = { 0 };

void setup() {
  Serial.begin(9600);
  panservo.attach(6);
  leftservo.attach(5);
  rightservo.attach(3);
  lcd.init();
  lcd.backlight();
  lcd.print("Starting up...");
}

void loop()
{
  // Be sure the continous servo's don't move
  leftservo.write(90);
  rightservo.write(90);
  
  // Rotate pan-servo and measure distance on 45, 90 and 135 degrees.
  for( int i = 0; i < 3; i++ )
  {
    panservo.write(degs[i]);
    delay(300);
    distance[i] = ultrasonic.Ranging(CM);
    if (distance[i] > 1000)
    {
      distance[i] = 300;
    }      
  }
  
  // Print the measurements to the lcd screen
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print(distance[0]);
  lcd.print(" cm on 45 deg.");
  lcd.setCursor(0,1);
  lcd.print(distance[1]);
  lcd.print(" cm on 90 deg.");
  lcd.setCursor(0,2);
  lcd.print(distance[2]);
  lcd.print(" cm on 135 deg.");
  
  // Decide which distance is the furthest.
  if (distance[0] <= distance[1] && distance[1] >= distance[2]) // 90 degrees is greatest
  {
    lcd.setCursor(0,3);
    lcd.print("Direction: Forward");
    leftservo.write(180);
    rightservo.write(0);
    delay(1000);
  }
  else if (distance[0] >= distance[1] && distance[1] >= distance[2]) // 45 degrees is greatest
  {
    lcd.setCursor(0,3);
    lcd.print("Direction: Left");
    leftservo.write(0);
    rightservo.write(0);
    delay(1000);
  }
  else if (distance[0] <= distance[1] && distance[1] <= distance[2]) // 135 degrees is greatest
  {
    lcd.setCursor(0,3);
    lcd.print("Direction: Right");
    leftservo.write(180);
    rightservo.write(180);
    delay(1000);
  }
  else if (distance[0] > distance[1] && distance[1] < distance[2]) // 90 degrees is smallest
  {
    if (distance[0] <= distance[2])
    {
      lcd.setCursor(0,3);
      lcd.print("Direction: Return");
      leftservo.write(0);
      rightservo.write(180);
      delay(1000);
    }
  }
  delay(100);
}

In ieder geval bedankt voor je reactie!

Vroegah.... heel lang geleden toen ik nog programmeur was bij G&D (ergens eind jaren 70) kreeg ik les van een tweetal ex Volmac leden in het verwerken van gesorteerde bestanden. Daarin hadden wij een begrip dat heette de zogenaamde KSK (= kleinste sorteer kenmerk). Daarbij zoek je naar de kleinste waarde van verschillend gesorteerde bestanden. Jij doet in feite precies hetzelfde. Namelijk de kleinste waarde zoeken van metingen uit 3 hoeken.

En hoe bepaal je dat?
Gewoon alle drie vergelijken
zo:

#define AANTAL_ENTRIES 3 aantal meethoeken

unsigned int ksk = 300; // maximale waarde
unsigned kleinste = AANTAL_ENTRIES + 1; // nog niets gevonden
for (i = 0; i < AANTAL_ENTRIES; i++){ // gewoon de tabel doorlopen
if (distance < ksk) { // als een waarde kleiner is dan de KSK dan wordt dat de nieuwe
_ ksk = distance*; // KSK*_
* kleinste = i; // kleinste is straks de index naar de kleinste waarde*
* }*
}
//
// nu weet je welke index de kleinste waarde heeft en kun je verdere actie ondernemen
//
if (kleinste == AANTAL_ENTRIES + 1) {
* //*
* // er is geen afstand kleiner dan 300 gevonden*
* //*
} else {
* //*
* // er is een kleinere waarde dan 300 gevonden*
* // en die staat in distance[kleinste]*
* //*
}

Stealth0113:

Jantje:
Ik heb volgende vragen

  1. Wat staat er op de LCD?
  2. Krijgen de servo's hun voeding van het Arduino board?
  3. Zijn er nog ander plaatsen in je code waar je de servo's aanspreekt?
  4. Ben je zeker dat de servo's aan de juiste pinnen hangen?
  1. Op Het LCD worden de waardes geprint die de sensor terug geeft, deze kloppen ook gewoon.
  2. Servo's worden apart gevoed door 4 AA's, Uno door een 9v batterij. GND is gedeeld om problemen te voorkomen.
  3. Nee, de servo's worden alleen in de if loop aangesproken
  4. 100% zeker, werken gewoon naar behoren. Als ik een sketch laad die alleen de servo's aanstuurt werkt dit gewoon vlekkeloos.
  1. Ik veronderstel dat er dus geen direction info wordt weergegeven.
  2. dat ziet er goed uit
  3. Das niet waar
void loop()
{
  // Be sure the continous servo's don't move
  leftservo.write(90);
  rightservo.write(90);
  1. Das goed om weten

Wat je nodig hebt is een pragmatiche aanpak om het probleem op te lossen.
Wat ik zou doen

  1. Verplaats deze code naar het einde van setup()
  // Be sure the continous servo's don't move
  leftservo.write(90);
  rightservo.write(90);
  1. Verwijder de
   delay(1000);

uit de beslissings boom.
3) Verhoog de laatste

delay(100);

Nar een getal dat je tijd geeft om te handlen. BV 10000
4) zet je robot op een verhoogje zodat de wielen de grond niet raken.
5) Gebruik je LCD (of de serial monitor) om te debuggen.
Schrijf de waarden op die de scanner je geeft. (VB 0,0,100)
Bepaal welke richting je verwacht dat de robot neemt met deze waarden? (dat zou go right moeten zijn)
Komt dit op de LCD?

    lcd.setCursor(0,3);
    lcd.print("Direction: Right");

Dan is het goed en zou de robot ook moeten werken.

Veel geluk
Jantje

@Nicoverduin & @Jantje: Bedankt voor de reacties! Ik ga dr van het weekend mee aan de slag en laat jullie de uitkomst weten!

Ik ben weer een stukje verder! Het heeft even geduurd voordat ik ermee verder kon omdat ik geen vrije tijd heb op het moment.

Hij kan nu goed beslissen of ie links, rechts of vooruit moet alleen als de waardes minder dan 10cm zijn wil hij nog niet achteruit...
Ook heb ik geprobeerd om naar een object toe te rijden. Bijv. een object is 50cm voor de robot, hij rijd 15cm per seconde. Dus ik had een berekening in de de delay gezet.

distance = distance / 15 * 1000;
delay(distance);

Alleen is hier geen touw aan vast te knopen hoe lang die delay gaat zijn, elke keer doet hij iets anders. Maar niet wat het zou moeten zijn.

Hier nog even de complete code zoals die nu is:

#include <Servo.h>
#include "Ultrasonic.h"
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

Ultrasonic ultrasonic(12,13); //(trig,echo)
LiquidCrystal_I2C lcd(0x27,20,4);
Servo panservo;
Servo leftservo;
Servo rightservo;

byte degs[] = { 45, 90, 135 };
int distance[ 3 ] = { 0 };

void setup() {
  Serial.begin(9600);
  panservo.attach(6);
  leftservo.attach(5);
  rightservo.attach(3);
  lcd.init();
  lcd.backlight();
  lcd.print("Starting up...");
  
  // Be sure the continous servo's don't move
  leftservo.write(90);
  rightservo.write(90);
}

void loop()
{  
  // Rotate pan-servo and measure distance on 45, 90 and 135 degrees.
  for( int i = 0; i < 3; i++ )
  {
    panservo.write(degs[i]);
    delay(300);
    distance[i] = ultrasonic.Ranging(CM);
    if (distance[i] > 1000)
    {
      distance[i] = 300;
    }      
  }
  
  // Print the measurements to the lcd screen
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print(distance[0]);
  lcd.print(" cm on 45 deg.");
  lcd.setCursor(0,1);
  lcd.print(distance[1]);
  lcd.print(" cm on 90 deg.");
  lcd.setCursor(0,2);
  lcd.print(distance[2]);
  lcd.print(" cm on 135 deg.");
  
  // Decide which distance is the furthest.
  if (distance[0] <= distance[1] && distance[1] >= distance[2]) // 90 degrees is greatest
  {
    lcd.setCursor(0,3);
    lcd.print("Direction: Forward");
    leftservo.write(180);
    rightservo.write(0);
  }
  else if (distance[0] > distance[1] && distance[1] >= distance[2]) // 45 degrees is greatest
  {
    lcd.setCursor(0,3);
    lcd.print("Direction: Left");
    leftservo.write(0);
    rightservo.write(0);
  }
  else if (distance[0] <= distance[1] && distance[1] < distance[2]) // 135 degrees is greatest
  {
    lcd.setCursor(0,3);
    lcd.print("Direction: Right");
    leftservo.write(180);
    rightservo.write(180);
  }
  else if (distance[0] < 10 && distance[1] < 10 && distance[1] < 10) // All object are closer then 10cm.
  {
      lcd.setCursor(0,3);
      lcd.print("Direction: Return");
      leftservo.write(0);
      rightservo.write(180);
  }
  delay(10000);
}

Mocht iemand nog suggesties, ideeën of verbeteringen hebben hoor ik dit uiteraard graag!

Gebruik je dan 2 keer distance ?

(1 keer als array en een keer als variabele)

En hoe initialiseer je die variabele ?
En waarom doe je niet gewoon * 66.67 (of net zoveel 6'en als de nauwkeurigheid die je wil halen) ?

Het advies

Jantje:
3) Verhoog de laatste

delay(100);

Naar een getal dat je tijd geeft om te handlen. BV 10000

was enkel voor het debuggen van je code.
Je finale code heeft liefst geen delay. want delay= doe niks = heel slecht

Jantje

MAS3:
Gebruik je dan 2 keer distance ?

(1 keer als array en een keer als variabele)

En hoe initialiseer je die variabele ?
En waarom doe je niet gewoon * 66.67 (of net zoveel 6'en als de nauwkeurigheid die je wil halen) ?

Nee, ik had het hier even uit m'n hoofd opgeschreven. In m'n sketch had ik iets anders gebruikt.

Thnx, voor je berekening. Zo kan het natuurlijk ook! Precisie is niet echt belangrijk want ik hou toch een foutmarge om "aanrijdingen" te voorkomen.

@Jantje: Ik ga het is proberen zonder delay, of anders met MAS3 z'n oplossing maar dan op de manier van de "blink without delay" sketch.