Witam na mojej stronie

Nazywam się Tomasz Rymiorz

Mój najnowszy projekt to przeróbka robota Robosapien firmy WowWee.
I to głównie na tym będę się koncentrować w dalszej części strony.

Robosapien Wi-Fi

Robosapien

Technologia bezustannie gna do przodu i to, co było nowinką techniczną wczoraj, dziś może być już bezużytecznym starociem, który nikogo nie jest w stanie zainteresować. Nie inaczej jest z interaktywnymi zabawkami, które nie nadążają za obecną technologią. Robosapien firmy WowWee oryginalnie był sterowany pilotem na podczerwień. W dobie Internetu Rzeczy zabawka bez dostępu do sieci nie ma prawa istnieć.
W ramach pracy dyplomowej rozbudowałem robota o układ zgodny z Arduino bazujący na mikrokontrolerze ESP8266 oraz napisałem aplikacje dla systemów Android oraz iOS sterującą robotem poprzez sieć Wi-Fi.

W swojej pracy wykorzystałem:
Arduino, Android Studio, XCode, REST, PHP, MySQL



Modyfikacja robota

Modyfikacja robota polegała na dodaniu do niego układu WeMos D1 mini, którego kompaktowe wymiary (zdjęcie 1) pozwalają na schowanie go wewnątrz obudowy robota. Oryginalne sterowanie Robosapien działało w oparciu o podczerwień, więc najprostszym sposobem na modyfikację, było wpięcie się do przewodu (biały) prowadzącego z odbiornika podczerwieni do układu logiki robota (zdjęcie 2) i symulowanie wysyłanych przez pilota sygnałów. Inspiracją do modyfikacji robota było rozwiązanie RoboSapienIR w serwisie The Arduino Playground. To stąd zaczerpnąłem najważniejszą funkcję odpowiedzialną za symulowanie sygnałów przesyłanych przez pilota. Jako, że wzorowałem się na tym rozwiązaniu, mój kod może być w wielu miejscach do niego podobny.

W Arduino wykorzystałem dwa piny, GPIO5 jako wejście sygnału z odbiornika podczerwieni i GPIO4 jako wyjście sygnału do układu robota. Arduino dzięki prostej funkcji przesyła właściwy kod do robota jakby pochodził on z pilota. Samo Arduino tuż po uruchomieniu łączy się z jedną z zaprogramowanych sieci Wi-Fi. Po połączeniu Arduino korzystając ze stworzonej dla robota usługi sieciowej (web service) wysyła swój adres IP, który został mu przydzielony oraz SSID sieci, z którą się połączył. Usługa sieciowa napisana w PHP działa w oparciu o wzorzec REST i zapisuje otrzymane dane do bazy MySQL, aby później aplikacja sterująca na smartfona mogła te dane pobrać i we właściwy sposób wykorzystać. W następnym kroku Arduino sam tworzy prostą usługę sieciową i od tego momentu oczekuje na komendy przesyłane mu za pomocą protokołu REST.

Układy logiki w Robosapien działają z napięciem 3,3V, które nie jest w stanie zasilić jednocześnie układu Arduino i mechanizmów robota, nic w tym momencie nie działa prawidłowo. Układ Arduino zasiliłem więc dwiema bateriami typu LR03. Nie chcąc robić otworów na dodatkowy włącznik dla Arduino wykorzystałem moduł wykonawczy z tranzystorem MOSFET IRF520 (zdjęcie 45). Zasilanie i sygnał sterujący modułem pobrałem z włącznika (zdjęcie 3), masę wziąłem z przewodu (czarny) wychodzącego ze złącza w górnej części układu robota (zdjęcie 2). Od teraz włączając robota, ten zasila moduł MOSFET, który z kolei steruje zasilaniem Arduino. Układ D1 mini umieściłem obok szyi robota, port USB wyprowadzając w kierunku do przodu (zdjęcie 6). Pod przednim pancerzem jest wystarczająco przestrzeni, aby zmieścić jednocześnie moduł MOSFET oraz dwie baterie zasilające.

Zdjęcie 1 Zdjęcie 2 Zdjęcie 3 Zdjęcie 4 Zdjęcie 5 Zdjęcie 6 Zdjęcie 7

Kod aplikacji sterującej robotem

Arduino

Pobierz szkic Arduino

lub podejrzyj cały kod na następnej stronie >>

Kod aplikacji sterującej robotem


#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <Wire.h>
#include <ESP8266HTTPClient.h>

ESP8266WiFiMulti wifiMulti;
WiFiServer server(80);
HTTPClient http;
WiFiClient wifi;

// Body
#define StepForward       0xA6
#define StepBackward      0xA7
#define StepTurnRight     0xA0
#define StepTurnLeft      0xA8
#define WalkForward       0x86
#define WalkBackward      0x87
#define TurnRight         0x80
#define TurnLeft          0x88
#define LeanForward       0xAD
#define LeanBackward      0xA5
#define TiltRight         0x83
#define TiltLeft          0x8B
#define Stop              0x8E

// Left Arm
#define LeftArmUp         0x89
#define LeftArmDown       0x8C
#define LeftArmOut        0x8A
#define LeftArmIn         0x8D
#define LeftHandThump     0xA9
#define LeftHandThrow     0xAA
#define LeftHandPickup    0xAC
#define LeftHandSweep     0xC9
#define LeftHandStrike1   0xCD
#define LeftHandStrike2   0xCB
#define LeftHandStrike3   0xC8

// Right Arm
#define RightArmUp        0x81
#define RightArmDown      0x84
#define RightArmOut       0x82
#define RightArmIn        0x85
#define RightHandThump    0xA1
#define RightHandThrow    0xA2
#define RightHandPickup   0xA4
#define RightHandSweep    0xC1
#define RightHandStrike1  0xC5
#define RightHandStrike2  0xC3
#define RightHandStrike3  0xC0

// Others
#define PowerOff          0xD1
#define Sleep             0xA3
#define WakeUp            0xB1
#define Burp              0xC2
#define High5             0xC4
#define Bulldozer         0xC6
#define Oops              0xC7
#define Whistle           0xCA
#define TalkBack          0xCC
#define Roar              0xCE
#define AllDemo           0xD0
#define KarateSkits       0xD2
#define RudeSkits         0xD3
#define Dance             0xD4

#define NoOp              0xEF

int irIn = 5;
int irOut = 4;

volatile int robotBit = 9;
volatile int robotCommand;
boolean robotUsed = false;


void setup() {
  Serial.begin(9600);
  pinMode(irIn, INPUT);
  pinMode(irOut, OUTPUT);
  digitalWrite(irOut, HIGH);
  attachInterrupt(0, readCommand, RISING);
  robotCommand = NoOp;

  Serial.println("");
  Serial.println("Initiation Wi-Fi");
  if (initiatingWifi()) {
    Serial.println(" Wi-Fi initiation completed");
    sendAdressToServer();
  }
}

void loop() {
  robotLoop();
  restLoop();
}


boolean initiatingWifi() {
  wifiMulti.addAP("LOGIN", "PASSWORD");
  wifiMulti.addAP("LOGIN", "PASSWORD");
  wifiMulti.addAP("LOGIN", "PASSWORD");

  Serial.print(" Connecting to the AP ");
  while (wifiMulti.run() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  Serial.println("");
  Serial.println("  Connected to Wi-Fi " + WiFi.SSID());

  Serial.println(" Server startup");
  server.begin();
  Serial.println("  Arduino REST server was started");

  return (WiFi.status() == WL_CONNECTED);
}

void sendAdressToServer() {
  Serial.println("Sending an address to the server");
  String url = "http://chicken.net.pl/toys/";
  String values = "username=LOGIN&password=PASSWORD&dbname=DATABASE&table=robosapien&wifissid=" + WiFi.SSID() + "&address=" + WiFi.localIP().toString();
  String request = url + "?" + values;// + " HTTP/1.1";

  Serial.println(" " + request);
  http.begin(request);
  http.addHeader("Accept", "application/json, text/plain, */*");
  http.addHeader("Content-Type", "application/json;charset=utf-8");
  http.POST(request);
  Serial.println(" Data sent");
  Serial.print("  ");
  http.writeToStream(&Serial);
  Serial.println(" locations in the database");
  http.end();
}


void robotLoop() {
  if (!robotUsed && robotCommand != NoOp) {
    sendCommand(robotCommand);
    robotCommand = NoOp;
  }
}

void readCommand() {
  delayMicroseconds(833 + 208);
  int bit = digitalRead(irIn);

  if (robotBit == 9) {
    robotCommand = 0;
    robotBit = 0;
    robotUsed = true;
  }
  if (robotBit < 8) {
    robotCommand <<= 1;
    robotCommand |= bit;
  }
  robotBit++;
  if (robotBit == 9) robotUsed = false;
}

void sendCommand(int command) {
  robotUsed = true;
  digitalWrite(irOut, LOW);

  delayMicroseconds(8 * 833);
  for (int i = 0; i < 8; i++) {
    digitalWrite(irOut, HIGH);
    delayMicroseconds(833);
    if ((command & 128) != 0) delayMicroseconds(3 * 833);
    digitalWrite(irOut, LOW);
    delayMicroseconds(833);
    command <<= 1;
  }

  digitalWrite(irOut, HIGH);
  delay(250);
  robotUsed = false;
}

int bodyCommand(String request) {
  if (request.indexOf("/stepforward") != -1) {
    wifi.print(getFullResponse("I execute the command StepForward"));
    return StepForward;
  }
  else if (request.indexOf("/stepbackward") != -1) {
    wifi.print(getFullResponse("I execute the command StepBackward"));
    return StepBackward;
  }
  else if (request.indexOf("/stepturnright") != -1) {
    wifi.print(getFullResponse("I execute the command StepTurnRight"));
    return StepTurnRight;
  }
  else if (request.indexOf("/stepturnleft") != -1) {
    wifi.print(getFullResponse("I execute the command StepTurnLeft"));
    return StepTurnLeft;
  }
  else if (request.indexOf("/walkforward") != -1) {
    wifi.print(getFullResponse("I execute the command WalkForward"));
    return WalkForward;
  }
  else if (request.indexOf("/walkbackward") != -1) {
    wifi.print(getFullResponse("I execute the command WalkBackward"));
    return WalkBackward;
  }
  else if (request.indexOf("/turnright") != -1) {
    wifi.print(getFullResponse("I execute the command TurnRight"));
    return TurnRight;
  }
  else if (request.indexOf("/turnleft") != -1) {
    wifi.print(getFullResponse("I execute the command TurnLeft"));
    return TurnLeft;
  }
  else if (request.indexOf("/leanforward") != -1) {
    wifi.print(getFullResponse("I execute the command LeanForward"));
    return LeanForward;
  }
  else if (request.indexOf("/leanbackward") != -1) {
    wifi.print(getFullResponse("I execute the command LeanBackward"));
    return LeanBackward;
  }
  else if (request.indexOf("/tiltright") != -1) {
    wifi.print(getFullResponse("I execute the command TiltRight"));
    return TiltRight;
  }
  else if (request.indexOf("/tiltleft") != -1) {
    wifi.print(getFullResponse("I execute the command TiltLeft"));
    return TiltLeft;
  }
  else if (request.indexOf("/stop") != -1) {
    wifi.print(getFullResponse("I execute the command Stop"));
    return Stop;
  }
  else {
    wifi.print(getFullResponse("invalid request"));
    return NoOp;
  }
}

int leftHandCommand(String request) {
  if (request.indexOf("/armup") != -1) {
    wifi.print(getFullResponse("I execute the command LeftArmUp"));
    return LeftArmUp;
  }
  else if (request.indexOf("/armdown") != -1) {
    wifi.print(getFullResponse("I execute the command LeftArmDown"));
    return LeftArmDown;
  }
  else if (request.indexOf("/armout") != -1) {
    wifi.print(getFullResponse("I execute the command LeftArmOut"));
    return LeftArmOut;
  }
  else if (request.indexOf("/armin") != -1) {
    wifi.print(getFullResponse("I execute the command LeftArmIn"));
    return LeftArmIn;
  }
  else if (request.indexOf("/handthump") != -1) {
    wifi.print(getFullResponse("I execute the command LeftHandThump"));
    return LeftHandThump;
  }
  else if (request.indexOf("/handthrow") != -1) {
    wifi.print(getFullResponse("I execute the command LeftHandThrow"));
    return LeftHandThrow;
  }
  else if (request.indexOf("/handpickup") != -1) {
    wifi.print(getFullResponse("I execute the command LeftHandPickup"));
    return LeftHandPickup;
  }
  else if (request.indexOf("/handsweep") != -1) {
    wifi.print(getFullResponse("I execute the command LeftHandSweep"));
    return LeftHandSweep;
  }
  else if (request.indexOf("/handstrike1") != -1) {
    wifi.print(getFullResponse("I execute the command LeftHandStrike1"));
    return LeftHandStrike1;
  }
  else if (request.indexOf("/handstrike2") != -1) {
    wifi.print(getFullResponse("I execute the command LeftHandStrike2"));
    return LeftHandStrike2;
  }
  else if (request.indexOf("/handstrike3") != -1) {
    wifi.print(getFullResponse("I execute the command LeftHandStrike3"));
    return LeftHandStrike3;
  }
  else {
    wifi.print(getFullResponse("invalid request"));
    return NoOp;
  }
}

int rightHandCommand(String request) {
  if (request.indexOf("/armup") != -1) {
    wifi.print(getFullResponse("I execute the command RightArmUp"));
    return RightArmUp;
  }
  else if (request.indexOf("/armdown") != -1) {
    wifi.print(getFullResponse("I execute the command RightArmDown"));
    return RightArmDown;
  }
  else if (request.indexOf("/armout") != -1) {
    wifi.print(getFullResponse("I execute the command RightArmOut"));
    return RightArmOut;
  }
  else if (request.indexOf("/armin") != -1) {
    wifi.print(getFullResponse("I execute the command RightArmIn"));
    return RightArmIn;
  }
  else if (request.indexOf("/handthump") != -1) {
    wifi.print(getFullResponse("I execute the command RightHandThump"));
    return RightHandThump;
  }
  else if (request.indexOf("/handthrow") != -1) {
    wifi.print(getFullResponse("I execute the command RightHandThrow"));
    return RightHandThrow;
  }
  else if (request.indexOf("/handpickup") != -1) {
    wifi.print(getFullResponse("I execute the command RightHandPickup"));
    return RightHandPickup;
  }
  else if (request.indexOf("/handsweep") != -1) {
    wifi.print(getFullResponse("I execute the command RightHandSweep"));
    return RightHandSweep;
  }
  else if (request.indexOf("/handstrike1") != -1) {
    wifi.print(getFullResponse("I execute the command RightHandStrike1"));
    return RightHandStrike1;
  }
  else if (request.indexOf("/handstrike2") != -1) {
    wifi.print(getFullResponse("I execute the command RightHandStrike2"));
    return RightHandStrike2;
  }
  else if (request.indexOf("/handstrike3") != -1) {
    wifi.print(getFullResponse("I execute the command RightHandStrike3"));
    return RightHandStrike3;
  }
  else {
    wifi.print(getFullResponse("invalid request"));
    return NoOp;
  }
}

int programmedCommand(String request) {
  if (request.indexOf("/poweroff") != -1) {
    wifi.print(getFullResponse("I execute the command PowerOff"));
    return PowerOff;
  }
  else if (request.indexOf("/sleep") != -1) {
    wifi.print(getFullResponse("I execute the command Sleep"));
    return Sleep;
  }
  else if (request.indexOf("/wakeup") != -1) {
    wifi.print(getFullResponse("I execute the command WakeUp"));
    return WakeUp;
  }
  else if (request.indexOf("/burp") != -1) {
    wifi.print(getFullResponse("I execute the command Burp"));
    return Burp;
  }
  else if (request.indexOf("/high5") != -1) {
    wifi.print(getFullResponse("I execute the command High5"));
    return High5;
  }
  else if (request.indexOf("/bulldozer") != -1) {
    wifi.print(getFullResponse("I execute the command Bulldozer"));
    return Bulldozer;
  }
  else if (request.indexOf("/oops") != -1) {
    wifi.print(getFullResponse("I execute the command Oops"));
    return Oops;
  }
  else if (request.indexOf("/whistle") != -1) {
    wifi.print(getFullResponse("I execute the command Whistle"));
    return Whistle;
  }
  else if (request.indexOf("/talkback") != -1) {
    wifi.print(getFullResponse("I execute the command TalkBack"));
    return TalkBack;
  }
  else if (request.indexOf("/roar") != -1) {
    wifi.print(getFullResponse("I execute the command Roar"));
    return Roar;
  }
  else if (request.indexOf("/alldemo") != -1) {
    wifi.print(getFullResponse("I execute the command AllDemo"));
    return AllDemo;
  }
  else if (request.indexOf("/karateskits") != -1) {
    wifi.print(getFullResponse("I execute the command KarateSkits"));
    return KarateSkits;
  }
  else if (request.indexOf("/rudeskits") != -1) {
    wifi.print(getFullResponse("I execute the command RudeSkits"));
    return RudeSkits;
  }
  else if (request.indexOf("/dance") != -1) {
    wifi.print(getFullResponse("I execute the command Dance"));
    return Dance;
  }
  else {
    wifi.print(getFullResponse("invalid request"));
    return NoOp;
  }
}

void restLoop() {
  wifi = server.available();

  if (wifi) {
    while (!wifi.available()) {
      delay(1);
    }

    String request = wifi.readStringUntil('\r');
    wifi.flush();

    if (request.indexOf("/body") != -1) {
      robotCommand = bodyCommand(request);
    }
    else if (request.indexOf("/left") != -1) {
      robotCommand = leftHandCommand(request);
    }
    else if (request.indexOf("/right") != -1) {
      robotCommand = rightHandCommand(request);
    }
    else if (request.indexOf("/program") != -1) {
      robotCommand = programmedCommand(request);
    }
    else {
      wifi.print(getFullResponse("invalid request"));
      robotCommand = NoOp;
    }

    wifi.flush();
    delay(1);
  }
}

String getFullResponse(String request) {
  String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n\r\n<html>\r\n";
  s += request;
  s += "</html>\n";

  return s;
}
					

Sterowanie robotem

Aby sterować zmodyfikowanym Robosapien wystarczy znać jego adres IP, który został przyznany robotowi przez router oraz być połączonym do tej samej sieci Wi-Fi. Do samego sterowania nie jest wymagana jakakolwiek aplikacja, same polecenia do robota są przesyłane za pomocą protokołu REST. Znając jego adres i składnię komend, przy pomocy dowolnej strony oferującej tworzenie zapytań REST możemy wysłać polecenia do robota. Linia komend została podzielona na cztery fragmenty: body, left, right i program, a każdy z nich odpowiada innemu rodzajowi czynności i obsługuje sobie właściwe komendy.

I tak „body” odnosi się do ciała, mamy tam: walkforward, walkbackward, turnleft, turnright oraz stop.

Części „left” i „right” to ramiona robota obsługujące komendy: armup, armdown, armout, armin, handthump, handthrow, handpickup, handsweep, handstrike1, handstrike2 oraz handstrike3.

Natomiast „program” odnosi się do poleceń ogólnych: poweroff, sleep, wakeup, burp, high5, bulldozer, oops, whistle, talkback, roar, alldemo, karateskits, rudeskits i dance.

Przykładowo:
POST http://192.168.1.101/body/walkforward
POST http://192.168.1.101/left/armup



Napisałem dwie aplikacje sterujące robotem. Podstawowa aplikacja powstała dla systemu Android, natomiast aplikacja dla iOS została napisana w ramach zajęć programowania aplikacji mobilnych w Objective-C. Obie aplikacje są podobne wizualnie, a komendy wybieramy z rozwijanej listy. W aplikacji iOS sterowanie odbywa się za pomocą strzałek, a w aplikacji na Androida ruchem robota sterujemy przy pomocy joysticka.

Aplikacja na Androida

Aplikacja posiada dość prosty obrazkowy interfejs (zdjęcie 1), a także menu (zdjęcie 2), w którym możemy podejrzeć lokalizację robota i w razie konieczności ją odświeżyć, jak również w przypadku chęci korzystania ze słuchawki Bluetooth jest opcja wybrania domyślnej słuchawki, która w chwili połączenia z telefonem będzie aktywować sterowanie głosowe robotem. Z poziomu aplikacji jest również możliwość szybkiego uruchomienia sieci Wi-Fi oraz Bluetooth.

Rozpoznawanie mowy i komunikacja Bluetooth

Na potrzeby swojej aplikacji znalazłem rozwiązanie Continues Voice Recognition, wykorzystujące system rozpoznawania mowy w systemie Android. Aplikacja bezustannie nasłuchuje otoczenia, a gdy po wypowiedzeniu zdania następuje przerwa w wypowiedzi, system wie, że nastąpił koniec i przystępuje do tłumaczenia. Po zwróceniu wyniku, aplikacja dalej nasłuchuje dźwięków z otoczenia. Rozpoznawanie mowy działa dobrze jeśli telefon nas słyszy, jednak odłożony na półkę nie będzie prawidłowo wychwytywał poleceń głosowych. Aby temu zaradzić wykorzystałem technologię bezprzewodową Bluetooth. Aplikacja włącza rozpoznawanie mowy po wykryciu połączenia ze słuchawką Bluetooth. Użytkownik musi jedynie wcześniej wybrać swoją słuchawkę. System sterowania głosem nie wymaga stosowania konkretnie sformułowanych komend. Został stworzony, aby wyszukiwać komendy w rozpoznanym tekście. Przykładowo, tekst „robot, zrób krok do przodu” zostanie rozpoznany tak samo jak tekst „krok do przodu”, a tekst „robot, unieś lewą rękę w górę” jest równoznaczny z komendą „lewa w górę”. Zależało mi, aby ton wypowiadanych komend był jak najbardziej naturalny.

Do stworzenia aplikacji na Androida korzystałem z:
Android Studio, HttpURLConnection Tutorial, JoyStick, ContinuesVoiceRecognition.

Zdjęcie 1 Zdjęcie 2

Robosapien Wi-Fi w praktyce

Pierwszy test oprogramowania Arduino. Robot połączony z układem ArduCAM zasilany baterią 9V.

Test ostatecznej wersji robota. Prezentacja całości z wbudowanym układem WeMos D1 mini, modułem MOSFET IRF520 oraz zasilaniem 2xLR03.

Filmy nagrywane aplikacją Apowersoft Screen Recorder.



O mnie i tej stronie

Nazywam się Tomasz Rymiorz.
Studiuję Aplikacje mobilne na kierunku Informatyka w Wyższej Szkole Biznesu w Dąbrowie Górniczej.
Przygodę z programowaniem zacząłem w Borland Delphi, które do teraz uważam za jedno z lepszych środowisk programistycznych. Hobbystycznie również tworzyłem strony internetowe ze szczególnym upodobaniem technologii Adobe Flash. Obecnie programuję i rozwijam się w środowiskach Android Studio oraz Arduino. Aplikacje mobilne i Internet Rzeczy to bodajże najbardziej rozwijające się obecnie technologie, dające sporo możliwości i jeszcze więcej satysfakcji. Jakkolwiek w dalszym ciągu lubię tworzyć strony, czego ta tutaj jest doskonałym przykładem.
Znam środowiska Delphi, Visual Studio, Arduino, Android Studio, XCode, Adobe Flash.
Programowałem w językach Object Pascal, C/C++, HTML, PHP, ActionScript, Java, Objective-C.

Strona zbudowana na fullPage.js;
Do kolorowania składni kodu Arduino użyto Prism;
Kontakt ze mną poprzez e-mail;



Aplikacje desktopowe

TotalCommander Portable >> Pobierz
Program uruchomieniowy dla TotalCommandera. Żadna ze znalezionych przeze mnie wersji nie chciała działać bez ingerowania w pliki ustawień właściciela komputera. Moja wersja zmusza TotalCommandera do korzystania z ustawień przyniesionych wraz z programem.
Stworzone dla TotalCommandera w wersji 7. Używam tego do dnia dzisiejszego.


OX >> Pobierz
Moja pierwsza aplikacja, gra kółko-krzyżyk.


spis7 >> Pobierz
To zwieńczenie moich prac nad programem katalogującym, wersja piąta, na chwilę obecną ostateczna. Jest szybki, prosty, intuicyjny i dobrze wygląda. Można w nim katalogować m.in. filmy, gry, książki. Potrafi dużo i robi to elegancko. Dopracowany w najdrobniejszych szczegółach, pozwala w przejrzysty sposób zebrać informacje o zbiorach multimedialnych w jednym miejscu.
- Program daje możliwość zabezpieczenia zakładek hasłem.
- Opcja pożyczek wraz z przypominaniem.
- Opisy są przejrzyste i dynamicznie generowane w kodzie HTML.
- Proste, a zarazem zaawansowane szukanie i filtrowanie pozycji.
- Przenoszenie pozycji między zakładkami.
- Możliwość przeciągania tekstów i obrazków z przeglądarki.
- Automatyczne odczytywanie informacji z plików wideo.
Program od Windows 8 przestał się uruchamiać. Nie mam wszystkich plików źródłowych, by usunąć problem i skompilować program na nowo.

Zdjęcie 1 Zdjęcie 2 Zdjęcie 3 Zdjęcie 4 Zdjęcie 5

Starsze wersje programu katalogującego

Spis 2 >> Pobierz
Druga wersja mojego programu do katalogowania i pierwsza udostępniona publicznie. Pozbawiona jakichkolwiek opcji, pozwala jedynie na proste katalogowanie. Możliwość przypisania do czterech opisów do pozycji.

Zdjęcie 1 Zdjęcie 2

spis3 >> Pobierz
Trzecie wydanie, tym razem z opcjami zmiany ustawień i obsługą skórek. Bardziej zaawansowany od poprzednika, pozwala na szczegółowe opisy pozycji, które prezentuje w przejrzysty sposób, po raz pierwszy generowany w HTML. Ten program wytyczył kierunek, w którym podążałem z każdą następną wersją.

Zdjęcie 1 Zdjęcie 2

spis 2008 >> Pobierz
Kontynuacja koncepcji z programu spis3 oraz wyeliminowanie jego błędów. Największe zmiany to rezygnacja ze skórek i dostosowanie programu wizualnie do systemu. Sam program nabrał prędkości w działaniu jednocześnie zwiększając swoje możliwości, m.in. poprzez dodanie obrazków do pozycji.
Program od Windows 8 przestał się uruchamiać.

Zdjęcie 1 Zdjęcie 2


Projekty stron www

Zdjęcie 1

Rok 2005. Multimedialna Strefa. Cały projekt strony oparty został na tabelach. Na potrzeby tego serwisu stworzyłem program, który generował kod HTML po każdorazowym dodaniu nowego pliku. Podgląd kodu

Poprzednie strony domowe

Zdjęcie 1 Zdjęcie 2 Zdjęcie 3 Zdjęcie 4 Zdjęcie 5 2003r.
Zdjęcie 1 Zdjęcie 2 Zdjęcie 3 Zdjęcie 4 2003r.
Zdjęcie 1 Zdjęcie 2 Zdjęcie 3 Zdjęcie 4 2007r.
Zdjęcie 1 Zdjęcie 2 Zdjęcie 3 Zdjęcie 4 Zdjęcie 5 2015r.


Mapy do gier

Unreal Tournament >> Pobierz
Jest to przeróbka mapy Deck16. Usunąłem część świateł i dodałem latarki. Gra się całkiem przyjemnie, mapa w znacznym stopniu zmienia klimat rozgrywki.

Heroes of Might & Magic III >> Pobierz
Mapa "Oblicze świata", wymaga dodatku "The Shadow of Death".

StarCraft >> Pobierz
Zbiór czternastu moich najlepszych map.