Pavouk Hiwonder

Nedaří se vám s projektem a nenašli jste vhodné místo, kde se zeptat? Napište sem.
Pravidla fóra
Tohle subfórum je určeno pro konzultaci ucelených nápadů, popřípadě řešení komplexnějších projektů, které opravdu není možné rozdělit na menší části.
Většinu problémů jde rozdělit na menší a ptát se na ně v konkrétních subfórech.
Odpovědět
luger
Příspěvky: 146
Registrován: 30 dub 2023, 11:06
Reputation: 0

Pavouk Hiwonder

Příspěvek od luger » 01 bře 2024, 16:25

Zdravím všechny,
pořídil jsem si nového malého robo pavoučka Hiwonder. Snadno dohledatelné na webu.

Je to drobek, váží asi 3,5 kg a málem neprojde dveřma :lol: . Serva mají tah 20 kg cm a když ho držíte v ruce když zrovna "běží" tak sebou mrská jak ulovený kapr :lol: . Fakt je to síla.

První zkušenosti:
Pavouček je velmi dobře vyrobený, kvalitně, žádné škrábance, kvalitní barva, žádný šroub se nevyklá, serva naprosto bez vůle ! To se sám divím.
Balení obsahuje i baterii Lipol 2000 mA a nabíječku. Nabíječka nejde použít v evropských zásuvkách protože do ní nejde zasunout. Stačí odbrousit nebo odřezat překážející plastovou část a je to v pohodě. Baterka vydrží asi 1 hod běhání a přibližně stejně dlouho se nabíjí.

Pavouček je ovládaný klasickým Arduino UNO a není to nijak omezené nějakýma "speciálnostma". Na firemním webu je k dispozici docela dost programů k ovládání a také příslušné knihovny.
Pozor - přiložené knihovny a programové příkazy k ovládání servocontroléru jsou zřejmě jedinečné a nedají se použít na jiné servocontroléry. Ostatní příkazy fungují normálně (např. Servo, I2C, apod.)

Ovládání serv nožiček a jejich případné přenastavení (nebo naprogramování vlastních "kroků a pohybů" ) je jednoduché a provádí se v přiloženém softwaru (vše lze najít na jejich webu).

luger
Příspěvky: 146
Registrován: 30 dub 2023, 11:06
Reputation: 0

Re: Pavouk Hiwonder

Příspěvek od luger » 02 bře 2024, 10:54

Samozřejmě že jsem se v novém pavoučkovi okamžitě začal vrtat. Plechová duralová konstrukce má mnohu "šliců" a dírek k namontování různých senzorů. Ihned jsem si tam namontoval senzor světla, zvuku a PIR. Gyroskop je součástí dodávky.
Všechny senzory se dají připojit buď na pevné a odolné 4(3)-pinové konektory a nebo jsou k dispozici i klasické vývody samice z UNA.
Funkcí Gyroskopu využívá především program který umožňuje pohyb pavoučka i když je vzhůru nohama. Je to jen taková sranda k pobavení ale může se to hodit když se náhodou pavouček pádem převrátí hore kok.... :lol:
Využil jsem gyroskop jinak - sleduje vychýlení v osách X a Y a pokud se moc nakloní tak stopne pohyby nožiček. Je to velmi jednoduchý prográmek.

luger
Příspěvky: 146
Registrován: 30 dub 2023, 11:06
Reputation: 0

Re: Pavouk Hiwonder

Příspěvek od luger » 04 bře 2024, 16:41

Zvukový senzor (originál Hiwonder dodaný s pavoučkem) je namontovaný pod krytem. Využívám jeho analogový výstup pro možnost ovládání programem. Je docela citlivý a reaguje na písknutí, tlesknutí nebo poklepání na skelet.
PIR jsem zvolil model SR-501 u kterého jde nastavit citlivos i čas. A zdá se mi i citlivější než třeba SR 505.
Světelný senzor je klasika s fotorezistorem. U tohoto taky budu využívat analog výstup.
Vyfotit zatím není co, všechno je schované pod horním krytem. Mám natočené první video, jenže mám zablokovaný přístup na youtube. Musím prý počkat 48 hod k jakémusi ověření. Asi mi FBI nebo MiB zaklepe na dveře nebo něco takového. Jestli přežiju výslech tak sem dám odkaz :lol: .

Uživatelský avatar
gilhad
Příspěvky: 789
Registrován: 07 bře 2018, 11:22
Reputation: 0

Re: Pavouk Hiwonder

Příspěvek od gilhad » 04 bře 2024, 18:24

Vlítne na tebe PETA kvůli trápení a zneužívání zvířat :)

luger
Příspěvky: 146
Registrován: 30 dub 2023, 11:06
Reputation: 0

Re: Pavouk Hiwonder

