The Aliens Legacy http://forum.alienslegacy.com/ |
|
updated raspberry pi setup http://forum.alienslegacy.com/viewtopic.php?f=3&t=18759 |
Page 1 of 1 |
Author: | knoxvilles_joker [ Sat May 09, 2020 5:34 am ] |
Post subject: | updated raspberry pi setup |
Sites and articles referenced writing this: https://bootlin.com/labs/doc/nunchuk.pdf https://learn.adafruit.com/16-channel-p ... ng-drivers https://computers.tutsplus.com/tutorial ... -cms-20984 https://www.raspberrypi.org/forums/view ... 44&t=98318 https://mcpeppr.wordpress.com/2015/02/0 ... is-broken/ https://pimylifeup.com/raspberry-pi-wii ... ntrollers/ https://raspberrypi.stackexchange.com/q ... g-wiringpi https://learn.adafruit.com/adafruit-16- ... cking-hats https://www.raspberrypi.org/forums/view ... p?t=135364 https://raspberrypi.stackexchange.com/q ... wont-start https://help.ubuntu.com/community/CWiiD https://hackaday.com/2019/05/13/wii-nun ... y-pi-zero/ https://www.raspberrypi.org/forums/view ... p?t=122260 viewtopic.php?f=3&t=17024&p=262942&hilit=shoulder+cannon#p262942 https://pythonbasics.org/python-play-sound/ https://my.eng.utah.edu/~cs5780/debouncing.pdf https://hackaday.com/2015/12/09/embed-w ... ns-part-i/ https://pythonforbiologists.com/printin ... ating-text https://www.python-course.eu/tkinter_text_widget.php https://realpython.com/python-print/ https://forums.envato.com/t/trying-to-c ... him/304683 https://www.kite.com/python/answers/how ... -in-python https://stackoverflow.com/questions/324 ... -time?lq=1 https://stackabuse.com/parallel-processing-in-python/ https://www.raspberrypi.org/forums/view ... p?t=195859 https://realpython.com/python-while-loop/ https://ray.io/ https://www.element14.com/community/thr ... hread=true https://keyboardinterrupt.org/catching- ... pt-signal/ https://stackoverflow.com/questions/306 ... ray-object https://learn.sparkfun.com/tutorials/i2c/all https://raspi.tv/2013/how-to-use-interr ... pio-part-2 https://github.com/adafruit/circuitpyth ... master.zip https://github.com/adafruit/Adafruit_Ci ... master.zip https://sourceforge.net/p/raspberry-gpi ... ki/Inputs/ viewtopic.php?f=3&t=17024&hilit=raspberry+predator+cannon&start=25 https://www.element14.com/community/thr ... hread=true https://www.amazon.com/Python-Programmi ... 154&sr=8-2 https://github.com/boppreh/keyboard/archive/master.zip To communicate with the Nunchuk, we must send a handshake signal. If you are using a black Wii Nunchuk, send 2 bytes 0xF0, 0x55 to initialize the first register and 0xFB, 0x00 to initialize the second register of the Nunchuk. On a white Wii Nunchuk, send 0x40, 0x00 followed by 0x00. The I2C address of both Wii Nunchucks is 0x52. The frequency used to communicate with the Wii Nunchuk is 100khz Source: https://pimylifeup.com/raspberry-pi-wii ... ntrollers/ OK now the base addresses of the wii nunchuck conflicts with the pca9685 bonnet. 0x40 is shared with the nunchuck. We are not able to change the address of the nunchuck so we have to change the address of the bonnet. In my case I bridged pin a2 to give it a base adress of 0x44. This solved the conflict. I would note that this is a big issue as when you have i2c addresses clash you will get no results when running i2cdetect -y 1. (older versions of the pi may have to use a zero instead of a 1.) Source: https://learn.adafruit.com/16-channel-p ... ng-drivers to setup the nunchuck just do these simple steps. run: sudo raspi-config under interfacing options select spi, seril, i2c and set them to on. DO NOT turn on 1-wire. (having 1-wire on breaks the pimoroni onoff shim from working (had a hell of a time finding out that one as the pimoroni forums are not exactly like most forums)) in raspi-config is network options and you can connect to wireless from there. If you get errors about wpa_supplicant you will have to run this command: sudo wpa_suppicant -c "/etc/wpa_supplicant/wpa_supplicant.conf" -iwlan0 -d If you are using outdated wireless settings you will have to add your network settings to wpa_supplicant.conf manually: with the following in that file: network={ ssid="networkname" psk="networkpassword" } Localisation options are where you set the keyboard and other country settings (timezone, wifi country, locale) Linux and keyboards can suck if you do not have the correct mapping and this is where you set it the easy way. to boot/config.txt add: dtparam=i2c_arm=on dtparam=spi=on dtparam=i2s=on to /etc/modprobe.d/rspi-blacklist.conf add: #blacklist spi-bcm2708 #blacklist i2-bcm2708 /usr/local/lib/python3.5/dist-packages/adafruit_pca9685.py <-- change ox40 to ox44 Now update the pi once you have it on the network: sudo apt-get update sudo apt-get upgrade -y sudo apt-get dist-upgrade -y sudo rpi-update sudo apt-get install python-cwiid sudo apt-get install wminput sudo apt-get install bluetooth <-- only needed if you have a very old raspberry pi sudo apt-get install i2c-tools sudo apt-get install python-smbus - sudo pip3 install adafruit-circuitpython-servokit sudo pip3 install --upgrade setuptools sudo apt-get install python3-pip pip3 install RPI.GPIO pip3 install adafruit-blinka <--failed? <-- use --upgrade switch to upgrade... pip3 install adafruit-circuitpython-bme280 sudo pip3 install adafruit-circuitpython-pca9685 sudo pip3 install adafruit-circuitpython-servokit sudo pip3 install adafruit-circuitpython-busdevice sudo pip3 install adafruit-circuitpython-register pip3 install adafruit-circuitpython-lis3dh sudo pip3 install adafruit-Blinka sudo pip3 install adafruit-circuitpython-motor sudo apt-get install python3-smbus sudo pip3 install pydub sudo pip3 install numpy sudo pip3 install keyboard sudo pip3 install pathlib sudo pip3 install rst2pyi sudo pip3 install gpiozero sudo pip install gpiozero sudo pip3 install RPI.GPIO sudo pip3 install --upgrade adafruit_blinka sudo pip3 install adafruit-circuitpython-max31855 sudo pip3 install adafruit-circuitpython-gps A word on libraries. libraries are like your public library. They are only as good as the amount of books that they have that YOU can use. Some books will be there by default, but other books you have to specifically request or donate/install at the library. each book when used will expand your ability to do things. Every distribution of a given utility be it python, mysql, php, www, etc, has a path variable and set of location(s) where functions/libraries are placed. Some utilities will have multiple versions installed or present and some of the previous versions will be symbolic links or symlinks to the latest version for compatibility with older untilities. The libraries are extensions or plug-ins for binaries and secured binaries (bin and sbin) processes/executables. the root directies of /bin and /sbin and /lib are for core system functionality. add-on utilities and things beyond core system functionality are located at /usr/local/bin/ , /usr/bin , /usr/sbin , /usr/local/sbin , /usr/lib , /usr/local/lib. User installed utilities and libraries are typically housed in /usr/local in sub folders there. But, the system configuration files and anything outside of those categories goes into /etc. logs are typically stored in /var. boot configuration files are stored in /boot. /boot is assessible on the sd card if you mount it on another computer and is a quick cheat to quickly move files to your raspberry pi if you have large files to move or do not want to hook it up to the internet for whatever reason or need. Knowing that most of your manual installs will get placed in one of those folders. In my case in this exploration of development I had to manually install the keyboard, debounce, nunchuck in /usr/local/lib/python3.5/dist-packages. This amounted mainly consisted of downloading the files as a zip from github, and unzipping them to the relevant folder. Now saying all that that information is handy to know as you are troubleshooting errors. the errors will literally point you to what is missing and then you have to research that module and how to invoke the install for it or ensure that it is registered and present on the system and recognized. In the CentOS/Redhat world these errors are referred to as dependency hell and it can be a very time consuming and frustrating exercise in patience to get all requirements met to make something work. That said make sure to liberally document all steps taken so you have some basis to later replicate your work. Simple run setup test of nunchuck. wget https://raw.githubusercontent.com/Boeee ... unchuck.py sudo python from nunchuck import nunchuck wii = nunchuck() wii.raw() wii raw will get you directional and accelerometer readings. source: https://computers.tutsplus.com/tutorial ... -cms-20984 Since you are running two i2c devices you will need push resisters on the SCL and SDA data lines. The nunchuck has additional pins you can use for this so you are going to be running a 6 wire harness. Due to resistance and physics it helps to keep all wires as close to the same length as possible. If you are running a nunchuck all by itself this should not be an issue. On the Pimoroni onoff shim if you need to not have it mounted just hook up these wires: 5v to 5v, gnd to a gnd. 3v3 to 3v3 for led. io#4 and #17 to the relevant pins. And make sure 1-wire interface is turned OFF. From Pimoroni Software: We've put together a one-line-installer to install the clean shutdown daemon. It watches the state of BCM pin 17 and, when pulled low (pressed), it initiates a clean shutdown. Last thing, just before your Pi shuts down, BCM pin 4 is pulled low to completely cut power to your Pi. To install the software, open a terminal and type curl https://get.pimoroni.com/onoffshim | bashto run the one-line-installer. source: https://shop.pimoroni.com/products/onoff-shim If you need to alter your scripts for startup and shutdown reference this article: https://retropie.org.uk/forum/topic/157 ... pimoroni/4 I have been chipping away at things and I just want to get some notes out there. At this point I am tracing down some nasty error codes in what we Linux geeks like to call dependency hell. You need this but you don't have that. You go to install that and this other thing is needed. You go to get this other thing and you need to install this thingamabob. You to go to install the thingamabob and the whachamawhooseit is needed. You go to look for the whachamawhooseit and realise you ran out of coffee, need to sleep and tray again from scratch. That is dependency hell. I try to take all the guess work out on the write ups I do so others that are less technical do not tear their hair out if they have any left to remove to start with... setting up the GPIO pin as an imput pin and in python "GPIO.setup(encoder_pin, GPIO.IN)" would be the same (not sure if there is a wired in pull up/down resistor in the circuit or you will need to setup to use the RPi internal 1). attachInterrupt is to configure the call back to call the counter function on a rising GPIO pin, python would use "GPIO.add_event_detect" Ok lets look at the callback function next (the counter function). Basically it only does 1 thing if all the debounce is correct then increment the global variable pulses. In python you will set all the debounce in when setting it up in the initialization "GPIO.add_event_detect" google it. So in python the counter function will only have 2 lines "global pulses" and "pulses +=1" https://www.raspberrypi.org/forums/view ... p?t=195859 You may notice that the callbacks are called more than once for each button press. This is as a result of what is known as 'switch bounce'. There are two ways of dealing with switch bounce: add a 0.1uF capacitor across your switch, software debouncing, or a combination of both To communicate with the Nunchuk, we must send a handshake signal. If you are using a black Wii Nunchuk, send 2 bytes 0xF0, 0x55 to initialize the first register and 0xFB, 0x00 to initialize the second register of the Nunchuk. On a white Wii Nunchuk, send 0x40, 0x00 followed by 0x00. The I2C address of both Wii Nunchucks is 0x52. The frequency used to communicate with the Wii Nunchuk is`100khz OK now the base addresses of the wii nunchuck conflicts with the pca9685 bonnet. 0x40 is shared with the nunchuck. We are not able to change the address of the nunchuck so we have to change the address of the bonnet. In my case I bridged pin a2 to give it a base adress of 0x44. This solved the conflict. I would note that this is a big issue as when you have i2c addresses clash you will get no results when running i2cdetect -y 1. (older versions of the pi may have to use a zero instead of a 1.) The wiinunchuck libs can run under python version 1. To run under python version3 you have to update smbus to python3. The pca9685 appears to only work when running under python version 3 or python3 command versus regulary python from the command line. I will have to rehash the old Arduino code to convert to a usable python script. At this point I am only focused on getting a working python script. I will worry about Daemonizing it later. to setup the nunchuck just do these simple steps. run: sudo raspi-config under interfacing options select spi, seril, i2c and set them to on. DO NOT turn on 1-wire. (having 1-wire on breaks the pimoroni onoff shim from working (had a hell of a time finding out that one as the pimoroni forums are not exactly like most forums)) in raspi-config is network options and you can connect to wireless from there. If you get errors about wpa_supplicant you will have to run this command: sudo wpa_suppicant -c "/etc/wpa_supplicant/wpa_supplicant.conf" -iwlan0 -d If you are using outdated wireless settings you will have to add your network settings to wpa_supplicant.conf manually: with the following in that file: network={ ssid="networkname" psk="networkpassword" } Localisation options are where you set the keyboard and other country settings (timezone, wifi country, locale) Linux and keyboards can suck if you do not have the correct mapping and this is where you set it the easy way. |
Author: | knoxvilles_joker [ Sun May 10, 2020 5:02 am ] |
Post subject: | |
OK, it is slowly coming together. This takes the x axis joystick input and translates it into servo movement after taking the reading of 43-258 and remaps to 0-180 degree readings: from board import SCL, SDA import busio from adafruit_pca9685 import PCA9685 from adafruit_motor import servo i2c = busio.I2C(SCL, SDA) pca = PCA9685(i2c) pca.frequency = 50 xjoystick1 = wii.joystick_x(); print(xjoystick1); servo3 = servo.Servo(pca.channels[3], min_pulse=600, max_pulse=2300); servo3.angle = wii.scale(xjoystick1,43,258,0,180); I will just say that that was fun to figure out as as far as I can find or figure no one has done this combination as of yet. Or if they have it has not been documented and publically shared. This should allow you to play sounds within a python script: from pydub import AudioSegment from pydub.playback import play song = AudioSegment.from_wav("sound.wav") play(song) Play sound in Python - Python Tutorial pythonbasics.org The values and such are read from this array of commands: wii.raw() # Returns all the data in raw wii.joystick() # Returns just the X and Y positions of the joystick wii.accelerometer() # Returns X, Y and Z positions of the accelerometer wii.button_c() # Returns True if C button is pressed, False if not wii.button_z() # Returns True if Z button is pressed, False if not wii.joystick_x() # Returns just the X position of the joystick wii.joystick_y() # Returns just the Y position of the joystick wii.accelerometer_x() # Returns just the X position of the accelerometer wii.accelerometer_y() # Returns just the Y position of the accelerometer wii.accelerometer_z() # Returns just the Z position of the accelerometer wii.scale(value,min,max,out_min,out_max) # Works the same as Arduino Map, perfect for changing values returned to a different scale, ie -100 - +100 Using a Wii Nunchuck to Control Python Turtle In this tutorial I’ll show you how to connect a Wii nunchuck adaptor to a Raspberry Pi and use Python to control the turtle module.This tutorial works with both official Nintendo or 3rd party... computers.tutsplus.com GPIO input for a 4 button membrane is next. |
Author: | martinr1000 [ Sun May 10, 2020 2:32 pm ] |
Post subject: | Re: updated raspberry pi setup |
Nice work. great for your predator setup by the looks of it. I bet you could use it in a sentry gun setup as well. |
Author: | knoxvilles_joker [ Sun May 10, 2020 8:49 pm ] |
Post subject: | |
This would translate to a sentry gun very easily. Though for my build I was looking at a motion tracking facial recognition setup. I am still reading up on options for GPIO triggering within the script or if I need to use another script, but, the problem is CPU cycles. I am trying to avoid any perceptiple delays. Especially the 6 second delay on my current setup. I also try to make the code I use very modular so it is a simple, simple matter to comment out a line and you can use things a different way or in a less complex form. On the smart gunner camera I discovered that some of this stuff can be used for very, evil, things, but good and evil are only differentiated between intent. Knowledge in and of itself has no particular alignment. |
Author: | knoxvilles_joker [ Sun May 10, 2020 10:14 pm ] |
Post subject: | Re: updated raspberry pi setup |
To view the current readings: from board import SCL, SDA; import busio; from adafruit_pca9685 import PCA9685; from adafruit_motor import servo; i2c = busio.I2C(SCL, SDA); pca = PCA9685(i2c); pca.frequency = 50; from nunchuck import nunchuck; wii = nunchuck() xjoystick1 = wii.joystick_x(); print(xjoystick1); servo3 = servo.Servo(pca.channels[3], min_pulse=600, max_pulse=2300); servo3.angle = wii.scale(xjoystick1,43,258,0,180); JoyY = wii.joystick_y(); TiltX = wii.accelerometer_x(); TiltY = wii.accelerometer_y(); TiltZ = wii.accelerometer_z(); ButC = wii.button_c(); ButZ = wii.button_z(); JoyY = wii.scale(JoyY,43,258,0,180); TiltX = wii.scale(TiltX,43,258,0,180); TiltY = wii.scale(TiltY,43,258,0,180); TiltZ = wii.scale(TiltZ,43,258,0,180); ButC = wii.scale(ButC,43,258,0,180); ButZ = wii.scale(ButZ,43,258,0,180); print("JoyY:" + str(JoyY), "TiltX:" + str(TiltX), "TiltY:" + str(TiltY), "TiltZ:" + str(TiltZ), "ButC:" + str(ButC), "ButZ:" + str(ButZ)); above yields this text: JoyY:90 TiltX:90 TiltY:90 TiltZ:90 ButC:False ButZ:False (the numbers vary based on position. The buttons false depressed, true if pressed) 43-258 are the readings range on the controller raw. wii.scale remaps those number to whatever scale you need. |
Author: | martinr1000 [ Sun May 10, 2020 10:54 pm ] |
Post subject: | Re: updated raspberry pi setup |
what version of the pi are you using? I understand that the pi 4 is significantly quicker than previous models |
Author: | martinr1000 [ Sun May 10, 2020 10:56 pm ] |
Post subject: | Re: |
knoxvilles_joker wrote: On the smart gunner camera I discovered that some of this stuff can be used for very, evil, things, but good and evil are only differentiated between intent. Knowledge in and of itself has no particular alignment. I am innocent and pure what kind of evil things |
Author: | knoxvilles_joker [ Mon May 11, 2020 12:03 am ] |
Post subject: | Re: Re: |
martinr1000 wrote: knoxvilles_joker wrote: On the smart gunner camera I discovered that some of this stuff can be used for very, evil, things, but good and evil are only differentiated between intent. Knowledge in and of itself has no particular alignment. I am innocent and pure what kind of evil things Automated sentry guns for aggressive security setups. A sniper setup like in the movie shooter. A remote sniper setup designed to evade heat signature detection and electronics around corner defense and attack strategies used by neer do wells. Drone based SMG aiming. That is just some of the simpler applications. Let us just say once I realized the evil applications potential I got a very good appreciation for how Professor Einstein felt when he witnessed the use of nuclear weapons... |
Author: | knoxvilles_joker [ Sat May 16, 2020 4:49 am ] |
Post subject: | Re: updated raspberry pi setup |
This script will display the raw output and will quit when the letter q is pressed: Code: #!/usr/bin/python3 import keyboard from nunchuck import nuchuck from time import sleep wii - nunchuck() wii.raw() while True: wii.joystick() print(wii.raw()) sleep(0.2) if keyboard.is_pressed('q'): break else: continue keyboard is an add on module to the pi and is installed with the string "sudo pip3 install keyboard" It somewhat worked and I ended up having to use a wget https://github.com/boppreh/keyboard/archive/master.zip running this from your main project folder. This utility is mainly programmed to run better on windows and mac os X boxes. It is a little bit problematic on hard core Linux setups such as the raspberry pi. I will advise that the formatting and spacing/indents on each line was a maddening experience as I am teaching myself python. Python is ten times picker on syntax than Arduino ever was. |
Author: | knoxvilles_joker [ Sat May 16, 2020 10:01 pm ] |
Post subject: | Re: updated raspberry pi setup |
I think I found a longer standing issue on the nunchuck where there are no pull up resisters on the scl and sda lines. I will need to fab a 4.7k ohm pull up resistor. This may have been causing some intermittent issues on the Arduino. The spec sheets specify using pull up resistors on each the sdl and sca data lines. This is not mentioned in the nunchucky setups. But the use of pull up resistors becomes important when you have more than one item on the i2c bus lines. To my knowledge no one has documented any wii usage on a more complicated setup. https://learn.sparkfun.com/tutorials/i2c/all |
Author: | knoxvilles_joker [ Sun May 17, 2020 6:46 am ] |
Post subject: | Re: updated raspberry pi setup |
A word on libraries. libraries are like your public library. They are only as good as the amount of books that they have that YOU can use. Some books will be there by default, but other books you have to specifically request or donate/install at the library. each book when used will expand your ability to do things. Every distribution of a given utility be it python, mysql, php, www, etc, has a path variable and set of location(s) where functions/libraries are placed. Some utilities will have multiple versions installed or present and some of the previous versions will be symbolic links or symlinks to the latest version for compatibility with older untilities. The libraries are extensions or plug-ins for binaries and secured binaries (bin and sbin) processes/executables. the root directies of /bin and /sbin and /lib are for core system functionality. add-on utilities and things beyond core system functionality are located at /usr/local/bin/ , /usr/bin , /usr/sbin , /usr/local/sbin , /usr/lib , /usr/local/lib. User installed utilities and libraries are typically housed in /usr/local in sub folders there. But, the system configuration files and anything outside of those categories goes into /etc. logs are typically stored in /var. boot configuration files are stored in /boot. /boot is assessible on the sd card if you mount it on another computer and is a quick cheat to quickly move files to your raspberry pi if you have large files to move or do not want to hook it up to the internet for whatever reason or need. Knowing that most of your manual installs will get placed in one of those folders. In my case in this exploration of development I had to manually install the keyboard, debounce, nunchuck in /usr/local/lib/python3.5/dist-packages. This amounted mainly consisted of downloading the files as a zip from github, and unzipping them to the relevant folder. Now saying all that that information is handy to know as you are troubleshooting errors. the errors will literally point you to what is missing and then you have to research that module and how to invoke the install for it or ensure that it is registered and present on the system and recognized. In the CentOS/Redhat world these errors are referred to as dependency hell and it can be a very time consuming and frustrating exercise in patience to get all requirements met to make something work. That said make sure to liberally document all steps taken so you have some basis to later replicate your work. |
Author: | knoxvilles_joker [ Mon May 18, 2020 1:50 am ] |
Post subject: | Re: updated raspberry pi setup |
This is a copy of the broken code that I am pausing on developing until I get some i2c issues addressed: Code: #!/usr/bin/python3
import keyboard from board import SCL, SDA; import busio; from adafruit_pca9685 import PCA9685; from adafruit_motor import servo; i2c = busio.I2C(SCL, SDA); pca = PCA9685(i2c); pca.frequency = 50; from nunchuck import nunchuck; wii = nunchuck() while True: xjoystick1 = wii.joystick_x(); print(xjoystick1); servo3 = servo.Servo(pca.channels[3], min_pulse=600, max_pulse=2300); servo3.angle = wii.scale(xjoystick1,43,258,0,180); JoyY = wii.joystick_y(); TiltX = wii.accelerometer_x(); TiltY = wii.accelerometer_y(); TiltZ = wii.accelerometer_z(); ButC = wii.button_c(); ButZ = wii.button_z(); JoyY = wii.scale(JoyY,43,258,0,180); TiltX = wii.scale(TiltX,43,258,0,180); TiltY = wii.scale(TiltY,43,258,0,180); TiltZ = wii.scale(TiltZ,43,258,0,180); ButC = wii.scale(ButC,43,258,0,180); ButZ = wii.scale(ButZ,43,258,0,180); print("JoyY:" + str(JoyY), "TiltX:" + str(TiltX), "TiltY:" + str(TiltY), "TiltZ:" + str(TiltZ), "ButC:" + str(ButC), "ButZ:" + str(ButZ)); above yields this text: JoyY:90 TiltX:90 TiltY:90 TiltZ:90 ButC:False ButZ:False (the numbers vary based on position. The buttons false depressed, true if pressed) #43-258 are the readings range on the controller raw. wii.scale remaps those number to whatever scale you need. sleep(0.2) if keyboard.is_pressed('q'): break else: continue |
Author: | knoxvilles_joker [ Sun May 24, 2020 5:05 am ] |
Post subject: | |
And, I think I fried ANOTHER wii nunchuck. Learning is destroying... |
Author: | knoxvilles_joker [ Sat Nov 28, 2020 8:12 am ] |
Post subject: | |
I found that the nunchuky issues were due to i2c clock stretching issues endemic with the raspberry pi. The Arduino is not fast enough to care. |
Author: | nickblack423 [ Tue Jan 12, 2021 11:14 am ] |
Post subject: | |
This is so useful thank you. I am about to start tinkering with a Raspberry Pi Zero for my Motion Tracker. I will give you a shout when I run into trouble LOL |
Page 1 of 1 | All times are UTC [ DST ] |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |