Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pm:prj2024:ccontasel:raluca.movileanu [2024/05/17 11:11]
ana_maria.diaconu02 [Software Design]
pm:prj2024:ccontasel:raluca.movileanu [2024/05/26 23:22] (current)
raluca.movileanu [Download]
Line 129: Line 129:
  
  
-Masina si telecomanda sunt complet functionale(se pot observa si ledurile aprinse in imagine). 
  
 ===== Software Design ===== ===== Software Design =====
Line 136: Line 135:
 <note tip> <note tip>
   * Mediu de dezvoltare: Arduino IDE   * Mediu de dezvoltare: Arduino IDE
-  * Librării ​ÅŸi surse 3rd-party: SPI.h, nRF24L01.h, RF24.h+  * Librarii ​ÅŸi surse 3rd-party: SPI.h, nRF24L01.h, RF24.h
 </​note>​ </​note>​
  
-**Cod telecomanda:​** +<note important>LINK GITHUB: https://​github.com/​Raluck20/​Masina_cu_telecomanda</note>
-  #include<SPI.h> +
-  #​include<​nRF24L01.h> +
-  #include<RF24.h> +
-   +
-  RF24 radio(7, 10); +
-   +
-  const byte adress[6] = "​00001";​ +
-   +
-  const int fata = A0;  +
-  const int spate = A1;  +
-  const int stanga = A2; +
-  const int dreapta = A3;  +
-  const int fataStanga = A4; +
-  const int fataDreapta = A5;  +
-  const int spateStanga = A6; +
-  const int spateDreapta = A7;  +
-  const int rotireStanga = 3; +
-  const int rotireDreapta = 2; +
-   +
-  int stateFata = 0; +
-  int stateSpate = 0; +
-  int stateStanga = 0; +
-  int stateDreapta = 0; +
-  int stateFataStanga = 0; +
-  int stateFataDreapta = 0; +
-  int stateSpateStanga = 0; +
-  int stateSpateDreapta = 0; +
-   +
-  void setup() { +
-    Serial.begin(9600);​ +
-    radio.begin();​ +
-    radio.openWritingPipe(adress);​ +
-    radio.setPALevel(RF24_PA_LOW);​ +
-    radio.stopListening();​ +
-  } +
-   +
-  void loop() { +
-    int valoareFata = analogRead(fata);​ +
-    int valoareSpate = analogRead(spate);​ +
-    int valoareStanga = analogRead(stanga);​ +
-    int valoareDreapta = analogRead(dreapta);​ +
-    int valoareFataStanga = analogRead(fataStanga);​ +
-    int valoareFataDreapta = analogRead(fataDreapta);​ +
-    int valoareSpateStanga = analogRead(spateStanga);​ +
-    int valoareSpateDreapta = analogRead(spateDreapta);​ +
-     +
-    if(valoareFata > 1015) { +
-      Serial.println("​fata"​);​ +
-      comanda("​fata"​);​ +
-      delay(500);​ +
-    }  +
-     +
-    if(valoareSpate > 1015) { +
-      Serial.println("​spate"​);​ +
-      comanda("​spate"​);​ +
-      delay(500);​ +
-    }  +
-     +
-    if(valoareStanga > 1015) { +
-      Serial.println("​stanga"​);​ +
-      comanda("​stanga"​);​ +
-      delay(500);​ +
-    }  +
-     +
-    if(valoareDreapta > 1015) { +
-      Serial.println("​dreapta"​);​ +
-      comanda("​dreapta"​);​ +
-      delay(500);​ +
-    }  +
-     +
-    if(valoareFataStanga > 1015) { +
-      Serial.println("​fata stanga"​);​ +
-      comanda("​fata stanga"​);​ +
-      delay(500);​ +
-    }  +
-     +
-    if(valoareFataDreapta > 1015) { +
-      Serial.println("​fata dreapta"​);​ +
-      comanda("​fata dreapta"​);​ +
-      delay(500);​ +
-    }  +
-     +
-    if(valoareSpateStanga > 1015) { +
-      Serial.println("​spate stanga"​);​ +
-      comanda("​spate stanga"​);​ +
-      delay(500);  +
-    }  +
-     +
-    if(valoareSpateDreapta > 1015) { +
-      Serial.println("​spate dreapta"​);​ +
-      comanda("​spate dreapta"​);​ +
-      delay(500);​ +
-    }  +
-     +
-    if (digitalRead(rotireStanga) == HIGH) { +
-      Serial.println("​rotire stanga"​);​ +
-      comanda("​rotire stanga"​);​ +
-      delay(500);​ +
-    }  +
-     +
-    if (digitalRead(rotireDreapta) == HIGH) { +
-      Serial.println("​rotire dreapta"​);​ +
-      comanda("​rotire dreapta"​);​ +
-      delay(500);​ +
-    }  +
-  } +
-   +
-  void comanda(const char *mesaj){ +
-    char message[32];​ +
-    snprintf(message,​ sizeof(message),​ "​%s",​ mesaj); +
-    radio.write(&​message,​ sizeof(message));​ +
-  }+
  
 +**__Telecomanda:​__**
  
-**Cod masina:** +Initializare: 
-  ​#include <SPI.h> +  ​* Biblioteca SPI este inclusa pentru a permite comunicarea prin protocolul ​SPI. 
-  ​#include <nRF24L01.h> +  ​* Biblioteca ​nRF24L01 ​si RF24 sunt incluse pentru a gestiona modulul de comunicatie wireless ​RF24. 
-  #include <RF24.h> +  ​* Se defineste un obiect ​RF24 pentru modulul ​radio, ​specificand pinii 7 si 10 pentru ​conexiune. 
-   +  ​* Se defineste adresa de scriere a datelor pentru modulul RF24. 
-  const int motor1Inainte = 45; +  ​* Se definesc pinii pentru citirea comenzilor ​(analogici si digitalide la butoane.
-  const int motor1Inapoi = 44; +
-  const int motor2Inainte = 43; +
-  const int motor2Inapoi = 42; +
-   +
-  const int motor3Inainte = 39; +
-  const int motor3Inapoi = 38; +
-  const int motor4Inainte = 37; +
-  const int motor4Inapoi = 36; +
-   +
-  const char fata[] = "​fata";​ +
-  const char spate[] = "​spate";​ +
-  const char stanga[] = "​stanga";​ +
-  const char dreapta[] = "​dreapta";​ +
-  const char fataStanga[] = "fata stanga";​ +
-  const char fataDreapta[] = "fata dreapta";​ +
-  const char spateStanga[] = "spate stanga";​ +
-  const char spateDreapta[] = "spate dreapta";​ +
-  const char rotireStanga[] = "​rotire stanga";​ +
-  const char rotireDreapta[] = "​rotire dreapta";​  +
-   +
-  const int buzzer = 22; +
-  const int led1 = 26; +
-  const int led2 = 27; +
-  ​ +
-  RF24 radio(253); +
-  const byte address[6] = "​00001";​ +
-   +
-  unsigned long previousMillis = 0; +
-  const long interval = 3000; //​Interval ​pentru ​buzzer si leduri (1.5 sec pornite, 1.5 sec oprite) +
-  ​bool ledState = LOW; +
-  bool buzzerState = LOW; +
-   +
-  void setup() { +
-    Serial.begin(9600);​ +
-  ​ +
-    radio.begin(); +
-    radio.openReadingPipe(0,​ address); +
-    radio.setPALevel(RF24_PA_MIN);​ +
-    radio.startListening();​ +
-   +
-    pinMode(motor1Inainte,​ OUTPUT); +
-    pinMode(motor1Inapoi,​ OUTPUT); +
-    pinMode(motor2Inainte,​ OUTPUT); +
-    pinMode(motor2Inapoi,​ OUTPUT); +
-   +
-    pinMode(motor3Inainte,​ OUTPUT); +
-    pinMode(motor3Inapoi,​ OUTPUT); +
-    pinMode(motor4Inainte,​ OUTPUT); +
-    pinMode(motor4Inapoi,​ OUTPUT); +
-   +
-    pinMode(13, OUTPUT); +
-    pinMode(12, OUTPUT); +
-    pinMode(6, OUTPUT); +
-    pinMode(7, OUTPUT); +
-   +
-    pinMode(buzzer,​ OUTPUT); +
-    pinMode(led1,​ OUTPUT); +
-    pinMode(led2,​ OUTPUT); +
-  } +
-   +
-  void loop() { +
-    analogWrite(13,​ 150); +
-    analogWrite(12,​ 150); +
-    analogWrite(6,​ 150); +
-    analogWrite(7,​ 150); +
-   +
-    unsigned long currentMillis = millis(); +
-   +
-    if (currentMillis - previousMillis >= interval) { +
-      previousMillis = currentMillis;​ +
-       +
-      buzzerState = !buzzerState;​ +
-      ledState = !ledState;​ +
-       +
-      if (buzzerState) { +
-        tone(buzzer,​ 100); +
-      } else { +
-        noTone(buzzer);​ +
-      } +
-       +
-      digitalWrite(led1,​ ledState);​ +
-      digitalWrite(led2,​ ledState);​ +
-    } +
-   +
-    if (radio.available()) { +
-      char text[32] = "";​ +
-      radio.read(&​text,​ sizeof(text));​ +
-      Serial.println(text);​ +
-   +
-      if(strcmp(text,​ fata) == 0){ +
-        digitalWrite(motor1Inainte,​ LOW); +
-        digitalWrite(motor1Inapoi,​ HIGH); +
-        digitalWrite(motor2Inainte,​ LOW); +
-        digitalWrite(motor2Inapoi,​ HIGH); +
-        digitalWrite(motor3Inainte,​ HIGH); +
-        digitalWrite(motor3Inapoi,​ LOW); +
-        digitalWrite(motor4Inainte,​ HIGH); +
-        digitalWrite(motor4Inapoi,​ LOW); +
-        delay(500);​ +
-      } +
-   +
-      if(strcmp(text,​ spate) == 0){ +
-        digitalWrite(motor1Inainte,​ HIGH); +
-        digitalWrite(motor1Inapoi,​ LOW); +
-        digitalWrite(motor2Inainte,​ HIGH); +
-        digitalWrite(motor2Inapoi,​ LOW); +
-        digitalWrite(motor3Inainte,​ LOW); +
-        digitalWrite(motor3Inapoi,​ HIGH); +
-        digitalWrite(motor4Inainte,​ LOW); +
-        digitalWrite(motor4Inapoi,​ HIGH); +
-        delay(500);​ +
-      } +
-   +
-      if(strcmp(text,​ stanga) == 0){ +
-        digitalWrite(motor1Inainte,​ LOW); +
-        digitalWrite(motor1Inapoi,​ HIGH); +
-        digitalWrite(motor2Inainte,​ HIGH); +
-        digitalWrite(motor2Inapoi,​ LOW); +
-        digitalWrite(motor3Inainte,​ HIGH); +
-        digitalWrite(motor3Inapoi,​ LOW); +
-        digitalWrite(motor4Inainte,​ LOW); +
-        digitalWrite(motor4Inapoi,​ HIGH); +
-        delay(500);​ +
-      } +
-   +
-      if(strcmp(text,​ dreapta) == 0){ +
-        digitalWrite(motor1Inainte,​ HIGH); +
-        digitalWrite(motor1Inapoi,​ LOW); +
-        digitalWrite(motor2Inainte,​ LOW); +
-        digitalWrite(motor2Inapoi,​ HIGH); +
-        digitalWrite(motor3Inainte,​ LOW); +
-        digitalWrite(motor3Inapoi,​ HIGH); +
-        digitalWrite(motor4Inainte,​ HIGH); +
-        digitalWrite(motor4Inapoi,​ LOW); +
-        delay(500);​ +
-      } +
-   +
-      if(strcmp(text,​ fataStanga) == 0){ +
-        digitalWrite(motor1Inainte,​ LOW); +
-        digitalWrite(motor1Inapoi,​ HIGH); +
-        digitalWrite(motor2Inainte,​ LOW); +
-        digitalWrite(motor2Inapoi,​ LOW); +
-        digitalWrite(motor3Inainte,​ HIGH); +
-        digitalWrite(motor3Inapoi,​ LOW); +
-        digitalWrite(motor4Inainte,​ LOW); +
-        digitalWrite(motor4Inapoi,​ LOW); +
-        delay(500);​ +
-      } +
-   +
-      if(strcmp(text,​ fataDreapta) == 0){ +
-        digitalWrite(motor1Inainte,​ LOW); +
-        digitalWrite(motor1Inapoi,​ LOW); +
-        digitalWrite(motor2Inainte,​ LOW); +
-        digitalWrite(motor2Inapoi,​ HIGH); +
-        digitalWrite(motor3Inainte,​ LOW); +
-        digitalWrite(motor3Inapoi,​ LOW); +
-        digitalWrite(motor4Inainte,​ HIGH); +
-        digitalWrite(motor4Inapoi,​ LOW); +
-        delay(500);​ +
-      } +
-   +
-      if(strcmp(text,​ spateStanga) == 0){ +
-        digitalWrite(motor1Inainte,​ LOW); +
-        digitalWrite(motor1Inapoi,​ LOW); +
-        digitalWrite(motor2Inainte,​ HIGH); +
-        digitalWrite(motor2Inapoi,​ LOW); +
-        digitalWrite(motor3Inainte,​ LOW); +
-        digitalWrite(motor3Inapoi,​ LOW); +
-        digitalWrite(motor4Inainte,​ LOW); +
-        digitalWrite(motor4Inapoi,​ HIGH); +
-        delay(500);​ +
-      } +
-   +
-      if(strcmp(text,​ spateDreapta) == 0){ +
-        digitalWrite(motor1Inainte,​ HIGH); +
-        digitalWrite(motor1Inapoi,​ LOW); +
-        digitalWrite(motor2Inainte,​ LOW); +
-        digitalWrite(motor2Inapoi,​ LOW); +
-        digitalWrite(motor3Inainte,​ LOW); +
-        digitalWrite(motor3Inapoi,​ HIGH); +
-        digitalWrite(motor4Inainte,​ LOW); +
-        digitalWrite(motor4Inapoi,​ LOW); +
-        delay(500);​ +
-      } +
-   +
-      if(strcmp(text,​ rotireStanga) == 0){ +
-        digitalWrite(motor1Inainte,​ LOW); +
-        digitalWrite(motor1Inapoi,​ HIGH); +
-        digitalWrite(motor2Inainte,​ HIGH); +
-        digitalWrite(motor2Inapoi,​ LOW); +
-        digitalWrite(motor3Inainte,​ LOW); +
-        digitalWrite(motor3Inapoi,​ HIGH); +
-        digitalWrite(motor4Inainte,​ HIGH); +
-        digitalWrite(motor4Inapoi,​ LOW); +
-        delay(500);​ +
-      } +
-   +
-      if(strcmp(text,​ rotireDreapta) == 0){ +
-        digitalWrite(motor1Inainte,​ HIGH); +
-        digitalWrite(motor1Inapoi,​ LOW); +
-        digitalWrite(motor2Inainte,​ LOW); +
-        digitalWrite(motor2Inapoi,​ HIGH); +
-        digitalWrite(motor3Inainte,​ HIGH); +
-        digitalWrite(motor3Inapoi,​ LOW); +
-        digitalWrite(motor4Inainte,​ LOW); +
-        digitalWrite(motor4Inapoi,​ HIGH); +
-        delay(500);​ +
-      } +
-    } +
-   +
-    if (!radio.available()) { +
-      digitalWrite(motor1Inainte,​ LOW); +
-      digitalWrite(motor1Inapoi,​ LOW); +
-      digitalWrite(motor2Inainte,​ LOW); +
-      digitalWrite(motor2Inapoi,​ LOW); +
-      digitalWrite(motor3Inainte,​ LOW); +
-      digitalWrite(motor3Inapoi,​ LOW); +
-      digitalWrite(motor4Inainte,​ LOW); +
-      digitalWrite(motor4Inapoi,​ LOW); +
-    } +
-  }+
  
 +Setup:
 +  * Se initializeaza comunicatia seriala pentru debugging la o viteza de 9600 bps.
 +  * Se initializeaza modulul radio si se configureaza pentru scrierea datelor la adresa specificata.
 +  * Se seteaza nivelul de putere al modulului radio si se opreste ascultarea (receptia) pentru a permite transmiterea datelor.
 +
 +Loop:
 +  * In bucla principala, se citesc valorile analogice de la pinii definiti (A0-A7) care corespund directiilor de control: fata, spate, stanga, dreapta, fataStanga, fataDreapta,​ spateStanga,​ spateDreapta.
 +  * Daca valorile citite depasesc un anumit prag (1015), se trimite o comanda specifica prin intermediul modulului radio. Comenzile posibile sunt: "​fata",​ "​spate",​ "​stanga",​ "​dreapta",​ "fata stanga",​ "fata dreapta",​ "spate stanga",​ "spate dreapta"​.
 +  * In plus, se citesc valorile digitale de la pinii 2 si 3 pentru rotatia stanga si dreapta. Daca aceste butoane sunt apasate (valoare HIGH), se trimite comanda corespunzatoare.
 +  * Dupa fiecare comanda trimisa, exista o intarziere de 500 ms pentru a preveni trimiterea continua de comenzi si pentru a oferi un timp de raspuns adecvat.
 +
 +Functia '​comanda':​
 +  * Aceasta functie construieste un mesaj de 32 de caractere, care contine comanda de transmisie. Mesajul este transmis folosind functia radio.write prin intermediul modulului RF24.
  
-===== Rezultate ObÅ£inute ===== 
  
 <note tip> <note tip>
-Care au fost rezultatele obÅ£inute în urma realizării proiectului vostru.+__**In codul pentru telecomanda am folosit urmatoarele concepte:​**__ 
 + 
 +  * **SPI**: Utilizat pentru comunicarea cu modulul RF24 pentru transmisie wireless. 
 + 
 +  * **GPIO**: Utilizat pentru citirea starii pinilor digitali (rotireStanga si rotireDreapta). 
 + 
 +  * **ADC**: Utilizat pentru citirea valorilor analogice de la pinii A0-A7 (fata, spate, stanga, dreapta, etc.). 
 + 
 +  * **UART**: Utilizat pentru comunicarea seriala pentru debug (comunicare cu monitorul serial). 
 </​note>​ </​note>​
  
-===== Concluzii ===== 
  
-===== Download =====+**__Masina:​__**
  
-<note warning> +Initializare:​ 
-O arhivă ​(sau mai multe dacă este cazulcu fiÅŸierele obÅ£inute în urma realizării proiectului:​ surseschemeetc. Un fiÅŸier READMEun ChangeLogun script de compilare ÅŸi copiere automată ​pe uC crează întotdeauna o impresie bună ;-).+  * SPI.h, nRF24L01.h, RF24.h sunt incluse pentru a permite comunicarea SPI si utilizarea modulului RF24. 
 +  * Se definesc pinii de control pentru motoare ​(inainte si inapoi pentru fiecare din cele 4 motoare). 
 +  * Se definesc comenzile posibile (fataspatestangadreaptaetc.). 
 +  * Se definesc pinii pentru buzzer si LED-uri. 
 +  * Se initializeaza modulul RF24 pe pinii 2 si 53 si se seteaza adresa de citire. 
 +  * Pinii motoarelor, buzzer-ului si LED-urilor sunt setati ca iesiri.
  
-FiÅŸierele se încarcă pe wiki folosind facilitatea ​**Add Images or other files**. Namespace-ul în care se încarcă fiÅŸierele este de tipul **:​pm:​prj20??:​c?​** sau **:pm:​prj20??:​c?:​nume_student** (dacă este cazul). **Exemplu:** Dumitru Alin331CC -**:pm:prj2009:​cc:​dumitru_alin**.+Setup: 
 +  ​Se initializeaza comunicatia seriala. 
 +  ​Se initializeaza modulul RF24. 
 +  ​Se configureaza pinii de control ai celor 4 motoare ca iesiri. 
 +  ​Se configureaza pinii pentru controlul vitezei motoarelor si al buzzer-ului si LED-urilor ca iesiri. 
 + 
 + 
 +Loop: 
 +  * Seteaza viteza motoarelor prin iesirile PWM la un nivel constant (150 din 255). 
 +  * Schimba starea buzzer-ului si a LED-urilor la fiecare interval ​de milisecunde (3000 ms), creând un efect de intermitenta (1.5 secunde pornite, 1.5 secunde oprite). 
 +  ​Verifica daca exista date disponibile pe modulul radio. 
 +  ​Citeste mesajul primit si Il afiseaza pe monitorul serial. 
 +  ​In functie de mesajul primit (text), codul controleaza directia de miscare a motoarelor. Pentru fiecare comanda, se schimba starea pinilor corespunzatori motoarelor pentru a executa miscarea dorita (fata, spate, stanga, dreapta, etc.). 
 +  ​Daca nu exista comenzi disponibile,​ toate motoarele sunt oprite pentru a preveni miscarea accidentala. 
 + 
 +<note tip> 
 +__**In codul pentru masina am folosit urmatoarele concepte:**__ 
 + 
 +  * **SPI** (Serial Peripheral Interface): Utilizat pentru comunicarea cu modulul RF24 pentru receptia comenzilor wireless. 
 + 
 +  ​* **GPIO** (General Purpose Input/​Output):​ Utilizat pentru controlul motoarelor si a LED-urilor. Pinii motoarelor (ex. motor1Inaintemotor1Inapoi,​ etc.) si LED-urilor (led1, led2) sunt setati ca iesiri. 
 + 
 +  ​* **UART** (Universal Asynchronous Receiver-Transmitter)Utilizat pentru comunicarea seriala pentru debugging (comunicare cu monitorul serial). 
 + 
 +  * **Timere**Utilizat pentru a alterna starea buzzer-ului si a LED-urilor la fiecare 3 secunde. 
 + 
 +  ​* **PWM** (Pulse Width Modulation):​ Utilizat pentru a seta o valoare PWM pentru anumiti pinii (pentru controlul vitezei).
 </​note>​ </​note>​
  
 +===== Rezultate ObÅ£inute =====
 +
 +{{:​pm:​prj2024:​ccontasel:​masina_finala-removebg-preview.png?​500|}}
 +
 +{{:​pm:​prj2024:​ccontasel:​telecomanda_finala-removebg-preview_1_.png?​500|}}
 +
 +
 +<​html>​ <iframe width="​414"​ height="​896"​ src="​https://​www.youtube.com/​embed/​cTtHTLTAKH0"​ title="​Masina cu Telecomanda"​ frameborder="​0"​ allow="​accelerometer;​ autoplay; clipboard-write;​ encrypted-media;​ gyroscope; picture-in-picture;​ web-share"​ referrerpolicy="​strict-origin-when-cross-origin"​ allowfullscreen></​iframe>​ </​html>​
 +
 +===== Concluzii =====
 +
 +Am reusit sa realizez o masina cu telecomanda conform planului propus initial.
 +
 +**Indicatori de performanta:​**
 +  * Timpul dintre trimiterea unei comenzi de la telecomanda si executia acesteia de catre masina < 0.5 secunde.
 +  * Rata de succes a transmiterii si receptiei comenzilor prin modulul RF24 este de 100%.
 +  * Motoarele functioneaza la viteza dorita si mentin o performanta consistenta in timp.
 +  * Nu exista miscare accidentala sau nedorita a masinii cand aceasta nu primeste comenzi.
 +  * Corectitudinea si consistenta functionarii buzzer-ului si LED-urilor.
 +
 +**Optimizari pe care le-as putea adauga:**
 +  * Atasarea motoarelor in alt mod pe masina.
 +  * Folosirea a mai putinor baterii (eu am ales sa folosesc mai multe si pentru a adauga greutate masinii pentru aderenta).
 +
 +===== Download =====
 +
 +{{:​pm:​prj2024:​ccontasel:​pm_project.zip|}}
 ===== Jurnal ===== ===== Jurnal =====
  
Line 509: Line 254:
   * 16 mai - proiectare scheme electrice (telecomanda+masina)   * 16 mai - proiectare scheme electrice (telecomanda+masina)
   * 13-16 mai - am implementat si modificat codul in paralel cu realizarea componentelor fizice   * 13-16 mai - am implementat si modificat codul in paralel cu realizarea componentelor fizice
 +  * 23 mai - realizare caroserie masina
  
 </​note>​ </​note>​
  
-{{:​pm:​prj2024:​ccontasel:​image_2024-05-16_234616323.png?500|}}+{{:​pm:​prj2024:​ccontasel:​image_2024-05-24_033722137.png?500|}}
 ===== Bibliografie/​Resurse ===== ===== Bibliografie/​Resurse =====
  
pm/prj2024/ccontasel/raluca.movileanu.1715933512.txt.gz · Last modified: 2024/05/17 11:11 by ana_maria.diaconu02
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0