Vítejte na Elektro Bastlírn?
Nuke - Elektro Bastlirna
  Vytvořit účet Hlavní · Fórum · DDump · Profil · Zprávy · Hledat na fóru · Příspěvky na provoz EB

Vlákno na téma KORONAVIRUS - nutná registrace


Nuke - Elektro Bastlirna: Diskuzní fórum

 FAQFAQ   HledatHledat   Uživatelské skupinyUživatelské skupiny   ProfilProfil   Soukromé zprávySoukromé zprávy   PřihlášeníPřihlášení 

Servo se zpětnou vazbou 270°
Jdi na stránku Předchozí  1, 2, 3
 
Přidat nové téma   Zaslat odpověď       Obsah fóra Diskuzní fórum Elektro Bastlírny -> Miniaturní počítače (Arduino, Raspberry a další)
Zobrazit předchozí téma :: Zobrazit následující téma  
Autor Zpráva
bum



Založen: Sep 04, 2011
Příspěvky: 286

PříspěvekZaslal: po říjen 27 2025, 19:51    Předmět: Citovat

Právě že to bude měřit něco co není pravda a zašmodrchovaný to je právě tím že všichni honíte program ale vůbec se nezajímáte o to jak to je všechno zapojené a použité součástky. Ono ani někdo nemůže protože je závislý pouze na simulátorech bez nich je tam kde je. V analogových zapojeních jsme na použité součástky v sedmdesátých letech museli brát zřetel.
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
lesana87



Založen: Sep 20, 2014
Příspěvky: 3882

PříspěvekZaslal: po říjen 27 2025, 20:00    Předmět: Citovat

Plácáš nesmysly, když je tam napětí menší než je krok převodníku, tak prostě naměří 0 (nebo něco kolem nuly, když je tam šum), proč by měl naměřit něco jiného? A je úplně fuk, jaký má ten potenciometr odpor, za předpokladu, že vstupní odpor převodníku je řádově větší a to je určitě.

Už tu chybí jen "Já už jsem dělal blablabla, když ty jsi ještě tahala kačera."
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
bum



Založen: Sep 04, 2011
Příspěvky: 286

PříspěvekZaslal: po říjen 27 2025, 20:51    Předmět: Citovat

Už jsme spolu měli hodně, hodně rozdílných názorů, no a ohledně kačera nevím proč bych měl tvrdit že já už dělal v elektronice když Vy jste tahala kačera, určitě jsem hodně starší než Vy ale tohle jsem nikdy o nikom netvrdil, tím bych tuto konverzaci ukončil. No s tím potenciometrem to bych neřešil, to by jsme se tady jenom osočovali a dohadovali o tom co je mi úplně ukradené. Ono jde o to že dnes vždy někdo něco stáhne z internetu a vůbec o tom nic neví a pak tápe a hlavně nezná funkci součástek a pouze slepě kopíruje zapojeni aniž by věděl co a jak a proč to tak je a další věci a to se týká i programů což je mi již zcela lhostejné.
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
pdp7



Založen: Sep 15, 2014
Příspěvky: 297

PříspěvekZaslal: po říjen 27 2025, 21:05    Předmět: Citovat

Víš co udělám Lesano? Švihnu s tím nepájivým polem o zeď a popájám to na broušáku. Třeba to leccos změní Laughing
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
Valdano



Založen: Jan 01, 2023
Příspěvky: 2683
Bydliště: Česká Lípa

PříspěvekZaslal: po říjen 27 2025, 23:24    Předmět: Citovat

pdp7 napsal(a):
Při kalibraci si to povrkávalo a nehejbalo (uplně stejně jako to co to dělalo doposud). Pak se ukázalo OK.

To je divné, protože s tím mnou upraveným programem se vám servo hýbe. Díval jsem se do toho Arduino_Firmware.ino, který jste tady přiložil.

Příkaz: COMMAND:COVER:CALIBRATE

Pokud je ve funkci loop() identifikován tento příkaz tak se volá funkce calibrateCover() a v ní se hned na začátku pošle na sériový port výpis

RESULT:COVER:CALIBRATE:OK

a až teprve poté se začíná provádět kalibrace. Takže ten výpis se vypíše vždy bez ohledu na stav provedení kalibrace.

Po tom výpisu se uvnitř calibrateCover() volá funkce powerUpServo(). Ve funkci powerUpServo() se na začátku volá digitalWrite(SERVO_SWITCH_PIN, HIGH) tj. zřejmě pin pro zapnutí napájení serva.

Na konci funkce powerUpServo() je chyba, protože se tam volá servo.write(pos) před voláním servo.attach(SERVO_CONTROL_PIN, 500, 2500) tj. v době kdy ještě není přiřazen pin pro řízení serva.

Toto je špatně.
kód:
  servo.write(pos);

  servo.attach(SERVO_CONTROL_PIN, 500, 2500);

  return pos;
}

Opravil jsem to takto.
kód:
  servo.attach(SERVO_CONTROL_PIN, 500, 2500);

  servo.write(pos);

  return pos;
}


Pak se ve funkci calibrateCover() provádí postupný posun serva v 18-ti krocích posunem o 10 od pozice 0 až do pozice 180. Do kalibrace jsem doplnil výpisy na serial monitor ať vidíte jednotlivé kroky viz níže.

Zkuste tedy tuto verzi.

kód:
#include <Servo.h>
#include <FlashStorage.h>

constexpr auto DEVICE_GUID = "55c7745e-d21a-43da-abc5-837adcb27344";

constexpr auto COMMAND_PING = "COMMAND:PING";
constexpr auto RESULT_PING = "RESULT:PING:OK:";

constexpr auto COMMAND_INFO = "COMMAND:INFO";
constexpr auto RESULT_INFO = "RESULT:DarkSkyGeek's Automated Telescope Cover And Spectral Calibrator Firmware v1.0";

constexpr auto COMMAND_COVER_OPEN = "COMMAND:COVER:OPEN";
constexpr auto RESULT_COVER_OPEN_OK = "RESULT:COVER:OPEN:OK";
constexpr auto RESULT_COVER_OPEN_NOK = "RESULT:COVER:OPEN:NOK";

constexpr auto COMMAND_COVER_CLOSE = "COMMAND:COVER:CLOSE";
constexpr auto RESULT_COVER_CLOSE_OK = "RESULT:COVER:CLOSE:OK";
constexpr auto RESULT_COVER_CLOSE_NOK = "RESULT:COVER:CLOSE:NOK";

constexpr auto COMMAND_COVER_CALIBRATE = "COMMAND:COVER:CALIBRATE";
constexpr auto RESULT_COVER_CALIBRATE_OK = "RESULT:COVER:CALIBRATE:OK";

constexpr auto COMMAND_COVER_GET_CALIBRATION = "COMMAND:COVER:GETCALIBRATION";
constexpr auto RESULT_COVER_GET_CALIBRATION = "RESULT:COVER:GETCALIBRATION:";

constexpr auto COMMAND_COVER_GETSTATE = "COMMAND:COVER:GETSTATE";
constexpr auto RESULT_COVER_STATE_OPENING = "RESULT:COVER:GETSTATE:OPENING";
constexpr auto RESULT_COVER_STATE_OPEN = "RESULT:COVER:GETSTATE:OPEN";
constexpr auto RESULT_COVER_STATE_CLOSING = "RESULT:COVER:GETSTATE:CLOSING";
constexpr auto RESULT_COVER_STATE_CLOSED = "RESULT:COVER:GETSTATE:CLOSED";

constexpr auto COMMAND_CALIBRATOR_ON = "COMMAND:CALIBRATOR:ON";
constexpr auto RESULT_CALIBRATOR_ON = "RESULT:CALIBRATOR:ON:OK";

constexpr auto COMMAND_CALIBRATOR_OFF = "COMMAND:CALIBRATOR:OFF";
constexpr auto RESULT_CALIBRATOR_OFF = "RESULT:CALIBRATOR:OFF:OK";

constexpr auto COMMAND_CALIBRATOR_GETSTATE = "COMMAND:CALIBRATOR:GETSTATE";
constexpr auto RESULT_CALIBRATOR_STATE_ON = "RESULT:CALIBRATOR:GETSTATE:ON";
constexpr auto RESULT_CALIBRATOR_STATE_OFF = "RESULT:CALIBRATOR:GETSTATE:OFF";

constexpr auto ERROR_INVALID_COMMAND = "ERROR:INVALID_COMMAND";

constexpr auto STR_OK = "OK";
constexpr auto STR_NOK = "NOK";
constexpr auto STR_SETUP_CALIB_DATA = "SETUP: data kalibrace ";

constexpr auto STR_SERVO_OFF = "Vypnuti napajeni serva";
constexpr auto STR_SERVO_ON = "Zapnuti napajeni serva";
constexpr auto STR_CALIBRATE_START = "Kalibrace: zacatek cyklu";
constexpr auto STR_CALIBRATE_END = "Kalibrace: konec cyklu";
constexpr auto STR_POINT = "Bod: ";
constexpr auto STR_SETPOS = "Presun serva na pozici: ";
constexpr auto STR_WAIT1S = "Cekani 1s...";
constexpr auto STR_SERVO_STAV = "Nacteny stav serva po presunu: ";

// Pins assignment. Change these depending on your exact wiring!
const unsigned int CALIBRATOR_SWITCH_PIN = 6;
const unsigned int SERVO_SWITCH_PIN = 7;
const unsigned int SERVO_FEEDBACK_PIN = 8;
const unsigned int SERVO_CONTROL_PIN = 9;

// Value used to determine whether the NVM (Non-Volatile Memory) was written,
// or we are just reading garbage...
const unsigned long NVM_MAGIC_NUMBER = 0x12345678;

enum CoverState {
  opening,
  open,
  closing,
  closed
} coverState;

enum CalibratorState {
  on,
  off
} calibratorState;

typedef struct {
  unsigned int magicNumber;
  double slope;
  double intercept;
} ServoCalibration;

FlashStorage(nvmStore, ServoCalibration);

Servo servo;
ServoCalibration servoCalibrationData;

// How long do we wait between each step in order to achieve the desired speed?
const unsigned long STEP_DELAY_MICROSEC = 30L * 1000; // 30 msec

// Variables used to move the servo in the main loop...
int servo_position = 0;
unsigned long last_step_time = 0;

void setup()
{
  // Initialize serial port I/O.
  Serial.begin(57600);
  // Wait for serial port to connect. Required for native USB!
  while (!Serial) { }; 
  Serial.flush();

  // Read servo calibration data oin Flash storage:
  servoCalibrationData = nvmStore.read();

  // Initialize pins...
  pinMode(CALIBRATOR_SWITCH_PIN, OUTPUT);
  pinMode(SERVO_SWITCH_PIN, OUTPUT);
  pinMode(SERVO_FEEDBACK_PIN, INPUT);
  pinMode(SERVO_CONTROL_PIN, OUTPUT);

  // Make sure the RX, TX, and built-in LEDs don't turn on, they are very bright!
  // Even though the board is inside an enclosure, the light can be seen shining
  // through the small opening for the USB connector! Unfortunately, it is not
  // possible to turn off the power LED (green) in code...
  pinMode(PIN_LED_TXL, INPUT);
  pinMode(PIN_LED_RXL, INPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);

  // Make sure the servo is initially de-energized...
  digitalWrite(SERVO_SWITCH_PIN, LOW);

  // Make sure the calibrator is initially turned off...
  digitalWrite(CALIBRATOR_SWITCH_PIN, LOW);
  calibratorState = off;

  servo_position = 0;
  last_step_time = 0L;

  // When there is no calibration data yet, we have to assume that the cover is closed...
  if (servoCalibrationData.magicNumber != NVM_MAGIC_NUMBER) {
    coverState = closed;
  } else {
    // Close the cover, in case it is not completely closed.
    // To make sure that `closeCover` does not have an undefined behavior,
    // we initialize the `coverState` variable to `open`, just in case.
    // That variable will be updated in the `closeCover` function,
    // and then again once the cover has completely closed.
    coverState = open;
    closeCover(false);
  }
}

void loop()
{
  if (Serial.available() > 0) {
    String command = Serial.readStringUntil('\n');
    if (command == COMMAND_PING) {
      handlePing();
    } else if (command == COMMAND_INFO) {
      sendFirmwareInfo();
    } else if (command == COMMAND_COVER_GETSTATE) {
      sendCurrentCoverState();
    } else if (command == COMMAND_COVER_OPEN) {
      openCover(true);
    } else if (command == COMMAND_COVER_CLOSE) {
      closeCover(true);
    } else if (command == COMMAND_COVER_CALIBRATE) {
      calibrateCover();
    } else if (command == COMMAND_CALIBRATOR_GETSTATE) {
      sendCurrentCalibratorState();
    } else if (command == COMMAND_CALIBRATOR_ON) {
      turnCalibratorOn();
    } else if (command == COMMAND_CALIBRATOR_OFF) {
      turnCalibratorOff();
    } else if (command == COMMAND_COVER_GET_CALIBRATION) {
      sendCalibrationData();
    } else {
      handleInvalidCommand();
    }
  }

  // Blink the built-in LED to let the user know that the device needs to be calibrated once!
  // Note: The device needs to be recalibrated every time the firmware is flashed.
  if (servoCalibrationData.magicNumber != NVM_MAGIC_NUMBER) {
    digitalWrite(LED_BUILTIN, HIGH);
    delay(500);
    digitalWrite(LED_BUILTIN, LOW);
    delay(500);
  }

  if (coverState == opening || coverState == closing) {
    // Make sure we don't prematurely take a step if it's too early...
    unsigned long now = micros();
    if (now - last_step_time >= STEP_DELAY_MICROSEC) {
      last_step_time = now;

      if (coverState == opening) {
        servo_position++;
        if (servo_position >= 180) {
          servo_position = 180;
          coverState = open;
        }
      } else if (coverState == closing) {
        servo_position--;
        if (servo_position <= 0) {
          servo_position = 0;
          coverState = closed;
        }
      }

      servo.write(servo_position);

      if (coverState == open || coverState == closed) {
        powerDownServo();
      }
    }
  }
}

void handlePing()
{
  Serial.print(RESULT_PING);
  Serial.println(DEVICE_GUID);
}

void sendFirmwareInfo()
{
  Serial.println(RESULT_INFO);
}

void sendCurrentCoverState()
{
  switch (coverState) {
    case opening:
      Serial.println(RESULT_COVER_STATE_OPENING);
      break;
    case open:
      Serial.println(RESULT_COVER_STATE_OPEN);
      break;
    case closing:
      Serial.println(RESULT_COVER_STATE_CLOSING);
      break;
    case closed:
      Serial.println(RESULT_COVER_STATE_CLOSED);
      break;
  }
}

void openCover(bool writeResultToSerial)
{
  if (servoCalibrationData.magicNumber != NVM_MAGIC_NUMBER || (coverState != closed && coverState != closing)) {
    if (writeResultToSerial) {
      Serial.println(RESULT_COVER_OPEN_NOK);
    }
    return;
  }

  servo_position = powerUpServo();
  coverState = opening;

  if (writeResultToSerial) {
    Serial.println(RESULT_COVER_OPEN_OK);
  }
}

void closeCover(bool writeResultToSerial)
{
  if (servoCalibrationData.magicNumber != NVM_MAGIC_NUMBER || (coverState != open && coverState != opening)) {
    if (writeResultToSerial) {
      Serial.println(RESULT_COVER_CLOSE_NOK);
    }
    return;
  }

  servo_position = powerUpServo();
  coverState = closing;

  if (writeResultToSerial) {
    Serial.println(RESULT_COVER_CLOSE_OK);
  }
}

void calibrateCover()
{
  int i, pos = 0, stp = 10;
  int nDataPoints = 1 + 180 / stp;
  int feedbackValue = 0;
  double x[nDataPoints] = { 0 };
  double y[nDataPoints] = { 0 };

  Serial.println(RESULT_COVER_CALIBRATE_OK);

  powerUpServo();

  Serial.println(STR_CALIBRATE_START);
  for (i = 0, pos = 0; pos <= 180; i++, pos = i * stp) {
    Serial.print(STR_POINT);
    Serial.println(1 + i);
    Serial.print(STR_SETPOS);
    Serial.println(pos);
    servo.write(pos);
    Serial.println(STR_WAIT1S);
    delay(1000);
    feedbackValue = analogRead(SERVO_FEEDBACK_PIN);
    Serial.print(STR_SERVO_STAV);
    Serial.println(feedbackValue);
    x[i] = pos;
    y[i] = feedbackValue;
  }
  Serial.println(STR_CALIBRATE_END);

  linearRegression(x, y, nDataPoints, &servoCalibrationData.slope, &servoCalibrationData.intercept);
  servoCalibrationData.magicNumber = NVM_MAGIC_NUMBER;
  nvmStore.write(servoCalibrationData);

  coverState = open;

  closeCover(false);
}

void sendCalibrationData()
{
  Serial.print(RESULT_COVER_GET_CALIBRATION);
  if (servoCalibrationData.magicNumber != NVM_MAGIC_NUMBER) {
    Serial.println("0:0");
  } else {
    Serial.print(servoCalibrationData.slope);
    Serial.print(":");
    Serial.println(servoCalibrationData.intercept);
  }
}

void sendCurrentCalibratorState()
{
  switch (calibratorState) {
    case on:
      Serial.println(RESULT_CALIBRATOR_STATE_ON);
      break;
    case off:
      Serial.println(RESULT_CALIBRATOR_STATE_OFF);
      break;
  }
}

void turnCalibratorOn()
{
  digitalWrite(CALIBRATOR_SWITCH_PIN, HIGH);
  calibratorState = on;
  Serial.println(RESULT_CALIBRATOR_ON);
}

void turnCalibratorOff()
{
  digitalWrite(CALIBRATOR_SWITCH_PIN, LOW);
  calibratorState = off;
  Serial.println(RESULT_CALIBRATOR_OFF);
}

void handleInvalidCommand()
{
  Serial.println(ERROR_INVALID_COMMAND);
}

// Energize and attach servo.
int powerUpServo()
{
  // Vypis zapnuti napajeni serva
  Serial.println(STR_SERVO_ON);

  digitalWrite(SERVO_SWITCH_PIN, HIGH);

  // Default position (closed), which will be used only once,
  // before we have successfully calibrated the servo.
  int pos = 0;

  if (servoCalibrationData.magicNumber == NVM_MAGIC_NUMBER) {
    // Short delay, so that the servo has been fully initialized.
    // Not 100% sure this is necessary, but it won't hurt.
    delay(1000);

    int feedbackValue = analogRead(SERVO_FEEDBACK_PIN);
    pos = (int)((feedbackValue - servoCalibrationData.intercept) / servoCalibrationData.slope);

    // Deal with slight errors in the calibration process...
    if (pos < 0) {
      pos = 0;
    } else if (pos > 180) {
      pos = 180;
    }
  }

  // The optional min and max pulse width parameters are actually quite important
  // and depend on the exact servo you are using. Without specifying them, you may
  // not be able to use the full range of motion (270 degrees for this project)
  servo.attach(SERVO_CONTROL_PIN, 500, 2500);

  // This step is critical!
  // Without it, the servo does not know its position,
  // and the first write command will make it jerk to that position,
  // which is what we want to avoid...
  servo.write(pos);

  return pos;
}

// Detach and de-energize servo to eliminate any possible sources of vibrations.
// Magnets will keep the cover in position, whether it is open or closed.
void powerDownServo()
{
  // Vypis vypnuti napajeni serva
  Serial.println(STR_SERVO_OFF);
  servo.detach();
  digitalWrite(SERVO_SWITCH_PIN, LOW);
}

// Function to calculate the mean of an array.
double mean(double arr[], int n)
{
  double sum = 0.0;
  for (int i = 0; i < n; i++) {
    sum += arr[i];
  }
  return sum / n;
}

// Function to calculate the slope and intercept of a linear regression line.
void linearRegression(double x[], double y[], int n, double *slope, double *intercept)
{
  double x_mean = mean(x, n);
  double y_mean = mean(y, n);
  double numerator = 0.0;
  double denominator = 0.0;
  for (int i = 0; i < n; i++) {
    numerator += (x[i] - x_mean) * (y[i] - y_mean);
    denominator += (x[i] - x_mean) * (x[i] - x_mean);
  }
  *slope = numerator / denominator;
  *intercept = y_mean - (*slope * x_mean);
}
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
lesana87



Založen: Sep 20, 2014
Příspěvky: 3882

PříspěvekZaslal: út říjen 28 2025, 0:32    Předmět: Citovat

Valdano napsal(a):
Na konci funkce powerUpServo() je chyba, protože se tam volá servo.write(pos) před voláním servo.attach(SERVO_CONTROL_PIN, 500, 2500) tj. v době kdy ještě není přiřazen pin pro řízení serva.

To není chyba, to je schválně je to tam i vysvětlený v komentáři. Po zavolání servo.attach() se servo nastaví do naposledy navolené pozice, proto ji nejdřív nastaví voláním servo.write(), aby servo zůstalo tam, kde je. Tak, jak jsi to přehodil, ztrácí celá zpětná vazba smysl.
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
pdp7



Založen: Sep 15, 2014
Příspěvky: 297

PříspěvekZaslal: út říjen 28 2025, 10:48    Předmět: Citovat

Omlovám se všem, ale jak jsem napsal že si to popájím na broušáku (Danykův styl výroby DPS) tak jsem udělal a hádejte co. Funguje Laughing
Samozřejmně ještě popřemýšlím na tom odděleném silovém napájení serva (on ten dekl bude poměrně velký. Dalekohled je 300mm.
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
pdp7



Založen: Sep 15, 2014
Příspěvky: 297

PříspěvekZaslal: út říjen 28 2025, 16:30    Předmět: Citovat

Možno takto? Nebude onen spínaný stabilizátor nějak ovlivňovat arduino?


DC-extra.png
 Komentář:
 Velikost:  17.68 kB
 Zobrazeno:  9 krát

DC-extra.png


Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
Zobrazit příspěvky z předchozích:   
Přidat nové téma   Zaslat odpověď       Obsah fóra Diskuzní fórum Elektro Bastlírny -> Miniaturní počítače (Arduino, Raspberry a další) Časy uváděny v GMT + 1 hodina
Jdi na stránku Předchozí  1, 2, 3
Strana 3 z 3

 
Přejdi na:  
Nemůžete odesílat nové téma do tohoto fóra.
Nemůžete odpovídat na témata v tomto fóru.
Nemůžete upravovat své příspěvky v tomto fóru.
Nemůžete mazat své příspěvky v tomto fóru.
Nemůžete hlasovat v tomto fóru.
Nemůžete připojovat soubory k příspěvkům
Můžete stahovat a prohlížet přiložené soubory

Powered by phpBB © 2001, 2005 phpBB Group
Forums ©
Nuke - Elektro Bastlirna

Informace na portálu Elektro bastlírny jsou prezentovány za účelem vzdělání čtenářů a rozšíření zájmu o elektroniku. Autoři článků na serveru neberou žádnou zodpovědnost za škody vzniklé těmito zapojeními. Rovněž neberou žádnou odpovědnost za případnou újmu na zdraví vzniklou úrazem elektrickým proudem. Autoři a správci těchto stránek nepřejímají záruku za správnost zveřejněných materiálů. Předkládané informace a zapojení jsou zveřejněny bez ohledu na případné patenty třetích osob. Nároky na odškodnění na základě změn, chyb nebo vynechání jsou zásadně vyloučeny. Všechny registrované nebo jiné obchodní známky zde použité jsou majetkem jejich vlastníků. Uvedením nejsou zpochybněna z toho vyplývající vlastnická práva. Použití konstrukcí v rozporu se zákonem je přísně zakázáno. Vzhledem k tomu, že původ předkládaných materiálů nelze žádným způsobem dohledat, nelze je použít pro komerční účely! Tento nekomerční server nemá z uvedených zapojení či konstrukcí žádný zisk. Nezodpovídáme za pravost předkládaných materiálů třetími osobami a jejich původ. V případě, že zjistíte porušení autorského práva či jiné nesrovnalosti, kontaktujte administrátory na diskuzním fóru EB.


PHP-Nuke Copyright © 2005 by Francisco Burzi. This is free software, and you may redistribute it under the GPL. PHP-Nuke comes with absolutely no warranty, for details, see the license.
Čas potřebný ke zpracování stránky 0.19 sekund