Příspěvek od luger » 05 bře 2024, 12:31

Na to jsem připravený - pošlu na ně mého bojového pavouka :lol:

Jestli můžu, tak teď trochu vážně. K pavoučkovi je možnost několik "základních" programů a počítá se s tím že si je uživatel, trochu znalý v oboru , upraví.
Základ zůstává stejný - ovládání serv díky předprogramovaných "Action Group" (tyto skupiny jde překopat ) a také výukové základní programy - něco jako povely pro psa - lehni nebo běhej, vyhni se překážce, urči barvu předmětu, reaguj na zvuk atd..... je celkem snadné tyto programy předělat. Vlastně se jen mění některé parametry (např. vzdálenost, světlo apod.).

Já jsem si k úpravě vybral program "Cross the Maze" což je program díky kterému se pavouček vyhýbá překážkám. Postupně do něj vkládám podprogramy k řešení údajů z gyroskopu, PIR, měření vzdáleností ultrazvukem, zvuk, světlo apod. Celý program se postupně docela rychle rozrůstá a začínám se v něm ztrácet (IDE bohužel neumožňuje barevně rozlišit určité "bloky" nebo "skupiny"- začátečník by to určitě ocenil).
Správně uspořádat podmínky procesu není jednoduché. A když je jich 30 vzájemně propojených tak to je teprve sranda. :D

luger
Příspěvky: 146
Registrován: 30 dub 2023, 11:06
Reputation: 0

Re: Pavouk Hiwonder

Příspěvek od luger » 05 bře 2024, 20:23

Takže tady je první video:
https://www.youtube.com/watch?v=NJtphplPa2Q

Ještě se občas někde zasekne, ale to se časem vychytá.
Při kráčení málo zvedá nožky a proto na hustém koberci šlape jaksi bokem. Jde upravit příslušná "skupina povelů pro serva" ale zatím jsem nepřišel na to jak.

jankop
Příspěvky: 1030
Registrován: 06 zář 2017, 20:04
Reputation: 0
Bydliště: Brno
Kontaktovat uživatele:

Re: Pavouk Hiwonder

Příspěvek od jankop » 07 bře 2024, 16:51

Pro rozsáhlejší programy používám v IDE karty - záložky. Bylo by to perfektní, ale to ladění je o život.
ide.png

luger
Příspěvky: 146
Registrován: 30 dub 2023, 11:06
Reputation: 0

Re: Pavouk Hiwonder

Příspěvek od luger » 10 bře 2024, 11:21

Pavouček na videu pracuje na upraveném firemním programu. Zachoval jsem okamžitou možnost ručního ovládání.
V programu je vložený kontrolní podprográmek který ukazuje na matricovém displeji vzdálenost v cm změřenou ultrazvukem.

Teď mě čeká instalace kamery - ESP32 CAM ale zatím nevím kde vzít napětí 5V s odběrem min. 300 mA. Budu tam muset vložit mini step-down měnič. ) Připojit to přímo na Sensor Board se mi zdá velmi odvážné. Kdoví jak to mají ti kluci z Číny popropojované. Nechci nic odpálit. Serva by měly jet na 11,1V takže vůbec netuším kde je jaké napětí :D


Přikládám upravený program.

Kód: Vybrat vše


/******************************************************
* servo ultrazvuk  - D12
* svetlo           - A3
* zvuk             - A2     rozsah 0-1023    min cca 100
* PIR              - D6 
* infra levý       - D     2 ?
* infra pravý      - D     3 ?
* 
* RX               - D9  
* TX               - D8
* DISPLAY          - A0 , A1
*****************************************************/

#include <Wire.h>
#include "Servo.h"
#include "WMMatrixLed.h"
#include "SoftwareSerial.h"
#include "LobotServoController.h"
#include <MPU6050.h>
#include <I2Cdev.h>

#define rxPin 9  //Serial communication interface between arduino and servo controller
#define txPin 8  

#define DIN  A0  //Dot matrix interface
#define CLK  A1
//--------------------------------------------------------------
//#define GO_FORWARD  26         // pomaleji vpřed, střední postoj (původní 26)
#define RYCHLE      30         // rychle vpřed, střední postoj
#define GO_BACK     27         // pomalu kráčet vzad, střední postoj 
#define DOLEVA      32         // rychle doleva, střední postoj
#define DOPRAVA     33         // rychle doprava, střední postoj
#define LEHNOUT      13         // čapnutí a čekat na PIR
//#define NAHORU      34  
#define POMALU      26         // nejpomaleji vpřed 
#define PRESUN_DOLEVA   7
#define PRESUN_DOPRAVA  8 

//---------------------------------------------------------------
#define MIN_DISTANCE_TURN 350 /*Distance avoiding obstacle.The robot avoid obstacle when the obstacle avoidance is less than the set distance*/
#define DALEKO                // vzdálenost větší než 800-1000  
#define BIAS  0               /*Servo deviation.Adjust the data according to the actual situation to make the ultrasound face straight forward*/

#define I2C_ADDR    0x77

//Rigister
#define DISDENCE_L    0          //Low 8 bytes of distance, unit mm
#define DISDENCE_H    1

#define RGB_BRIGHTNESS  50      //0-255

#define RGB_WORK_MODE 2         //RGB mode, 0: user-defined mode 1: breathing light mode default 0

#define RGB1_R      3//R value of No.1 light,0~255,Default is 0
#define RGB1_G      4//Default is 0
#define RGB1_B      5//Default is 255

#define RGB2_R      6//R value of No.2 light,0~255,Default is 0
#define RGB2_G      7//Default is 0
#define RGB2_B      8//Default is 255

#define RGB1_R_BREATHING_CYCLE      9 //In the breathing light mode, the breathing cycle of the R of the No. 1light, the unit is 100ms and the default is 0.
                                      //If the period is set to 3000ms, the value is 30
#define RGB1_G_BREATHING_CYCLE      10
#define RGB1_B_BREATHING_CYCLE      11

#define RGB2_R_BREATHING_CYCLE      12//RGB 2
#define RGB2_G_BREATHING_CYCLE      13
#define RGB2_B_BREATHING_CYCLE      14

#define RGB_WORK_SIMPLE_MODE    0
#define RGB_WORK_BREATHING_MODE   1

//*************************************Gyroskop ********************************************
const float pi = 3.141592;
int16_t ax, ay, az;
int16_t gx, gy, gz;
float x, y, z;
byte  angle_x, angle_y, angle_z, _angle_x, _angle_y, _angle_z;
long ax_p, ay_p, az_p;
//*******************************************************************************************

int svetlo;
int pocitadlo = 0;

Servo sonarServo;  //Examples of ultrasonic servo control
SoftwareSerial MySerial(rxPin, txPin);  //Software serial port instantiation
WMMatrixLed matrixLed(CLK, DIN);  //Instantiated dot matrix
LobotServoController Controller(MySerial); //Instantiated secondary development
MPU6050 accelgyro;

bool WireWriteByte(uint8_t val)
{
    Wire.beginTransmission(I2C_ADDR);
    Wire.write(val);
    if( Wire.endTransmission() != 0 ) {
        return false;
    }
    return true;
}

bool WireWriteDataArray(  uint8_t reg,uint8_t *val,unsigned int len)
{
    unsigned int i;

    Wire.beginTransmission(I2C_ADDR);
    Wire.write(reg);
    for(i = 0; i < len; i++) {
        Wire.write(val[i]);
    }
    if( Wire.endTransmission() != 0 ) {
        return false;
    }

    return true;
}

bool WireReadDataByte(uint8_t reg, uint8_t &val)
{
    if (!WireWriteByte(reg)) {
        return false;
    }
    
    Wire.requestFrom(I2C_ADDR, 1);
    while (Wire.available()) {
        val = Wire.read();
    }
    
    return true;
}
int WireReadDataArray(   uint8_t reg, uint8_t *val, unsigned int len)
{
    unsigned char i = 0;
    
    /* Indicate which register we want to read from */
    if (!WireWriteByte(reg)) {
        return -1;
    }
    
    /* Read block data */
    Wire.requestFrom(I2C_ADDR, len);
    while (Wire.available()) {
        if (i >= len) {
            return -1;
        }
        val[i] = Wire.read();
        i++;
    }
    
    return i;
}

int getDistance() {                          //čtení vzdálenosti ultrazvuku
  u16 distance1, distance2, distance3;
  int distance = 0;
  WireReadDataArray(0,(uint8_t *)&distance1,2);
  WireReadDataArray(0,(uint8_t *)&distance2,2);
  WireReadDataArray(0,(uint8_t *)&distance3,2);
  distance = (distance1 + distance2 + distance3)/3;
  return distance;                           //Back to the measured distance
}

int gDistance;    //Global variable, used to store the distance measured by ultrasonic at the intermediate position
int gLDistance;   //Used to store the distance measured on the left side of the robot
int gRDistance;   //Used to store the distance measured on the right side of the robot


//**************************************************************************************************************
void getAllDistance()            // změřit vzdálenost ve všech třech směrech
{
  uint8_t RGB[6];
  uint8_t breathing[6];
  uint8_t value;
  
  value = RGB_WORK_SIMPLE_MODE;
  WireWriteDataArray(RGB_WORK_MODE,&value,1);
  RGB[0] = 0;RGB[1] = 255;RGB[2] = 255;//RGB1
  RGB[3] = 0;RGB[4] = 255;RGB[5] = 255;//RGB2
  WireWriteDataArray(RGB1_R,RGB,6);
    
  sonarServo.write(90);   //The ultrasonic servo rotates to 90 degrees, which is the middle position
  delay(500);   
  delay(100);                
  gDistance = getDistance();    //Measure the distance and save it to the global variable face gDistance

  sonarServo.write(180);            //turn to 180 degrees
  delay(500);                   //delay for waiting servo to rotate
  delay(100);
  gLDistance = getDistance();   //Measure the distance and save it to gLDistance
  
  sonarServo.write(0);           //Turn to 0 degree
  delay(500);                   //delay for waiting servo to rotate
  delay(100);
  gRDistance = getDistance();   //Measure the distance and save it to gRDistance

  sonarServo.write(90);            //The ultrasonic servo rotates to 90 degrees, which is the middle position
  delay(600);
}

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

void sonar()                                                      //logic of avoiding obstacle
{
  static uint32_t timer = 0;   //počáteční hodnota pro časovač
  static uint8_t step_ = 0;    //počáteční hodnota pro kroky    step_
  
  if (timer > millis())        //Vraťte se,pokud je nastavený čas větší než aktuální počet milisekund,pokud ne, pokračujte v následujících operacích.
    return;
  switch (step_)               //skákání na funkce "case" podle  step_
  {
//-----------------------------------------------------------------------------------------------------------------    
    case 0:                                     //step 0
      gDistance = getDistance();                //změřit vzdálenost vpředu a uložit do  gDistance
             
      naklon ();                                // kontrola náklonu (pokud je pavouček nakloněný tak zastavit
      
      if (pocitadlo >= 5)        //   počet kroků  5     kontrola počtu kroků (po překročení lehnout a čekat na PIR)
    {
      pocitadlo = 0;            // vynulování počítadla kroků
      PIR ();                   // kontrola PIR
  }      
                                                                                                        
                     
      if (!Controller.isRunning()) {            //Počkejte, dokud nebude ukončena akční skupina
        
        if (gDistance > 1000 ){ 
          Controller.runActionGroup(RYCHLE, 0);    //kráčet rychle vpřed    0- znamená neustále až do přerušení
          pocitadlo = pocitadlo + 1;
          step_ = 1;                                   //skočit na step 1
        }
        
        else if (gDistance > 500) {
             Controller.runActionGroup(POMALU, 0);    //kráčet  pomalu  vpřed    0- znamená neustále až do přerušení
            // pocitadlo = pocitadlo + 1;
            step_ = 1;                                   //skočit na step 0
            }
            
        else if (gDistance > 350 || gDistance == 0) {  //Pokud je naměřená vzdálenost větší než specifikovaná vzdálenost pro vyhnutí
                                                                     //se překážce (350 mm), jdi vpřed  
            
            Controller.runActionGroup(POMALU, 0);    //kráčet  nejpomaleji vpřed    0- znamená neustále až do přerušení
            pocitadlo = pocitadlo + 1;
            step_ = 1;                                   //skočit na step 1
        } 
                
        else {                            // Pokud je naměřená vzdálenost menší než zadaná vzdálenost pro vyhnutí se překážce
          Controller.stopActionGroup();   // zastavit kráčení
          step_ = 2;                      // skočit na  step 2
          timer = millis() + 500;         // zjišťuje stav každých 500 ms (původní hodnota 500)
        }
      }
      break;                             // ukončení podmínky pro přepínání
//---------------------------------------------------------------------------------------------------------      
    case 1:                               // step 1
    
      naklon ();                          // kontrola náklonu
      gDistance = getDistance();          // změřit vzdálenost vpředu a uložit do gDistance
            
      if (gDistance < MIN_DISTANCE_TURN && gDistance > 0) {
                                  // Pokud je naměřená vzdálenost menší než specifikovaná vzdálenost pro vyhnutí se překážce (350 mm)
                                  // zastavte všechny akční skupiny a přejděte ke kroku 2.
        Controller.stopActionGroup();       // zastavit
        step_ = 2;                          // skočit na step 2
        timer = millis() + 500;             // původní hodnota 500 
      }
      break;                                // ukončení kroku 1
//-----------------------------------------------------------------------------------------------------------      
    case 2:
      if (!Controller.isRunning()) {      // Počkejte, dokud nebude ukončena aktivní skupina
        getAllDistance();                 // změřit vzdálenost ve všech třech směrech
        
        step_ = 3;                        // skočit na case 3
      } 
      else {
        timer = millis() + 300;           // původní hodnota 500 
      }
      break;                              // ukončení kroku 2
//----------------------------------------------------------------------------------------------------------------      
    case 3:
      static bool lastActionIsGoBack = false;        //Statická proměnná - zaznamenat, zda je poslední akce zpět
      
      if (((gDistance > MIN_DISTANCE_TURN) || (gDistance == 0)) && lastActionIsGoBack == false) {
        
        //Pokud je mezilehlá vzdálenost větší než zadaná vzdálenost pro vyhnutí se překážce (350 mm) a poslední akcí není ustoupit,
        //vraťte se ke kroku 0. Posuzuje se, zda se poslední akce vrací zpět nebo ne, aby se zabránilo pádu programu do
        //smyčky zpět-"dopředu-"dozadu-"dopředu..."
        //      Když je poslední krok zpět, neprovede se vpřed
        
        step_ = 0;                     // návrat na krok 0 
        timer = millis() + 200;        // původní hodnota 200
        lastActionIsGoBack = false;
        break;
      }
      
      if ((((gLDistance >= gRDistance) && (gLDistance > MIN_DISTANCE_TURN)) || gLDistance == 0) && gDistance > 200) {
        
        //Když je minimální vzdálenost na levé straně měřená ultrazvukem větší než minimální vzdálenost na pravé straně
        //větší než specifikovaná vzdálenost pro vyhnutí se překážce a vzdálenost naměřená uprostřed je větší než 200 mm
        //Účelem detekce vzdálenosti uprostřed je vyhnout se předmětům mezi dvěma předními nohami robota, které způsobí
        // že se robot nemůže otočit.
        
        if (!Controller.isRunning()) {                     //Počkejte, dokud nebude ukončena aktivní skupina
          
          naklon();  
          if (gLDistance > 1000){                         // když je vzdálenost vlevo větší než 1000 tak boční přesun
            Controller.runActionGroup(PRESUN_DOLEVA, 4); 
            goto presunL;                                 // přesunout se bokem doleva a pokračovat bez otáčení                                 
          }
          
          Controller.runActionGroup(DOLEVA, 4);         // 3x zatočit doleva nízký postoj
          
          presunL:
          pocitadlo = pocitadlo + 1;
          naklon ();                                       // kontrola náklonu
                    
          lastActionIsGoBack = false;                     //Identifies that the last action is not back
          step_ = 0;  
          timer = millis() + 300;                   // původně 300
        }        
      }
      else if ((((gRDistance > gLDistance) && (gRDistance > MIN_DISTANCE_TURN)) || gRDistance == 0) && gDistance > 200) {
        // Když je minimální vzdálenost na levé straně měřená ultrazvukem větší než minimální vzdálenost na pravé straně
        // větší než specifikovaná vzdálenost pro vyhnutí se překážce a vzdálenost měřená uprostřed (mezi nohama) je větší než 200 mm
        
        if (!Controller.isRunning()) {                //Počkat, dokud nebude ukončena akční skupina
          
          if (gRDistance > 1000){                         // když je vzdálenost vpravo větší než 1000 tak boční přesun
            Controller.runActionGroup(PRESUN_DOPRAVA, 4); 
            goto presunR;                                 // přesunout se bokem doprava a pokračovat bez otáčení                                 
          }
          naklon ();                                    // kontrola náklonu
          Controller.runActionGroup(DOPRAVA, 4);     // 3x zatočit doprava
          
          presunR:
          pocitadlo = pocitadlo + 1;
                    
          lastActionIsGoBack = false;  //Identifies that the last action is not back
          step_ = 0;  
          timer = millis() + 300;             // původně 300
        }           
      }
      else {
        
        Controller.runActionGroup(GO_BACK, 3);      // 3x kráčet zpět 
        naklon ();                                  // kontrola náklonu
        pocitadlo = pocitadlo + 1;
                
        lastActionIsGoBack = true;                   //poslední akce kráčení je zpět
        step_ = 2;                                   //turn to step 2
        timer = millis() + 300;                      // původně 300
      }
      break;
  }
}
//************************************************************************************************************************
void setup() 
{
  Wire.begin();
  Serial.begin(9600);                                //Initialize serial port 0, baud rate 9600
  MySerial.begin(9600);                              //Initialize serial port , baud rate 9600
  sonarServo.attach(12);                             //Set the servo control io port
  sonarServo.write(90); 
  accelgyro.initialize();
  matrixLed.setColorIndex(1);
  matrixLed.setBrightness(3);
  matrixLed.clearScreen();
  
  pinMode(A3, INPUT);                // fotočidlo
  pinMode(A2, INPUT);                // zvukové čidlo
     
  //Controller.runActionGroup(0, 1);                       // střední počáteční pozice 25          0 - nízký postoj , 34 - vysoký postoj    
  Controller.runActionGroup(LEHNOUT, 1);       // původní OBRANA
  Controller.stopActionGroup();               // zastavit
  delay(3000);                                // mírné čekání
  PIR();                                      // kontrola PIR a světla při startu
  
  uint8_t drawBuffer[16] = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  for (int i = 0; i < 16; i++) {
    drawBuffer[i] = 0xff;
    matrixLed.drawBitmap(0,0,16,drawBuffer);   
    delay(20);
  }  

  matrixLed.clearScreen();
}
//*********************************************************************************************************************************************

void loop() 

{
  
  Controller.receiveHandle(); //Receive and process function, fetch data from the serial port receive buffer
  sonar();                    // hlavní vyhodnocování pohybu
  
  int distance = getDistance(); 
            distance = int(distance/10);               //cm
            matrixLed.showNum(1, float(distance));     // zobrazení hodnoty vzdálenosti na display
}

//***********************************************************************************************************************************************
void gyroskop() {
  accelgyro.getAcceleration(&ax, &ay, &az);       // zjistí všechny hodnoty z akcelerometru
  
  ax_p = ax_p + ax;                    // sčítání potřebný počet hodnot 
  ay_p = ay_p + ay;
  az_p = az_p + az;

    x = ax_p;                      
    y = ay_p;
    z = az_p;
     
    // vypočteme sklon a náklon [°]
    angle_x = atan2(x, sqrt(square(y) + square(z)))/(pi/180);
    angle_y = atan2(y, sqrt(square(x) + square(z)))/(pi/180);
    angle_z = atan2(z, sqrt(square(x) + square(y)))/(pi/180);   
  
    ax_p = 0;
    ay_p = 0;
    az_p = 0;
}

//************************************          KONTROLA náklonu   *********************************************************************
   void naklon(){
                        
            uhel:                                             //    návrat z kontroly velkého náklonu
            MPU6050 accelgyro;
            gyroskop ();                                      // --- základní pozice   -    x-y-z   2 - 0 - 85

            if (angle_x > 20 && angle_x < 235 ){
            goto uhel;
            }
            if (angle_y > 20 && angle_y < 235 ){
            goto uhel;
            }
   }

//****************************************************************************************************************************************
   void PIR () {
 
  pocitadlo = 0;
  sonarServo.write(90);            //The ultrasonic servo rotates to 90 degrees
  delay(600);
  
digitalWrite(6,HIGH); 
Controller.runActionGroup(LEHNOUT, 1);   // útok  -  5    obrana - 13
Controller.stopActionGroup();            // zastavit
delay(2000);

while ( digitalRead(6) == LOW && analogRead(A2) >= 50){     // ----přečte PIR (zvuk)---  (---&& analogRead(A2)>200    fotocidlo)

        // svetlo = analogRead (A1);         // precte fotosenzor  -  A
        //
        // if (svetlo >600){
        //  digitalWrite (5,HIGH); }       // zapnutí blesku při nedostatku světla -  pin D
        // else {
        //  digitalWrite (5,LOW);  }       // když je dostatek světla tak vypnout blesk
   } 
}    

//----------------------------------------------------------------------------------------------------------------------------------
void kroky (){
  if (pocitadlo >= 5)        //   počet kroků  5
    {
      pocitadlo = 0;         // vynulování počítadla kroků
      delay(1000);
      PIR ();
  }
}





   

luger
Příspěvky: 146
Registrován: 30 dub 2023, 11:06
Reputation: 0

Re: Pavouk Hiwonder

Příspěvek od luger » 13 bře 2024, 17:00

Potýkám se s problémem použití funkce "millis" v podmínce. Nechci zakládat nové téma protože se jedná konkrétně o program pavouka se všemi příslušnými funkcemi.
Nějak jsem tu funkci millis nepochopil. Hlavně mi jde o co se stane když z "podmínkového balíčku" vyskočím na nějaký void a tam už čas nekontroluji, ale sleduji třeba senzor. Jenže pak se vracím zpět na místo odkud jsem si odskočil a teď nevím co se v programu děje.
Přikládám výstřih z programu který ovládá pohyb pavouka s odskokem na kontrolu PIR senzoru při dosažení 5 kroků.
Převážně to funguje dobře, ale občas se pohyby koušou a jakoby se běh programu vracel kam nemá.
Může mi někdo laicky objasnit jak to funguje ? Díky moc.

Program:

Kód: Vybrat vše

void loop() 
{
if (pocitadlo >= 5)        //   když je počet kroků  5 běž na kontrolu PIR senzoru
    {
      PIR();               
    }
    sonar();                    // hlavní vyhodnocování pohybu
}
//************************************************************************************************************************************

void sonar()                                                      //logic of avoiding obstacle

{
  static uint32_t timer = 0;   //počáteční hodnota pro časovač
  static uint8_t step_ = 0;    //počáteční hodnota pro kroky    step_
  
  if (timer > millis())        //Vraťte se,pokud je nastavený čas větší než aktuální počet milisekund,pokud ne, pokračujte v následujících operacích.
    return;
  switch (step_)               //skákání na funkce "case" podle  step_
  {
//-----------------------------------------------------------------------------------------------------------------    
    case 0:                                     //step 0
      gDistance = getDistance();                //změřit vzdálenost vpředu a uložit do  gDistance
             
      naklon ();                                // kontrola náklonu (pokud je pavouček nakloněný tak zastavit
      
      if (pocitadlo >= 5)        //   počet kroků  5     kontrola počtu kroků (po překročení lehnout a čekat na PIR)
      {
      PIR ();                   // kontrola PIR
      }      
                                                                                                        
        if (!Controller.isRunning()) {            //Počkejte, dokud nebude ukončena akční skupina
        
        if (gDistance > 1000 ){ 
          Controller.runActionGroup(RYCHLE, 0);        //kráčet rychle vpřed    0- znamená neustále až do přerušení
          step_ = 1;                                   //skočit na step 1
        }
        
        else if (gDistance > 500) {
             Controller.runActionGroup(PLAZENI, 0);       //kráčet  pomalu  vpřed    0- znamená neustále až do přerušení
             step_ = 1;                                   //skočit na step 0
            }
            
        else if (gDistance > 350 || gDistance == 0) {          //Pokud je naměřená vzdálenost větší než specifikovaná vzdálenost pro vyhnutí
                                                               //se překážce (350 mm), jdi vpřed  
            
            Controller.runActionGroup(POMALU, 0);        //kráčet  nejpomaleji vpřed    0- znamená neustále až do přerušení
            step_ = 1;                                   //skočit na step 1
        } 
                
        else {                            // Pokud je naměřená vzdálenost menší než zadaná vzdálenost pro vyhnutí se překážce
          Controller.stopActionGroup();   // zastavit kráčení
          step_ = 2;                      // skočit na  step 2
          timer = millis() + 500;         // zjišťuje stav každých 500 ms (původní hodnota 500)
        }
      }
      break;                             // ukončení podmínky pro přepínání
//---------------------------------------------------------------------------------------------------------      
    case 1:                               // step 1
    
      naklon ();                          // kontrola náklonu gyroskopem
      gDistance = getDistance();          // změřit vzdálenost vpředu a uložit do gDistance
            
      if (gDistance < MIN_DISTANCE_TURN && gDistance > 0) {
                                  // Pokud je naměřená vzdálenost menší než specifikovaná vzdálenost pro vyhnutí se překážce (350 mm)
                                  // zastavte všechny akční skupiny a přejděte ke kroku 2.
        Controller.stopActionGroup();       // zastavit
        step_ = 2;                          // skočit na step 2
        timer = millis() + 500;             // původní hodnota 500 
      }
      break;                                // ukončení kroku 1
//-----------------------------------------------------------------------------------------------------------      
    case 2:
      if (!Controller.isRunning()) {      // Počkejte, dokud nebude ukončena aktivní skupina
        getAllDistance();                 // změřit vzdálenost ve všech třech směrech
        step_ = 3;                        // skočit na case 3
      } 
      else {
        timer = millis() + 500;           // původní hodnota 500 
      }
      break;                              // ukončení kroku 2
//----------------------------------------------------------------------------------------------------------------      
    case 3:
      static bool lastActionIsGoBack = false;        //Statická proměnná - zaznamenat, zda je poslední akce zpět
      
      if (((gDistance > MIN_DISTANCE_TURN) || (gDistance == 0)) && lastActionIsGoBack == false) {
        
        //Pokud je mezilehlá vzdálenost větší než zadaná vzdálenost pro vyhnutí se překážce (350 mm) a poslední akcí není ustoupit,
        //vraťte se ke kroku 0. Posuzuje se, zda se poslední akce vrací zpět nebo ne, aby se zabránilo pádu programu do
        //smyčky zpět-"dopředu-"dozadu-"dopředu..."
        //      Když je poslední krok zpět, neprovede se vpřed
        
        step_ = 0;                     // návrat na krok 0 
        timer = millis() + 200;        // původní hodnota 200
        lastActionIsGoBack = false;
        break;
      }
      
      if ((((gLDistance >= gRDistance) && (gLDistance > MIN_DISTANCE_TURN)) || gLDistance == 0) && gDistance > 200) {
        
        //Když je minimální vzdálenost na levé straně měřená ultrazvukem větší než minimální vzdálenost na pravé straně
        //větší než specifikovaná vzdálenost pro vyhnutí se překážce a vzdálenost naměřená uprostřed je větší než 200 mm
        //Účelem detekce vzdálenosti uprostřed je vyhnout se předmětům mezi dvěma předními nohami robota, které způsobí
        // že se robot nemůže otočit.
        
        if (!Controller.isRunning()) {                     //Počkejte, dokud nebude ukončena aktivní skupina
          
          naklon();  
          if (gLDistance > 1000){                         // když je vzdálenost vlevo větší než 1000 tak boční přesun
            Controller.runActionGroup(PRESUN_DOLEVA, 4); 
            goto presunL;                                 // přesunout se bokem doleva a pokračovat bez otáčení                                 
          }
          
          Controller.runActionGroup(DOLEVA, 4);         // 3x zatočit doleva nízký postoj
          
          presunL:
          pocitadlo = pocitadlo + 1;                    // počítání kroků
          naklon ();                                    // kontrola náklonu
                    
          lastActionIsGoBack = false;                   //Identifies that the last action is not back
          step_ = 0;  
          timer = millis() + 300;                       // původně 300
        }        
      }
      else if ((((gRDistance > gLDistance) && (gRDistance > MIN_DISTANCE_TURN)) || gRDistance == 0) && gDistance > 200) {
        // Když je minimální vzdálenost na levé straně měřená ultrazvukem větší než minimální vzdálenost na pravé straně
        // větší než specifikovaná vzdálenost pro vyhnutí se překážce a vzdálenost měřená uprostřed (mezi nohama) je větší než 200 mm
        
        if (!Controller.isRunning()) {                //Počkat, dokud nebude ukončena akční skupina serva
          
          if (gRDistance > 1000){                         // když je vzdálenost vpravo větší než 1000 tak boční přesun
            Controller.runActionGroup(PRESUN_DOPRAVA, 4); 
            goto presunR;                                 // přesunout se bokem doprava a pokračovat bez otáčení                                 
          }
          naklon ();                                    // kontrola náklonu
          Controller.runActionGroup(DOPRAVA, 4);        // 3x zatočit doprava
          
          presunR:
          pocitadlo = pocitadlo + 1;
                    
          lastActionIsGoBack = false;  //Identifies that the last action is not back
          step_ = 0;  
          timer = millis() + 300;                   // původně 300
        }           
      }
      else {
        
        Controller.runActionGroup(GO_BACK, 3);      // 3x kráčet zpět 
        naklon ();                                  // kontrola náklonu
        pocitadlo = pocitadlo + 1;
                
        lastActionIsGoBack = true;                   //poslední akce kráčení je zpět
        step_ = 2;                                   //turn to step 2
        timer = millis() + 300;                      // původně 300
      }
      break;
  }
}

//****************************************************************************************************************************************
void PIR () {
 
if (!Controller.isRunning()) {            //Počkejte, dokud nebude ukončena akční skupina serva
  Controller.runActionGroup(LEHNOUT, 1);  // pavouk si lehne
delay(2000);
//Controller.stopActionGroup();              // zastavit serva

while ( digitalRead(6) == LOW ) {           // ----  čeká na PIR                                    
        pocitadlo = 0;
} 
}
}
   

Uživatelský avatar
gilhad
Příspěvky: 789
Registrován: 07 bře 2018, 11:22
Reputation: 0

Re: Pavouk Hiwonder

Příspěvek od gilhad » 13 bře 2024, 22:34

funkce millis() vraci pocet milisekund od zapnuti arduina (nebo posledního restartu) .

Mas tam promennou timer, do které si ukládáš nějaké budoucí časy.

Takze tam na mnoha mistech tam máš něco jako

timer=millis()+500;

což znamená doba za půl sekundy.

Timer se tam používá na začátku té funkce sonar, pokud je jeho hodnota větší než millis, tak se funkce okamžitě skončí. Čili se čeká, dokud neuběhne dost času, kolik sis posledně nastavil a mezitím se točí ve smyčce loop.

Pokud necháš pavouka běžet dost dlouho, tak se millis přetočí (a timer o chvíli dřív) a celé se to rozsype. Ale to hrozí asi po 50 dnech.

----

Když někde použiješ millis, tak to vezme hodnotu času přesně v okamžik jejího volání (třeba mě teď hodiny ukazují 22:26, když si to někam napíšu, bude to tam napsané a nebude se to měnit. Když se na hodiny podívám později, bude tam jiné číslo, ale ta hodnota zapsaná na papíru bude pořád stejná.).
Když tu hodnotu uložíš do nějaké proměnné, třeba timer, tak se už ta hodnota nemění.
Když někam vyskočíš (teda, když zavoláš nějakou funkci), tak to nevidí ty vnitřní proměnné, ale to ničemu nevadí.
Až se to vrátí, tak ty vnitřní proměnné mají pořád stejné hodnoty. (A protože to jsou proměnné deklarované jako static, tak se neztratí ani když funkce skončí a až se funkce znovu zavolá, tak budou mít stejnou hodnotu jako předtím.)

Odpovědět

Kdo je online

Uživatelé prohlížející si toto fórum: Žádní registrovaní uživatelé a 49 hostů