Timer Shutdown - laser chat

Bonjour,

Je suis tout nouveau et j'essai de réaliser un laser pour que mon chat me laisse tranquille ! :smiley:

J'ai récupérer le code sur un site et je souhaiterais y ajouter un shutdown pour que le laser cesse de fonctionner au bout de 5min par exemple (il va devenir fou sinon ...).

J'ai commencé à lire plusieurs sujets/tuto la dessus et j'avoue être perdu entre les timer/delay (en même temps c'est ma première réalisation).

Est ce qu'une âme charitable peut m'aider ? :wink:

merci !

Mon bout de code ressemble à cela:

#include <Servo.h>


float min_x = 5;
float max_x = 50;
float min_y = 5;
float max_y = 50;
int min_freeze = 100;
int max_freeze = 500;
float minimal_movement = 0;

/* YOU SHOULD NOT HAVE TO MODIFY THE CODE BELOW THIS LINE */

// finding center of square for starting point
int random_delay;
float x_position = min_x + (max_x - min_x) / 2;
float y_position = min_y + (max_y - min_y) / 2;
float x_old_position = x_position;
float y_old_position = y_position;
float x_new_position;
float y_new_position;
float x_speed;
float y_speed;
int movement_time;

// Instantiating two servos
Servo x_servo;
Servo y_servo;
int pos = 0;

void setup() {
  y_servo.attach(6);  // attaches the y servo on pin 6 to the servo object
  x_servo.attach(9);  // attaches the x servo on pin 9 to the servo object
  pinMode (13, OUTPUT);
  digitalWrite (13, HIGH);  // switch on  the laser

  //Place the servos in the center at the beginning
  y_servo.write(y_position);
  x_servo.write(x_position);

}

void loop() {
  movement_time = random(10, 40);
  random_delay = random(min_freeze, max_freeze);
  x_new_position = random(min_x + minimal_movement, max_x - minimal_movement);
  y_new_position = random(min_y + minimal_movement, max_y - minimal_movement);

  if ( (y_new_position > y_old_position) && (abs(y_new_position - y_old_position) < 5 )) {
    y_new_position = y_new_position + minimal_movement;
  }  else if ( (y_new_position < y_old_position) && (abs(y_new_position - y_old_position) < 5 )) {
    y_new_position = y_new_position - minimal_movement;
  }

  if ( (x_new_position > x_old_position) && (abs(x_new_position - x_old_position) < 5 )) {
    x_new_position = x_new_position + minimal_movement;
  }  else if ( (x_new_position < x_old_position) && (abs(x_new_position - x_old_position) < 5 )) {
    x_new_position = x_new_position - minimal_movement;
  }

  x_speed = (x_new_position - x_old_position) / movement_time;
  y_speed = (y_new_position - y_old_position) / movement_time;
  for (pos = 0; pos < movement_time; pos += 1) {
    x_position = x_position + x_speed;
    y_position = y_position + y_speed;
    x_servo.write(x_position);
    y_servo.write(y_position);
    delay(10);
  }
  x_old_position = x_new_position;
  y_old_position = y_new_position;
  delay(random_delay);

}

Tel qu'il est le code ne doit pas faire ce que tu veux, car certaines variables ne sont pas initialisées. D'autres sont nulles.

Les positions en x et y changent par pas de "minimal_movement" qui vaut 0 : donc elles ne changent pas et le laser ne se déplacera pas.
De plus, tu calcules une vitesse en divisant par "movement_time" qui n'est pas initialisé : avec un peu de chance, il vaut 0 et tu auras un bug, sinon, il vaut une valeur inconnue aléatoire et on ne sait pas ce qui se passera.

Commence déjà à régler ces problèmes...

Pour le shutdown, il faut utiliser un chrono et faire tourner la partie actuelle de ton code jusqu'à ce que le chrono arrive à un délai que tu auras décidé à l'avance (en gros le temps d'endurance de ton chat). Le plus simple est de mettre tout le contenu de ta loop dans une fonction et de mettre juste dans la nouvelle loop la gestion du chrono.

La fonction (mais il vaut mieux régler les problèmes actuels avant de faire ça, je te le fais pour l'exemple) :

void gestion_servos () { // je déplace juste le contenu de la loop ici
  movement_time = random(10, 40);
  random_delay = random(min_freeze, max_freeze);
  x_new_position = random(min_x + minimal_movement, max_x - minimal_movement);
  y_new_position = random(min_y + minimal_movement, max_y - minimal_movement);

  if ( (y_new_position > y_old_position) && (abs(y_new_position - y_old_position) < 5 )) {
    y_new_position = y_new_position + minimal_movement;
  }  else if ( (y_new_position < y_old_position) && (abs(y_new_position - y_old_position) < 5 )) {
    y_new_position = y_new_position - minimal_movement;
  }

  if ( (x_new_position > x_old_position) && (abs(x_new_position - x_old_position) < 5 )) {
    x_new_position = x_new_position + minimal_movement;
  }  else if ( (x_new_position < x_old_position) && (abs(x_new_position - x_old_position) < 5 )) {
    x_new_position = x_new_position - minimal_movement;
  }

  x_speed = (x_new_position - x_old_position) / movement_time;
  y_speed = (y_new_position - y_old_position) / movement_time;
  for (pos = 0; pos < movement_time; pos += 1) {
    x_position = x_position + x_speed;
    y_position = y_position + y_speed;
    x_servo.write(x_position);
    y_servo.write(y_position);
    delay(10);
  }
  x_old_position = x_new_position;
  y_old_position = y_new_position;
  delay(random_delay);
}

La gestion du temps dans la loop :

void loop {
  while (millis()-debut < delai) gestion_servos (); // on fait courir le chat
  while (1); // boucle infinie pour calmer le chat avant la crise cardiaque
}

et tu déclares dans l'entête :

unsigned long debut;
unsigned long delai = 1000 * 60 * 10; // 10 minutes (en millisecondes) par exemple

et dans le setup :

debut = millis();

Quand ça fonctionnera, je suis preneur d'une vidéo pour voir le chat courir après la tache du laser... :slight_smile:

Salut,

Merci de ton retour et de tes explications et de tes commentaires! ;D

En effet, voici mes valeurs pour que cela fonctionne:

float min_x = 5;
float max_x = 50;
float min_y = 5;
float max_y = 35;
int min_freeze = 200;
int max_freeze = 3000;
float minimal_movement = 5;

Je vais voir pour tester avec les modifs !

Merci

Salut,

Je viens d'essayer mais le timer ne fonctionne pas ... j'ai du mal l'intégrer...
Voici le bout de code dont je dispose maintenant (j'ai mis 1min pour tester):

/*
  Laser Tower for the CAT - LA FABRIQUE DIY
  Pseudo-randomly moves a servo tower (on X and Y axis) and lights up a laser.
  x_servo is attached to pin 6 and moves in the X plan 
  y_servo is attached to pin 9 and moves in the Y plan 
  Laser is on pin 13
  HOW IT WORKS : 
  The program randomly choose a new position for the laser inside a square you can define below. 
  It checks the new position is different from the old one of at least "minimal_movement".
  It moves the tower to the new position and stays still for a time between min_freeze and max_freeze 
  (this aims to reproduce the behaviour of an insect landing somewhere for a bit and then flying off, 
  that's the variable you need to increase if your cat is fat).
  Ans starts the process over and over again. 
  
  Created 30 Sep 2016 by Lucas Berbesson
*/


#include <Servo.h>

/* YOU CAN CUSTOM THESE VARIABLES IF YOU WANT TO ALTER THE TOWER BEHAVIOUR */

// X servo angle will stay in [min_x, max_x] range
// Y servo angle will stay in [min_y, max_y] range
// to be ajsuted to the size of your living room

unsigned long debut;
unsigned long delai = 1000 * 60 * 1; // 10 minutes (en millisecondes) par exemple

float min_x = 5;
float max_x = 50;
float min_y = 5;
float max_y = 35;
int min_freeze = 200;
int max_freeze = 3000;
float minimal_movement = 5;

/* YOU SHOULD NOT HAVE TO MODIFY THE CODE BELOW THIS LINE */

// finding center of square for starting point
int random_delay;
float x_position = min_x + (max_x - min_x)/2;
float y_position = min_y + (max_y - min_y)/2; 
float x_old_position = x_position;
float y_old_position = y_position;
float x_new_position;
float y_new_position;
float x_speed;
float y_speed;
int movement_time;

// Instantiating two servos
Servo x_servo;  
Servo y_servo;
int pos = 0;

void setup() {
  debut = millis();
  y_servo.attach(6);  // attaches the y servo on pin 6 to the servo object
  x_servo.attach(9);  // attaches the x servo on pin 9 to the servo object
  pinMode (13, OUTPUT);
  digitalWrite (13, HIGH);  // switch on  the laser
  
  //Place the servos in the center at the beginning 
  y_servo.write(y_position); 
  x_servo.write(x_position);     

}

void loop() {
	
  while (millis()-debut < delai) gestion_servos (); // on fait courir le chat
  while (1); // boucle infinie pour calmer le chat avant la crise cardiaque
  }


void gestion_servos () { // je déplace juste le contenu de la loop ici
  movement_time = random(10, 40);
  random_delay = random(min_freeze, max_freeze);
  x_new_position = random(min_x + minimal_movement, max_x - minimal_movement);
  y_new_position = random(min_y + minimal_movement, max_y - minimal_movement);

  if ( (y_new_position > y_old_position) && (abs(y_new_position - y_old_position) < 5 )) {
    y_new_position = y_new_position + minimal_movement;
  }  else if ( (y_new_position < y_old_position) && (abs(y_new_position - y_old_position) < 5 )) {
    y_new_position = y_new_position - minimal_movement;
  }

  if ( (x_new_position > x_old_position) && (abs(x_new_position - x_old_position) < 5 )) {
    x_new_position = x_new_position + minimal_movement;
  }  else if ( (x_new_position < x_old_position) && (abs(x_new_position - x_old_position) < 5 )) {
    x_new_position = x_new_position - minimal_movement;
  }

  x_speed = (x_new_position - x_old_position) / movement_time;
  y_speed = (y_new_position - y_old_position) / movement_time;
  for (pos = 0; pos < movement_time; pos += 1) {
    x_position = x_position + x_speed;
    y_position = y_position + y_speed;
    x_servo.write(x_position);
    y_servo.write(y_position);
    delay(10);
  }
  x_old_position = x_new_position;
  y_old_position = y_new_position;
  delay(random_delay);
}

Est ce que tu peux y jeter un œil ?

Merci :slight_smile:

Après une lecture rapide, je pense que ça vient de ces lignes, placées dans l'entête :

float x_position = min_x + (max_x - min_x)/2;
float y_position = min_y + (max_y - min_y)/2; 
float x_old_position = x_position;
float y_old_position = y_position;

Je l'avais vu la première fois, mais comme ça compilait j'ai pensé que c'était quelque chose que je ne connaissais pas.

Dans l'entête tu dois juste déclarer les variables globales:

float x_position;
float y_position; 
float x_old_position;
float y_old_position;

et dans le setup tu les initialises :

x_position = min_x + (max_x - min_x)/2;
y_position = min_y + (max_y - min_y)/2; 
x_old_position = x_position;
y_old_position = y_position;

Mets ces lignes AVANT la ligne

  //Place the servos in the center at the beginning

Si ça ne marche toujours pas, dans ton prochain message explique ce qui ne va pas...

Ca va pas faire avancer ton projet. - j'en ai fait un dans la meme optique que toi, mais le chat a preferé jouer avec les servomoteurs qui faisaient un bruit bien plus intrigant que le point rouge...

Prevoit de le fixer bien en hauteur... Olivier

Salut,

@Olitask ... Ahah j'espère qu'il vont quand même jouer avec ... ces bêtes à poils hein ! ^^

@lesept

Je ne parviens à pas à téléverser avec les modifications apporter car les valeurs ne sont pas définies dans le scope (voir messages d'erreurs ci dessous).

Le laser fonctionne bien, juste le timer n'est pas pris en compte. >:(

Merci de ton retour.

Arduino : 1.8.4 (Windows 10), Carte : "Arduino/Genuino Uno"

 warning: integer overflow in expression [-Woverflow]

 unsigned long delai = 1000 * 60 * 1; // 10 minutes (en millisecondes) par exemple

                            ^

 In function 'void gestion_servos()':

sketch_jun28a:68: error: 'y_old_position' was not declared in this scope

   if ( (y_new_position > y_old_position) && (abs(y_new_position - y_old_position) < 5 )) {

                          ^

sketch_jun28a:74: error: 'x_old_position' was not declared in this scope

   if ( (x_new_position > x_old_position) && (abs(x_new_position - x_old_position) < 5 )) {

                          ^

sketch_jun28a:80: error: 'x_old_position' was not declared in this scope

   x_speed = (x_new_position - x_old_position) / movement_time;

                               ^

sketch_jun28a:81: error: 'y_old_position' was not declared in this scope

   y_speed = (y_new_position - y_old_position) / movement_time;

                               ^

sketch_jun28a:83: error: 'x_position' was not declared in this scope

     x_position = x_position + x_speed;

     ^

sketch_jun28a:84: error: 'y_position' was not declared in this scope

     y_position = y_position + y_speed;

     ^

exit status 1
'y_old_position' was not declared in this scope

Poste ton code, j'ai du mal à le voir d'ici :slight_smile:

Le voici ;D

Merci pour le temps consacré !

#include <Servo.h>

/* YOU CAN CUSTOM THESE VARIABLES IF YOU WANT TO ALTER THE TOWER BEHAVIOUR */

// X servo angle will stay in [min_x, max_x] range
// Y servo angle will stay in [min_y, max_y] range
// to be ajsuted to the size of your living room

unsigned long debut;
unsigned long delai = 1000 * 60 * 1; // 10 minutes (en millisecondes) par exemple

float min_x = 5;
float max_x = 50;
float min_y = 5;
float max_y = 35;
int min_freeze = 200;
int max_freeze = 3000;
float minimal_movement = 5;

/* YOU SHOULD NOT HAVE TO MODIFY THE CODE BELOW THIS LINE */

// finding center of square for starting point
int random_delay;
float x_new_position;
float y_new_position;
float x_speed;
float y_speed;
int movement_time;

// Instantiating two servos
Servo x_servo;  
Servo y_servo;
int pos = 0;

void setup() {
  debut = millis();
  y_servo.attach(6);  // attaches the y servo on pin 6 to the servo object
  x_servo.attach(9);  // attaches the x servo on pin 9 to the servo object
  pinMode (13, OUTPUT);
  digitalWrite (13, HIGH);  // switch on  the laser
  
  float x_position = min_x + (max_x - min_x)/2;
float y_position = min_y + (max_y - min_y)/2; 
float x_old_position = x_position;
float y_old_position = y_position;
  
  //Place the servos in the center at the beginning 
  y_servo.write(y_position); 
  x_servo.write(x_position);     

}

void loop() {
	
  while (millis()-debut < delai) gestion_servos (); // on fait courir le chat
  while (1); // boucle infinie pour calmer le chat avant la crise cardiaque
  }


void gestion_servos () { // je déplace juste le contenu de la loop ici
  movement_time = random(10, 40);
  random_delay = random(min_freeze, max_freeze);
  x_new_position = random(min_x + minimal_movement, max_x - minimal_movement);
  y_new_position = random(min_y + minimal_movement, max_y - minimal_movement);

  if ( (y_new_position > y_old_position) && (abs(y_new_position - y_old_position) < 5 )) {
    y_new_position = y_new_position + minimal_movement;
  }  else if ( (y_new_position < y_old_position) && (abs(y_new_position - y_old_position) < 5 )) {
    y_new_position = y_new_position - minimal_movement;
  }

  if ( (x_new_position > x_old_position) && (abs(x_new_position - x_old_position) < 5 )) {
    x_new_position = x_new_position + minimal_movement;
  }  else if ( (x_new_position < x_old_position) && (abs(x_new_position - x_old_position) < 5 )) {
    x_new_position = x_new_position - minimal_movement;
  }

  x_speed = (x_new_position - x_old_position) / movement_time;
  y_speed = (y_new_position - y_old_position) / movement_time;
  for (pos = 0; pos < movement_time; pos += 1) {
    x_position = x_position + x_speed;
    y_position = y_position + y_speed;
    x_servo.write(x_position);
    y_servo.write(y_position);
    delay(10);
  }
  x_old_position = x_new_position;
  y_old_position = y_new_position;
  delay(random_delay);
}

Tu n'as pas fait comme je t'ai dit :

lesept:
Dans l'entête tu dois juste déclarer les variables globales:

float x_position;

float y_position;
float x_old_position;
float y_old_position;



et dans le setup tu les initialises :


x_position = min_x + (max_x - min_x)/2;
y_position = min_y + (max_y - min_y)/2;
x_old_position = x_position;
y_old_position = y_position;

Tes variables sont déclarées dans le setup :

float x_position = min_x + (max_x - min_x)/2;
float y_position = min_y + (max_y - min_y)/2; 
float x_old_position = x_position;
float y_old_position = y_position;

donc elles sont locales au setup et ne sont pas connues du reste du programme.

Il faut les déclarer dans l'entête pour qu'elles soient globales (connues de l'ensemble du programme) et les initialiser dans le setup (sans les redéclarer, donc pas de float en début de ligne).

Salut,

Je pense avoir piger le truc; j'ai donc déclarer mes valeurs pour les initialisées dans l'en-tête avant les appeler par la suite !

Par contre le timer ne prends pas ... j'ai mis 1min pour le réglage mais il n'est pas pris en compte:

#include <Servo.h>

/* YOU CAN CUSTOM THESE VARIABLES IF YOU WANT TO ALTER THE TOWER BEHAVIOUR */

// X servo angle will stay in [min_x, max_x] range
// Y servo angle will stay in [min_y, max_y] range
// to be ajsuted to the size of your living room

float x_position;
float y_position; 
float x_old_position;
float y_old_position;

unsigned long debut;
unsigned long delai = 1000 * 60 * 1; // 10 minutes (en millisecondes) par exemple

float min_x = 5;
float max_x = 50;
float min_y = 5;
float max_y = 35;
int min_freeze = 20;
int max_freeze = 300;
float minimal_movement = 5;


/* YOU SHOULD NOT HAVE TO MODIFY THE CODE BELOW THIS LINE */

// finding center of square for starting point
int random_delay;
float x_new_position;
float y_new_position;
float x_speed;
float y_speed;
int movement_time;

// Instantiating two servos
Servo x_servo;  
Servo y_servo;
int pos = 0;

void setup() {
  debut = millis();
  y_servo.attach(6);  // attaches the y servo on pin 6 to the servo object
  x_servo.attach(9);  // attaches the x servo on pin 9 to the servo object
  pinMode (13, OUTPUT);
  digitalWrite (13, HIGH);  // switch on  the laser
  
		x_position = min_x + (max_x - min_x)/2;
		y_position = min_y + (max_y - min_y)/2; 
		x_old_position = x_position;
		y_old_position = y_position;
  
  //Place the servos in the center at the beginning 
  y_servo.write(y_position); 
  x_servo.write(x_position);     

}

void loop() {
	
  while (millis()-debut < delai) gestion_servos (); // on fait courir le chat
  while (1); // boucle infinie pour calmer le chat avant la crise cardiaque
  }


void gestion_servos () { // je déplace juste le contenu de la loop ici
  movement_time = random(10, 40);
  random_delay = random(min_freeze, max_freeze);
  x_new_position = random(min_x + minimal_movement, max_x - minimal_movement);
  y_new_position = random(min_y + minimal_movement, max_y - minimal_movement);

  if ( (y_new_position > y_old_position) && (abs(y_new_position - y_old_position) < 5 )) {
    y_new_position = y_new_position + minimal_movement;
  }  else if ( (y_new_position < y_old_position) && (abs(y_new_position - y_old_position) < 5 )) {
    y_new_position = y_new_position - minimal_movement;
  }

  if ( (x_new_position > x_old_position) && (abs(x_new_position - x_old_position) < 5 )) {
    x_new_position = x_new_position + minimal_movement;
  }  else if ( (x_new_position < x_old_position) && (abs(x_new_position - x_old_position) < 5 )) {
    x_new_position = x_new_position - minimal_movement;
  }

  x_speed = (x_new_position - x_old_position) / movement_time;
  y_speed = (y_new_position - y_old_position) / movement_time;
  for (pos = 0; pos < movement_time; pos += 1) {
    x_position = x_position + x_speed;
    y_position = y_position + y_speed;
    x_servo.write(x_position);
    y_servo.write(y_position);
    delay(10);
  }
  x_old_position = x_new_position;
  y_old_position = y_new_position;
  delay(random_delay);
}

Je ne vois pas pourquoi le timer ne fonctionnerait pas. Voici une version "nettoyée" du code (variables locales plutôt que globales, mais ça ne change rien) avec un Serial.print pour montrer l'évolution du chrono. J'ai aussi ajouté une ligne pour éteindre le laser à la fin du délai.

#include <Servo.h>
#define min_freeze 20
#define max_freeze 300

// X servo angle will stay in [min_x, max_x] range
// Y servo angle will stay in [min_y, max_y] range
// to be ajsuted to the size of your living room

float x_position;
float y_position;
float x_old_position;
float y_old_position;

unsigned long debut;
unsigned long delai = 1000 * 60 * 1; // 10 minutes (en millisecondes) par exemple

float min_x = 5;
float max_x = 50;
float min_y = 5;
float max_y = 35;


// Instantiating two servos
Servo x_servo;
Servo y_servo;

void setup() {
  Serial.begin(115200);
  
  debut = millis();
  y_servo.attach(6);  // attaches the y servo on pin 6 to the servo object
  x_servo.attach(9);  // attaches the x servo on pin 9 to the servo object
  pinMode (13, OUTPUT);
  digitalWrite (13, HIGH);  // switch on  the laser

  x_position = min_x + (max_x - min_x) / 2;
  y_position = min_y + (max_y - min_y) / 2;
  x_old_position = x_position;
  y_old_position = y_position;

  //Place the servos in the center at the beginning
  y_servo.write(y_position);
  x_servo.write(x_position);
}


void loop() {
  while (millis() - debut < delai) gestion_servos (); // on fait courir le chat
  digitalWrite (13, LOW);  // switch off  the laser
  while (1); // boucle infinie pour calmer le chat avant la crise cardiaque
}


void gestion_servos () { // je déplace juste le contenu de la loop ici
  Serial.println(millis() - debut);
  float minimal_movement = 5;
  int movement_time = random(10, 40);
  int random_delay = random(min_freeze, max_freeze);
  float x_new_position = random(min_x + minimal_movement, max_x - minimal_movement);
  float y_new_position = random(min_y + minimal_movement, max_y - minimal_movement);

  if ( (y_new_position > y_old_position) && (abs(y_new_position - y_old_position) < 5 )) {
    y_new_position = y_new_position + minimal_movement;
  }  else if ( (y_new_position < y_old_position) && (abs(y_new_position - y_old_position) < 5 )) {
    y_new_position = y_new_position - minimal_movement;
  }

  if ( (x_new_position > x_old_position) && (abs(x_new_position - x_old_position) < 5 )) {
    x_new_position = x_new_position + minimal_movement;
  }  else if ( (x_new_position < x_old_position) && (abs(x_new_position - x_old_position) < 5 )) {
    x_new_position = x_new_position - minimal_movement;
  }

  float x_speed = (x_new_position - x_old_position) / movement_time;
  float y_speed = (y_new_position - y_old_position) / movement_time;
  for (int pos = 0; pos < movement_time; pos += 1) {
    x_position = x_position + x_speed;
    y_position = y_position + y_speed;
    x_servo.write(x_position);
    y_servo.write(y_position);
    delay(10);
  }
  x_old_position = x_new_position;
  y_old_position = y_new_position;
  delay(random_delay);
}

Peux-tu régler la console sur 115200 et copier / coller ce qui s'affiche dedans ? Peut-être que tu as l'impression que le délai n'est pas pris en compte, alors que c'est un autre problème (servo immobile par exemple).

Salut,

En effet, voici ce qu'il ne prend pas :

C:\.........\sketch_jun28a.ino:15:28: warning: integer overflow in expression [-Woverflow]

 unsigned long delai = 1000 * 60 * 1; // 10 minutes (en millisecondes) par exemple

                            ^

Le croquis utilise 5708 octets (17%) de l'espace de stockage de programmes. Le maximum est de 32256 octets.
Les variables globales utilisent 256 octets (12%) de mémoire dynamique, ce qui laisse 1792 octets pour les variables locales. Le maximum est de 2048 octets.

Peut être :

unsigned long delai = 1000UL * 60 * 1;

ou

unsigned long delai = 1000L * 60 * 1;

Ce n'est qu'un warning, donc la code est compilé et devrait tourner. Qu'affiche la console ?

Super ! Ça fonctionne avec le 1000L !

Merci pour cet accompagnement ! :slight_smile:

De rien ! J'attends la photo du chat épuisé après 10 minutes de chasse du spot laser... :slight_smile: