The discussion of the Alien series of films and the props used in them is the aim, but if it's got Big Bugs and Big Guns, then they are welcome too!





Post new topic Reply to topic  [ 44 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Wiimote with nunchuk on linux via bluetooth (Xeno/Pred)
PostPosted: Sun May 31, 2020 1:30 am 

Service Number: A05/TQ2.0.32141E1
Country: United States
after having multiple issues with i2c addressing the nunchuk alone I decided to try using the wiimote with the nunchuk slaved to it going completely wireless side stepping the i2c bus issue.

I have another option I will try on the raspberry pi that may help to address things and that post will get updated at that point. The short answer is I am getting a poor connection causing issues.

Now down to business.

The wiimote is a wonderful product as you have literally 24 possible button readings/states available to control any number of functions. The fact that it is wireless and only requires two AA batteries is especially good as the number one problem with any costume is too many wires getting in the way. Most of this stuff was initlally developed about ten years ago and has been rolled into most all mainstream Linux installs to date.

Please note if you are running something other than Raspbian your commands may be slightly different. Also please note that as Linux advances, and it does so rapidly at a pace that it can boggle a mind when stuff works after a few months with fresh installs. Note in the thread or PM/email me if you are having issues with version info and we can troubleshoot through and try to document/figure out what is going on.

First lets make sure we have the needed modules installed
sudo apt-get install lswm wminput libcwiid1
sudo apt install bluez
sudo apt-get install xwiimote

Now the hardware address of the is obtained through the bluetoothctl command init
just run
bluetoothctl
that opens console command and you need to run these commands
agent on
discoverable on
scan on

Output will be a list of devices. Hit the sync red button on the battery bay area of the wii mode to get it to broadcast its information for 20 seconds.

Take note of the 16 character mac address. Make sure to note confuse the o with a zero as it is a hexadecimal address and things won't work with wrong characters

list will list the avialble controllers and this is only relevant if you have a slaved controller.
devices will show the available devices that the Bluetooth scan sees
paired-devices shows which devices are paired.

Once the device shows up reliably, noted by not having lights light up everyime you hit sync,
you will need to set some settings for the device
info mac_addr will show information on the device. This will have needed info if you are trying to manipulate some settings if you are using any sort of knock off or other device
trust mac_addr sets the device as trusted
pair mac_addr pairs it with the pi
connect mac_addr connects the device.
pairing and trust are consistant across reboots.

sdptool is another nice utility as well but it is a little more tricky but can get you similar information on the devices
sdptool browse will show a list of connected devices
sdptool search --bdaddr mac_addr 0x0011 will show information on the wii nunchuck you get the mac_addr from running browse

To verify that the nunchuk is connected you check here for hid_wiimote
/sys/module

Once you get that verified you can now run down to the xwii command set
xwiishow list will show the connected device along with its uuid and identifier. note the number
then run xwiishow #
you will get a screen after a frew moments and it will list live raw data readings.

On my hardware pieces I will have to add some additional settings to recognize additional button presses.

Source sites for information:
http://manpages.ubuntu.com/manpages/tru ... ote.7.html
https://www.lifewire.com/use-nintendo-w ... es-2202065
https://www.instructables.com/id/Wiimot ... berry-Pi-/
http://manpages.ubuntu.com/manpages/tru ... ote.7.html
https://dietpi.com/phpbb/viewtopic.php?t=2966
http://raspberrypi-aa.github.io/session4/venv.html
http://wiiyourself.gl.tter.org/
https://sourceforge.net/projects/wiiuse/
https://automaticaddison.com/how-to-mak ... pberry-pi/
http://www.brianhensley.net/2012/08/wii ... esome.html
https://www.raspberrypi-spy.co.uk/2013/ ... pberry-pi/
https://sudomod.com/forum/viewtopic.php?t=1607
https://www.cl.cam.ac.uk/projects/raspb ... t/wiimote/
https://stackoverflow.com/questions/567 ... -extension
https://stackoverflow.com/questions/102 ... tion-issue
https://github.com/wedesoft/cwiid
https://github.com/abstrakraft/cwiid
http://wiki.ros.org/cwiid
https://github.com/dvdhrm/xwiimote/archive/master.zip
https://github.com/dvdhrm/xwiimote-bind ... master.zip

_________________
The impossible takes a while longer and goes over budget too...


Last edited by knoxvilles_joker on Sun Jun 14, 2020 11:10 am, edited 2 times in total.

Top
 Profile  
Reply with quote  
 Post subject: Re: Wiimote with nunchuk on linux via bluetooth
PostPosted: Sun May 31, 2020 11:07 pm 

Service Number: A05/TQ2.0.32141E1
Country: United States
OK, compiling the wiimote software from source seems to have helped things

But, compiling dependencies need to be met with these installs:
sudo apt-get install dh-autoreconf
sudo apt install libudev-dev
sudo apt-get install libncurses5-dev
sudo apt-get install git build-essential swig3.0 python-dev nodejs-dev cmake libjson-c-dev
sudo apt-get install swig

These files need to be downloaded:
wget https://github.com/dvdhrm/xwiimote/archive/master.zip
mv master.zip xwiimote.zip
then to install it:
sudo sh autogen.sh
sudo make
sudo make install

wget https://github.com/dvdhrm/xwiimote-bind ... master.zip
mv master.zip xwiimote-bindings.zip
then to install it:
sudo sh autogen.sh
sudo make
sudo make install

Compiling from source assures you have the latest build. It also fixes some issues you may have from out of date install repositories(old files) that your OS might have.

_________________
The impossible takes a while longer and goes over budget too...


Top
 Profile  
Reply with quote  
 Post subject: Re: Wiimote with nunchuk on linux via bluetooth
PostPosted: Fri Jun 05, 2020 9:53 pm 

Service Number: A05/TQ2.0.32141E1
Country: United States
to set the nunchuck to auto connect at startup:

sudo crontab -e
2
enter
at bottom enter:
@ reboot echo "connect 00:00:00:00:00:00" | bluetoothctl <-- 00:00:00:00:00:00 is the mac address of your wiimote.

reboot and hit buttons 1 and 2 simultaneously on remote as pi is starting up. It will auto connect and will pause on hostname section at startup and then resume booting.
Please note that if you change batteries or otherwise shut off remote a reboot of the pi will be required for reconnection in headless mode (no screen and keyboard used.)

_________________
The impossible takes a while longer and goes over budget too...


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Sat Jun 06, 2020 10:12 am 
Harvester of Sorrow
User avatar

Location: Lancashire (Wirral born)
Service Number: A04/TQ1.0.32156E1
Country: United Kingdom
What’s this got to do with Aliens?

_________________
Image AKA: Simon


Top
 Profile  
Reply with quote  
 Post subject: Re:
PostPosted: Sun Jun 07, 2020 2:43 am 

Service Number: A05/TQ2.0.32141E1
Country: United States
88reaper88 wrote:
What’s this got to do with Aliens?


This is an update to my control headend upgrades to my predator. Alternately I am doing this in generic enough a matter that you could use this to control a xenomorph. You could use it to play up to 24 different sounds.

You could use this to remotely control a sentry gun setup.

It could be used to control a robotic facehugger

It could control a robot.

To my knowledge this has not been documented and done to date. Plus I am having to work with the developer to see about getting some library updates done.

The actual control boards being used are half the size of the current setup.

Plus the way that I code things I try to make it very, very, very easy for newcomers and have no issues at all helping anyone at anytime if they are having issues with electronics or programming. The goal afterall is to make this community as welcoming as possible to anyone starting in the craft and trade of costuming.

It was also a recent realization that by craft I am a very adept technical writer as that is something I have done at every single job I have ever had. Plus the spill over with creative energies has made me realize that I am also gifted with the ability to draft screen play and comedic skits. But the core question remains, how do I use my abilities and gifts to grow this group and make it the most awesome place on the internet?

I had posed the question on having a separate section for predator or xenomorphs on the forums, but it really takes away from the main forum activity. The more you divide the more you split up the group into a separate shell that many never pay a mind to anywhere near as much.

This is not getting posted on therpf. adafruit.com forums are down and have been going up and down as the international unrest continues and I would normally post this there additionally.

_________________
The impossible takes a while longer and goes over budget too...


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Sun Jun 14, 2020 11:13 am 

Service Number: A05/TQ2.0.32141E1
Country: United States
The CWIID library appears to be housed here:
https://github.com/abstrakraft/cwiid
http://wiki.ros.org/cwiid

OK compiling from source:
wget https://github.com/abstrakraft/cwiid/archive/master.zip
mv master.zip cwiid.zip
cd cwiid-master

sudo apt-get install flex bison libbluetooth-dev gtk2.0-dev gtk2.0 gawk libgtk-3-dev
sudo apt-get install build-essential zlib1g-dev pkg-config libglib2.0-dev binutils-dev libboost-all-dev autoconf libtool libssl-dev libpixman-1-dev libpython-dev python-pip python-capstone virtualenv python3-gi
sudo libtoolize -f
sudo aclocal -I usr/share/aclocal
sudo automake -a -c
sudo autoconf
sudo ./configure
sudo make
sudo make install


Doing a straight ./configure won't work
you have to do autogen and then ./configure but then you get stuck on not finding gtk on check packages.

Now the issue is this setup conflicts with xwiimote library as referenced above. I will again reach out to the author on this and see what options we have.

_________________
The impossible takes a while longer and goes over budget too...


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Sat Jun 20, 2020 8:47 am 

Service Number: A05/TQ2.0.32141E1
Country: United States
cwiid is compiled. I have reached out to the author on xwiimote to see what options we have as it keeps looking for a library file that is not there.

The fix was in the bug reports and is resolved by:
export LD_LIBRARY_PATH=/usr/local/lib:${LD_LIBRARY_PATH}
source ~/.bashrc

_________________
The impossible takes a while longer and goes over budget too...


Top
 Profile  
Reply with quote  
 Post subject: Re: Wiimote with nunchuk on linux via bluetooth
PostPosted: Sat Aug 08, 2020 9:50 am 

Service Number: A05/TQ2.0.32141E1
Country: United States
Got it working had to do this:

bluetoothctl
scan on
pair bdaddr (where bdaddr is the Bluetooth address of the wiimote)

compile cwiid and python3-wiimote from source here:
https://github.com/azzra/python3-wiimote
https://github.com/abstrakraft/cwiid

copy 2.7 python modules to python3.7 as all the adafruit pieces are python3.7 only.

https://talk.maemo.org/showthread.php?t=60178
This side showed the nomenclature to get me started:

step down to python3 console with:
sudo python3
import cwiid
wm=cwiid.Wiimote()
(hit sync button on bottom of remote)
wm.state (shows current report state)
report state is changed with:
wm.rpt_mode = cwiid.RPT_BTN

wm.led=# where # equals a decimal value 1 - 15 noted here: https://github.com/abstrakraft/cwiid/bl ... /command.c
wm.rumble=# where # equals a uint8_t value noted here: https://github.com/abstrakraft/cwiid/bl ... /command.c

Report options are as follows:
RPT_STATUS minimal report
RPT_NUNCHUK report on the nunchuk
RPT_MOTIONPLUS report on the motionplus adapter
RPT_IR report on the IR function, requires bar accessory to work
RPT_EXT reports all readings on whatever connected device
RPT_CLASSIC report on the classic controller
RPT_BTN report on the wiimote controller
RPT_BALANCE report on the balance controller
RPT_ACC report on the wiimote accelerometer readings

dir(cwiid) gives you all command options
I am still going through the command options and identifying how I can avoid having to do placeholder arrays and processing things .

I have posted an issues report on the developer GitHub documenting these requesting that they be added to the man pages (in layman's terms that is the funny user manual that is supposed to document everything.)

_________________
The impossible takes a while longer and goes over budget too...


Top
 Profile  
Reply with quote  
 Post subject: Re: Wiimote with nunchuk on linux via bluetooth
PostPosted: Mon Aug 10, 2020 3:12 am 

Service Number: A05/TQ2.0.32141E1
Country: United States
OK, I can get ALL the readings to read into an array:
wm.rpt_mode = cwiid.RPT_BTN | cwiid.RPT_ACC | cwiid.RPT_NUNCHUK
{'rpt_mode' : 22, 'led' : 2, 'rumble' : 0, 'battery': 120, 'ext_type': 1, 'error': 0, 'buttons': 0, 'acc': (145, 128, 145), 'nunchuk': {'stick': (125, 129), 'acc': (171, 117, 132), 'buttons': 0}}


The issue is that I have to rename ACC and BUTTONS to account for duplicate but discrete entries.

_________________
The impossible takes a while longer and goes over budget too...


Top
 Profile  
Reply with quote  
 Post subject: Re: Wiimote with nunchuk on linux via bluetooth
PostPosted: Mon Aug 17, 2020 3:41 am 

Service Number: A05/TQ2.0.32141E1
Country: United States
OK, the way the reporting runs as seen here:
wm.rpt_mode = cwiid.RPT_BTN | cwiid.RPT_ACC | cwiid.RPT_NUNCHUK
{'rpt_mode' : 22, 'led' : 2, 'rumble' : 0, 'battery': 120, 'ext_type': 1, 'error': 0, 'buttons': 0, 'acc': (145, 128, 145), 'nunchuk': {'stick': (125, 129), 'acc': (171, 117, 132), 'buttons': 0}}
This option set for reporting methodology will not work. You can use:
wm.rpt_mode=cwiid.RPT_STATUS | cwiid.RPT_NUNCHUK or wm.rpt_mode=cwiid.RPT_STATUS | cwiid.RPT_ACC
and not get duplicate array items.
The core issue is that the wm.state is basically a print command for a dictionary array. The way that the python language works you can no slice sub dictionary elements without stepping things through more formatting.
This is the quickest way to grab the wii nunchuk button states:
wmbut=wm.state['nunchuk']; wbut=wmbut['buttons']; print(wbut)
That will give the nunchuk button states as an integer value of 0, 1, 2, or 3.
for acc settigs you will need to do this:
wmbut=wm.state['nunchuk']; wacc=wmbut['acc']; print(wacc)
This will give a value of (x, y, z)

_________________
The impossible takes a while longer and goes over budget too...


Top
 Profile  
Reply with quote  
 Post subject: Re: Wiimote with nunchuk on linux via bluetooth
PostPosted: Sat Aug 22, 2020 12:39 am 

Service Number: A05/TQ2.0.32141E1
Country: United States
OK, because of the reporting methodology in use by libcwiid and python you have to extract the data, store it as variables and then use those as input for other commands.

sudo python3
import cwiid
wm=cwiid.Wiimote()
wm.rpt_mode=cwiid.RPT_NUNCHUK
nunbut=wm.state['nunchuk']; print(nunbut); wacc=nunut['acc']; print(wacc); naccx=wacc[0]; naccy=wacc[1]; naccz=wacc[2]; print(naccx, naccy, naccz); nstick=nunbut['stick']; nstickx=nstick[0]; nsticky=nstick[1]; print(nstickx, nsticky); nunbuttons=nunbut['buttons']; print(buttons); wm.state;

and would yield the following output: (numbers will vary based upon wm.state data)

{'stick': (124, 129), 'acc': (170, 121, 136), 'buttons': 0}
170, 121, 136)
170, 121, 136
(124, 129)
124, 129
0

_________________
The impossible takes a while longer and goes over budget too...


Top
 Profile  
Reply with quote  
 Post subject: Re: Wiimote with nunchuk on linux via bluetooth
PostPosted: Sat Aug 22, 2020 3:52 am 

Service Number: A05/TQ2.0.32141E1
Country: United States
the next key is to remap the accelerometer and stick values into values that the servos can use. There are two value options a pwm signal length (0ish to 2200ish), or an angular reading(0ish.

There is not a clean way to do this built into the library. Nor is there a good remap or constrain function I could easily locate for the need.
The basic remap formula is: new value = ((old value - old min)/(old max - old min))*(new max-new min) + new min
The stick has a value range on the nunchuk of 28-220 and we are remapping to the typical servo range of 0-180 degrees. So the formula simplified is: new value = (( old value - 28)/(220-28))*(180 - 0) + 0 = ((old value - 28)/(192))* 180
so if our nunchuk value is a neutral 124 for the x access and has a value name of nstickx and we are going to name the new remapped value as nstickxr, we would have something like this:
nstickr = ((nstickx -28)/(192))*180 (now in the next line lets substitute in the value of 124)
nstickr = ((124-28)/192))*180 = ((96)/192))*180 = 0.5 * 180 = 90 = nstickr
Now if you are not sure that you will always get a non integer value we will need to remap the number as an integer value. That is done with the int() function like so:
nstickri = int(nstickr)
but how can we simplify?
nstickr= int(((nstickx-28)/192))*180)
This works, but, can we simplify the equation and variables any more? Let us try to include the calculations into the readings we actually pull from the data array we are getting from the wiimote with minimal steps. for this case example lets pull the x axis reading on the nunchuk joystick
nunbut=wm.state['nunchuk']; nstick=nunbut['stick']; print(nstick); nstickx=int(((nstick[0]-28)/192)*180); print(nstickx);
that yields a result of (in neutral position):
(124, 129)
90

Now the wiimote accelerometer is a little bit different as it has a max value of 255 (range 0-255.) The accelerometer in it is a true accelerometer in purpose and design and was intended to be used with the IR pointer and a light bar to track cursor movements. Not a good reader of movement, though I might play with a motion plus once I get one to see if I can get better acceleration readings with it.

The wii nunchuk is a little bit different on its accelerometer readings as it is setup as more of a agyroscope position type sensor and as such is better at detecting yaw and pitch changes (x and z values.) the readings range on it seems to vary between 180 and 70
nunbut=wm.state['nunchuk']; nacc=nunbut['acc']; print(nstick); naccx=int(((nacc[0]-70)/110)*180); print(naccx);
And this yields:
(76, 104, 100)
9

And who thought that after highschool and college that they would no longer be doing polynomial math?

_________________
The impossible takes a while longer and goes over budget too...


Top
 Profile  
Reply with quote  
 Post subject: Re: Wiimote with nunchuk on linux via bluetooth
PostPosted: Sun Aug 23, 2020 5:28 am 

Service Number: A05/TQ2.0.32141E1
Country: United States
Some conceptual notes. I may need to do a separate one on the math broken down.
Attachment:
predcannonconcept.pdf [77.78 KiB]
Downloaded 97 times

_________________
The impossible takes a while longer and goes over budget too...


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Sun Aug 23, 2020 9:06 am 

Service Number: A05/TQ2.0.32141E1
Country: United States
OK, to ensure accidental button presses do not cause issues I added an incremental button press counter to the buttons I would be using for sounds. I followed the format that you would use for RPi.GPIO so that it would be a simple matter to later adapt using GPIO input pins into the code base.
I took the button detection parts of the script for example button 2 and did this with it:
at the top I declared all btncounters at a value of zero. I will also do this with all the servos and lights in case things get into a stale state if there is a battery or other power failures.
import time
import os

btn2cnt = 0;

file2 = "/boot/gameover.wav";

if (buttons & cwiid.BTN_2):
print ('button 2 pressed');
btn2cnt = btn2cnt +1;
print(btn2cnt, "presses so far");
time.sleep(button_delay)
if (btn2cnt == 3):
print ('btn2cnt reached playing gameover');
os.system("aplay " + file2);
btn2cnt = 0;
time.sleep(button_delay

I directly call the audio file with aplay to play a wave file. I call directly to the files actual physical location and in so doing prevent issues where the script is in a different folder. On these sort of setups I prefer to keep things in the /boot directory as that way if something really hoses up I can simply reload things by loading the sdcard into a computer and reloading files. I use aplay for wav files and mpg123 for mp3 files.

At each step a delay of 100ms is done to allow the pi to keep up.

Now onto the board bonnet. I had to implement two variants of it. One for LED controls and the other for servo controls. They are able to run concurrently.

import board
from board import SCL, SDA
import busio
from adafruit_pca9685 import PCA9685
i2c_bus = busio.I2C(SCL, SDA)
pca = PCA9685(i2c_bus)
pca.frequency = 50

That sets up the board for duty ccycle implementation for the board. To call an led you call it like this:
pca.channels[15].duty_cycle = 0x7fff

That takes care of the light piece. I will have to play with an optocoupler to step up voltage on a super bright led array I have but that should be simple if I am understanding the wiring correctly now.

To setup the servo control piece we do this:

from adafruit_servokit import ServoKit
kit = ServoKit(channels=16)

to move a servo you call it like this:
kit.servo[0].angle=180.
the number in brackets is the channel number. The angle is an angle with a value of 0 to 180.

Now after digging through the libraries and compositional files I found that I can run this report mode and pull EVERYTHING needed for our control setup.
wii=cwiid.Wiimote() (this connects the wiimote and sets its instance as wii) (I have not tested it with two wii motes though...)
wii.led = 1 (this turns on the second led to let you know that it is connected)
wii.rpt_mode = cwiid.RPT_BTN | cwiid.RPT_ACC | cwiid.RPT_NUNCHUK

now with that setup within the run loop you need to draw the data from wm.state. I do it this way:
battery= wii.state['battery']
buttons = wii.state['buttons']
wacc = wii.state['acc']
nunbut = wii.state['nunchuk']
nbut = nunbut['buttons']
nacc = nunbut['acc']
nstick = nunbut['stick']

Now the nunchuk readings were output in wm.state as a nested dictionary. Due to the way that python is you can not slice or otherwise callout directly a subdictionary. You have to pull it out and then manipulate and pull data from that distinct array. The other quirk with python is there is not a good way to remap or constrain values so you have to do the calculations yourself. As I was going through calibrating things I found that the joystick values actually ranged 26-226 and had to adjust the formulas accordingly.

nstickx = int(((nstick[0]-26)/200)*180)
nsticky = int(((nstick[1]-26)/200)*180)
naccx = int(((nacc[0]-70)/110)*180)
naccy = int(((nacc[1]-70)/110)*180)
naccz = int(((nacc[2]-70)/110)*180)

the base formula for remapping is: new value = ((old value - old min)/ old max - old min) * (new max - new min) + new min
Now all these calculations create a nice long decimal value but we need clean integers. No problem we use the int() function built into python. It drops the decimals for us and gives a nice clean number.

Now that all of that is set it is an extremely straight forward matter to just plug in the readjusted values into the servo angular equestions like this:
kit.servo[0].angle= nstickx

The key to remember is to have a read of your active data stream so if it bombs out because something goes out of range you can re adjust things. You do that by doing this:
print(wii.state)
print('wb nb bat joyxy, accxyz')
print(buttons, nbut, battery, nstickx, nsticky, naccx, naccy, naccz)
This gives you the raw data, a key and the reformatted data.

I am still formatting the python script but will have that available once I am happy with things. And I will try to copiously note the script so anyone could do whatever they want by tweaking the setup for themselves.

But let me conclude with saying this is rather exciting as I got multiple pieces all working together for a nice working code piece and have things more or less fully documented.

Adafruit servo board information and setup:
https://learn.adafruit.com/16-channel-p ... cuitpython
https://circuitpython.readthedocs.io/pr ... ervo.Servo
https://circuitpython.readthedocs.io/pr ... t/api.html

_________________
The impossible takes a while longer and goes over budget too...


Top
 Profile  
Reply with quote  
 Post subject: Re: Wiimote with nunchuk on linux via bluetooth
PostPosted: Sun Aug 23, 2020 11:09 am 

Service Number: A05/TQ2.0.32141E1
Country: United States
Draft one of script:

Code:
#!/usr/bin/python
#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#|R|a|s|p|b|e|r|r|y|P|i|-|S|p|y|.|c|o|.|u|k|
#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#
# wii_remote_1.py
# Connect a Nintendo Wii Remote via Bluetooth
# and  read the button states in Python.
#
# Project URL :
# http://www.raspberrypi-spy.co.uk/?p=1101
#
# Author : Matt Hawkins
# Date   : 30/01/2013
# Updated 8/2020 by Gabriel Vos aka Knoxvilles_joker
# http://alienslegacy.com
# updates done to allow for sound and servo controls and read full feature set of nunchuk

# -----------------------
# Import required Python libraries
# -----------------------
import cwiid
import time
#import i2c
import os
#from board import SCL, SDA
import board
from board import SCL, SDA
import busio
#import adafruit_pca9685
from adafruit_pca9685 import PCA9685
i2c_bus = busio.I2C(SCL, SDA)
pca = PCA9685(i2c_bus)
pca.frequency = 50
#from adafruit_motor import servo
#pca = PCA9685
# standard servo declearations for controls
from adafruit_servokit import ServoKit
#pca.frequency = 50
kit = ServoKit(channels=16)
# class adafruit_moter.servo.Servo(pwm.out, *, actuation_range=180, minPpulse=750, max_pluse=2250)
#import adafruit_moster.servo
kit.servo[0].angle=170
time.sleep(0.1)
kit.servo[0].angle=0
#set_pulse_widge_range(min_pulse, max_pulse)
# kit.servo[0].set_pulse_width_range(1000, 2000)
pca.channels[15].duty_cycle = 0x7fff

button_delay = 0.1
# these are values for button depress bounces.  I use a counter to ensure accidental presses do not cause undue issues
# this also allows for gpio input if at some point there is a need to switch to RPi.GPIO button inputs with minimal change
# addressing for issues with debounce and system noise on button presses
btn1cnt = 0
btn2cnt = 0
btnupcnt = 0
btnleftcnt = 0
btndowncnt = 0
btnrightcnt = 0
btnacnt = 0
btnbcnt = 0
btnccnt = 0
btnzcnt = 0
btnhomecnt = 0
# I may have to use the sub process command set to allow for multi tasking but that is at a later stage
# These are the files for sound playback over the 3.5mm audio output going over the 3.5mm jack from the hdmi port.
# wav files are played with aplay and mp3 files are played with mpg123 engaged using the os.system command subset
# playsound does not appear to play nice with python 3.7 and is not an option currently
file1 = "/boot/minigun.wav"
file2 = "/boot/gameover.wav"
fileleft = "/boot/predator.mp3"
filedown = "/boot/alien.wav"
# canon and laser sounds
#filec =
#filez =
#fileb =


print ('Press 1 + 2 on your Wii Remote now ...')
time.sleep(1)

# Connect to the Wii Remote. If it times out
# then quit.
try:
  wii=cwiid.Wiimote()
except RuntimeError:
  print ("Error opening wiimote connection")
  quit()

print ('Wii Remote connected...\n')
print ('Press some buttons!\n')
print ('Press PLUS and MINUS together to disconnect and quit.\n')
wii.led = 1
wii.rpt_mode = cwiid.RPT_BTN  | cwiid.RPT_ACC | cwiid.RPT_NUNCHUK

while True:
#  Do not turn this line on unless you like spam in your command line output if you do comment the same line above first though
#  wii.rpt_mode = cwiid.RPT_BTN | cwiid.RPT_ACC | cwiid.RPT_NUNCHUK
#  below are values pulled from the wm.state data array and stored to be used to drive various functions
#  you can comment out the status display to troubleshoot button pushes.  all buttons are accounted for in the script
  time.sleep(0.1)
  battery = wii.state['battery']
  buttons = wii.state['buttons']
  wacc= wii.state['acc']
  nunbut = wii.state['nunchuk']
  nbut =nunbut['buttons']
  nacc =nunbut['acc']
  nstick= nunbut['stick']
  nstickx= int(((nstick[0]-26)/200)*180)
  nsticky= int(((nstick[1]-26)/200)*180)
  naccx  = int(((nacc[0]-70)/110)*180)
  naccy  = int(((nacc[1]-70)/110)*180)
  naccz  = int(((nacc[2]-70)/110)*180)
# These are disabled as the wiimote accelerometer has too odd a range of settings and is not a true tilt sensor
# It was meant to be used in conjuction with a ir ptr for calibration and pointing ability
# waccx  = int(((
 # waccy  = int(((
 # waccz  = int(((
  print(wii.state)
  print('wb nb bat joyxy, accxyz')
  print(buttons, nbut, battery, nstickx, nsticky, naccx, naccy, naccz)
  time.sleep(0.1)
  kit.servo[1].angle = nstickx
  kit.servo[2].angle = nsticky
  # If Plus and Minus buttons pressed
  # together then rumble and quit.
  if (buttons - cwiid.BTN_PLUS - cwiid.BTN_MINUS == 0):
    print ('\nClosing connection ...')
    wii.rumble = 1
    time.sleep(1)
    wii.rumble = 0
    exit(wii)
  if (battery <= 79):
    print ('please change battery now')
    wii.rumble = 1
    time.sleep(1)
    wii.rumble = 0



  # Check if other buttons are pressed by
  # doing a bitwise AND of the buttons number
  # and the predefined constant for that button.
  if (buttons & cwiid.BTN_LEFT):
    print ('Left pressed')
    btnleftcnt = btnleftcnt +1
    print (btnleftcnt, "presses so far")
    time.sleep(button_delay)
  if (btnleftcnt == 3):
    #os.system("aplay " + pred)
    btnleftcnt = 0
    time.sleep(button_delay)

  if(buttons & cwiid.BTN_RIGHT):
    print ('Right pressed')
    btnrightcnt = btnrightcnt +1
    print (btnrightcnt, "presses so far")
    time.sleep(button_delay)
  if (btnrightcnt == 3):
    #os.system("aplay " + kill)
    btnrightcnt = 0
    time.sleep(button_delay)

  if (buttons & cwiid.BTN_UP):
    print ('Up pressed')
    btnupcnt = btnupcnt +1
    print (btnupcnt, "presses so far")
    time.sleep(button_delay)
  if (btnupcnt == 3):
    #os.system("aplay " + drum)
    btnupcnt = 0
    time.sleep(button_delay)

  if (buttons & cwiid.BTN_DOWN):
    print ('Down pressed')
    btndowncnt = btndowncnt +1
    print (btndowncnt, "presses so far")
    time.sleep(button_delay)
  if (btndowncnt == 3):
    #os.system("aplay " + alien)
    btndowncnt = 0
    time.sleep(button_delay)

  if (buttons & cwiid.BTN_1):
    print ('Button 1 pressed')
    btn1cnt = btn1cnt +1;
    print(btn1cnt, "presses so far")
    time.sleep(button_delay)
  if (btn1cnt == 3):
    print ('btn cnt reached playing minigun snd');
    #os.system("aplay " + file1);
    btn1cnt = 0
    time.sleep(button_delay)

  if (buttons & cwiid.BTN_2):
    print ('Button 2 pressed')
    btn2cnt = btn2cnt +1;
    print(btn2cnt, "presses so far");
    time.sleep(button_delay)
  if (btn2cnt == 3):
    print ('btn2cnt reached playing gameover')
    #os.system("aplay " + file2)
    btn2cnt = 0;
    time.sleep(button_delay)

  if (buttons & cwiid.BTN_A):
    print ('Button A pressed engaging disengaging laser')
    btnacnt = btnacnt +1
    print(btnacnt, "presses so far")
    time.sleep(button_delay)
  if (btnacnt == 3):
    pca.channels[15].duty_cycle=0xffff
    time.sleep(button_delay)
  if (btnacnt == 5):
    pca.channels[15].duty_cycle=0x0000
    btnacnt = 0
    time.sleep(button_delay)

  if (buttons & cwiid.BTN_B):
    print ('Button B pressed')
    btnbcnt = btnbcnt +1;
    print(btnbcnt, "presses so far");
    time.sleep(button_delay)
  if (btnbcnt == 3):
    print('btnbcnt reached playing laser sound');
    #os.system("aplay " + fileb)
    btnbcnt = 0;
    time.sleep(button_delay);

  if (buttons & cwiid.BTN_HOME):
    print ('Home Button pressed')
    btnhomecnt = btnhomecnt +1;
    print(btnhomecnt, "presses so far");
    time.sleep(button_delay)
  if (btnhomecnt == 2):
    kit.servo[5].angle = 90
    time.sleep(button_delay);
  if (btnhomecnt == 4):
    kit.servo[5].angle = 0
    btnhomecnt = 0
    time.sleep(4)

  if (buttons & cwiid.BTN_MINUS):
    print ('Minus Button pressed')
    time.sleep(button_delay)

  if (buttons & cwiid.BTN_PLUS):
    print ('Plus Button pressed')
    time.sleep(button_delay)

  if (nbut & cwiid.NUNCHUK_BTN_C):
    print ('nunchuk c pressed')
    btnccnt = btnccnt +1;
    print (btnccnt, "presses so far")
    time.sleep(button_delay)
  if (btnccnt == 2):
    print ('fire left cannon, lights')
    pca.channels[14].duty_cycle=0xffff
    #os.system("aplay " + fire1)
    time.sleep(1)
    btnccnt = 0
  if (nbut & cwiid.NUNCHUK_BTN_Z):
    btnzcnt = btnzcnt +1
    print (btnzcnt, "presses so far")
    print ('nunchuk z pressed')
    time.sleep(button_delay)
  if (btnzcnt == 2):
    print ('fire right cannon, lights')
    pca.channels[13].duty_cycle=0xffff
    #os.system("aplay " + fire1)
    btnzcnt = 0
    time.sleep(button_delay)
  if (nbut - cwiid.NUNCHUK_BTN_Z - cwiid.NUNCHUK_BTN_C == 0):
    print ('nunchuk c plus z pressed')
    time.sleep(button_delay)

_________________
The impossible takes a while longer and goes over budget too...


Top
 Profile  
Reply with quote  
 Post subject: Re: Wiimote with nunchuk on linux via bluetooth
PostPosted: Sat Aug 29, 2020 3:17 am 

Service Number: A05/TQ2.0.32141E1
Country: United States
I have dialed in the code. Parts orders are pending. It still burns me that some parts I can ONLY get out of china.

Updated Code:
Code:
#!/usr/bin/python
#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#|R|a|s|p|b|e|r|r|y|P|i|-|S|p|y|.|c|o|.|u|k|
#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#
# wii_remote_1.py
# Connect a Nintendo Wii Remote via Bluetooth
# and  read the button states in Python.
#
# Project URL :
# http://www.raspberrypi-spy.co.uk/?p=1101
#
# Author : Matt Hawkins
# Date   : 30/01/2013
# Updated 8/2020 by Gabriel Vos aka Knoxvilles_joker
# http://alienslegacy.com
# updates done to allow for sound and servo controls and read full feature set of nunchuk
# Please note if using notepad and not notepad++ you must check for excess carriage returns in linux with the nano, vim, or your other preferred editor
# Please note python is very picky about syntax and spaces edit at own risk

# -----------------------
# Import required Python libraries
# -----------------------
import cwiid
import time
#import i2c
import os
#from board import SCL, SDA
import board
from board import SCL, SDA
import busio
#import adafruit_pca9685
from adafruit_pca9685 import PCA9685
i2c_bus = busio.I2C(SCL, SDA)
pca = PCA9685(i2c_bus)
pca.frequency = 50
#from adafruit_motor import servo
#pca = PCA9685
# standard servo declearations for controls
from adafruit_servokit import ServoKit
#pca.frequency = 50
kit = ServoKit(channels=16)
# class adafruit_moter.servo.Servo(pwm.out, *, actuation_range=180, minPpulse=750, max_pluse=2250)
#import adafruit_moster.servo

time.sleep(0.1)
kit.servo[0].angle=25
kit.servo[1].angle=0
kit.servo[2].angle=0
kit.servo[3].angle=0
kit.servo[4].angle=0
kit.servo[5].angle=0
kit.servo[6].angle=0
kit.servo[7].angle=0
# These are the options for the pwm portion of the servo bonnett
#set_pulse_widge_range(min_pulse, max_pulse)
# kit.servo[0].set_pulse_width_range(1000, 2000)
pca.channels[15].duty_cycle = 0x7fff

button_delay = 0.1
# these are values for button depress bounces.  I use a counter to ensure accidental presses do not cause undue issues
# this also allows for gpio input if at some point there is a need to switch to RPi.GPIO button inputs with minimal change
# addressing for issues with debounce and system noise on button presses
# note that only ascii characters 0-128 are allowed.  Any special characters are not recognized for character counter names.
btn1cnt = 0
btn2cnt = 0
btnupcnt = 0
btnleftcnt = 0
btndowncnt = 0
btnrightcnt = 0
btnacnt = 0
btnbcnt = 0
btnccnt = 0
btnzcnt = 0
btnhomecnt = 0
btnminuscnt = 0
# I may have to use the sub process command set to allow for multi tasking but that is at a later stage
# These are the files for sound playback over the 3.5mm audio output going over the 3.5mm jack from the hdmi port.
# wav files are played with aplay and mp3 files are played with mpg123 engaged using the os.system command subset
# playsound does not appear to play nice with python 3.7 and is not an option currently
file1 = "/boot/minigun.wav"
file2 = "/boot/gameover.wav"
fileleft = "/boot/predator.mp3"
filedown = "/boot/alien.wav"
# canon and laser sounds
#filec =
#filez =
#fileb =


print ('Press 1 + 2 on your Wii Remote now ...')
time.sleep(1)

# Connect to the Wii Remote. If it times out
# then quit.
try:
  wii=cwiid.Wiimote()
except RuntimeError:
  print ("Error opening wiimote connection")
  quit()

print ('Wii Remote connected...\n')
print ('Press some buttons!\n')
print ('Press PLUS and MINUS together to disconnect and quit.\n')
wii.led = 1
wii.rpt_mode = cwiid.RPT_BTN  | cwiid.RPT_ACC | cwiid.RPT_NUNCHUK

while True:
#  Do not turn this line on unless you like spam in your command line output if you do comment the same line above first though
#  wii.rpt_mode = cwiid.RPT_BTN | cwiid.RPT_ACC | cwiid.RPT_NUNCHUK
#  below are values pulled from the wm.state data array and stored to be used to drive various functions
#  you can comment out the status display to troubleshoot button pushes.  all buttons are accounted for in the script
  time.sleep(0.1)
  battery = wii.state['battery']
  buttons = wii.state['buttons']
  # Wii Accelerometer readings are 0 - 255.  It is a true accelerommeter and it is meant to be used with the IR pointer for calibration in accurate use
  # Online documentation indicates that a light source can be used for referenc ein plcase of a light bar, but your mileage will vary.
  # this function is not used but is reported
  wacc= wii.state['acc']
  # I will be getting a wii motion device at some point and adding it but until then only the nunchuck accelerometer and joystick movements are used.
  nunbut = wii.state['nunchuk']
  nbut =nunbut['buttons']
  nacc =nunbut['acc']
  # Nunchuk stick range appears to be 226 - 26
  nstick= nunbut['stick']
  nstickx= int(((nstick[0]-26)/200)*180)
  nsticky= int(((nstick[1]-26)/200)*180)
  # Nunchuck range appears to be 250 - 26
  naccx  = int(((nacc[0]-20)/230)*180)
  naccy  = int(((nacc[1]-20)/230)*180)
  naccz  = int(((nacc[2]-20)/230)*180)
  time.sleep(button_delay)
# These are disabled as the wiimote accelerometer has too odd a range of settings and is not a true tilt sensor
# It was meant to be used in conjuction with a ir ptr for calibration and pointing ability
# This is great for calibration based upon device input
# waccx  = int(((
 # waccy  = int(((
 # waccz  = int(((
  print(wii.state)
  print('wb nb bat joyxy, accxyz')
  print(buttons, nbut, battery, nstickx, nsticky, naccx, naccy, naccz)
  time.sleep(0.1)
  # servo setup is as follows:
  # main track left is 0, 1 is tilt arm left. 2 is tilt arm left levelling servo, 3 is pan servo for left and right action
  # 5 is main tilt right servo, 6 is levelling servo right, 7 is right pan left right servo
  # 10 is pwm light for firing, 15 is head laser
  # I am still playing with pwm signaling with opto couplers with a full 5v laser setup.
  kit.servo[3].angle = nstickx
#  time.sleep(button_delay)
  kit.servo[1].angle = nsticky
  time.sleep(button_delay)
  # the midarm servo is being set to always maintain a level status regardless of arm tilt.  based on my calculations with a 1:1 gear ratio
  # the best way to acheive this is with a 180 -x = z factor.  You will need to adjust this if gearing is different.
  kit.servo[2].angle = (180 - nsticky)
  kit.servo[4].angle = naccx
#  time.sleep(button_delay)
  kit.servo[6].angle = naccz
  time.sleep(button_delay)
  kit.servo[5].angle = (180 - naccz)
  # If Plus and Minus buttons pressed
  # together then rumble and quit.
  # This is a great way to exit code if you set it to run at startup and need console control back.
  # This failsafe is a great way to ensure if you have buggy code you have an opportunity to fix it
  # By default I will typically place this in the \boot directory.
  if (buttons - cwiid.BTN_PLUS - cwiid.BTN_MINUS == 0):
    print ('\nClosing connection ...')
    wii.rumble = 1
    time.sleep(1)
    wii.rumble = 0
    exit(wii)
  if (battery <= 79):
    print ('please change battery now')
    wii.rumble = 1
    time.sleep(1)
    wii.rumble = 0
# The battery replace code is a physical reminder that battery is low.
# This is a failsafe to ensure that battery drop off is not severe.
# The value is 0-255 but I have seen it drop to 70s before comms are lost.
# The most I have seen it in is the upper 100s.  Mileage will vary based upon batteries in use
# Please bear in mind wiimote is only designed for standard AA batteries.  Do not cheat with fancier batteries
# The setup and maintenance is intended to be a lower cost setup.


  # Check if other buttons are pressed by
  # doing a bitwise AND of the buttons number
  # and the predefined constant for that button.
  # I am using a counter based setup for actions.
  # Theoretically this could lead to infinite number of actions after sequential number is reached
  # This is great if you are wanting a sequential set of sounds to play in sequence, or a start and reset sequence on a set servo or light
  # Please note that at the beginning for servos you want them all to reset to their neutral start positions.
  # This ensures if things crashed on the last go around you are not hyper extending or retracting servos beyond their active range
  # This lowers power consumption and esures minimal breakage issues

  if (buttons & cwiid.BTN_LEFT):
    print ('Left pressed')
    btnleftcnt = btnleftcnt +1
    print (btnleftcnt, "presses so far")
    time.sleep(button_delay)
  if (btnleftcnt == 3):
    #os.system("aplay " + pred)
    btnleftcnt = 0
    time.sleep(button_delay)

  if(buttons & cwiid.BTN_RIGHT):
    print ('Right pressed')
    btnrightcnt = btnrightcnt +1
    print (btnrightcnt, "presses so far")
    time.sleep(button_delay)
  if (btnrightcnt == 3):
    #os.system("aplay " + kill)
    btnrightcnt = 0
    time.sleep(button_delay)

  if (buttons & cwiid.BTN_UP):
    print ('Up pressed')
    btnupcnt = btnupcnt +1
    print (btnupcnt, "presses so far")
    time.sleep(button_delay)
  if (btnupcnt == 3):
    #os.system("aplay " + drum)
    btnupcnt = 0
    time.sleep(button_delay)

  if (buttons & cwiid.BTN_DOWN):
    print ('Down pressed')
    btndowncnt = btndowncnt +1
    print (btndowncnt, "presses so far")
    time.sleep(button_delay)
  if (btndowncnt == 3):
    #os.system("aplay " + alien)
    btndowncnt = 0
    time.sleep(button_delay)

  if (buttons & cwiid.BTN_1):
    print ('Button 1 pressed')
    btn1cnt = btn1cnt +1;
    print(btn1cnt, "presses so far")
    time.sleep(button_delay)
  if (btn1cnt == 3):
    print ('btn cnt reached playing minigun snd');
    #os.system("aplay " + file1);
    btn1cnt = 0
    time.sleep(button_delay)

  if (buttons & cwiid.BTN_2):
    print ('Button 2 pressed')
    btn2cnt = btn2cnt +1;
    print(btn2cnt, "presses so far");
    time.sleep(button_delay)
  if (btn2cnt == 3):
    print ('btn2cnt reached playing gameover')
    #os.system("aplay " + file2)
    btn2cnt = 0;
    time.sleep(button_delay)

  if (buttons & cwiid.BTN_A):
    print ('Button A pressed engaging disengaging laser')
    btnacnt = btnacnt +1
    print(btnacnt, "presses so far")
    time.sleep(button_delay)
  if (btnacnt == 3):
    pca.channels[15].duty_cycle=0xffff
    time.sleep(button_delay)
  if (btnacnt == 5):
    pca.channels[15].duty_cycle=0x0000
    btnacnt = 0
    time.sleep(button_delay)

  if (buttons & cwiid.BTN_B):
    print ('Button B pressed')
    btnbcnt = btnbcnt +1;
    print(btnbcnt, "presses so far");
    time.sleep(button_delay)
  if (btnbcnt == 3):
    print('btnbcnt reached playing laser sound');
    #os.system("aplay " + fileb)
    btnbcnt = 0;
    time.sleep(button_delay);

  if (buttons & cwiid.BTN_HOME):
    print ('Home Button pressed')
    btnhomecnt = btnhomecnt +1;
    print(btnhomecnt, "presses so far");
    time.sleep(button_delay)
  if (btnhomecnt == 2):
    kit.servo[0].angle = 150
    time.sleep(button_delay);
  if (btnhomecnt == 4):
    kit.servo[0].angle = 30
    btnhomecnt = 0
    time.sleep(4)

  if (buttons & cwiid.BTN_MINUS):
    print ('Minus Button pressed')
    btnminuscnt = btnminuscnt +1;
    print(btn-cnt, "presses so far");
    time.sleep(button_delay);
  if (btnminuscnt == 2):
    print ("resetting count");
    btnminuscnt = 0
    time.sleep(button_delay);


  if (buttons & cwiid.BTN_PLUS):
    print ('Plus Button pressed')
    time.sleep(button_delay)

  if (nbut & cwiid.NUNCHUK_BTN_C):
    print ('nunchuk c pressed')
    btnccnt = btnccnt +1;
    print (btnccnt, "presses so far")
    time.sleep(button_delay)
  if (btnccnt == 2):
    print ('fire left cannon, lights')
    pca.channels[10].duty_cycle=0xffff
    #os.system("aplay " + fire1)
    time.sleep(1)
    btnccnt = 0
  if (nbut & cwiid.NUNCHUK_BTN_Z):
    btnzcnt = btnzcnt +1
    print (btnzcnt, "presses so far")
    print ('nunchuk z pressed')
    time.sleep(button_delay)
  if (btnzcnt == 2):
    print ('fire right cannon, lights')
    pca.channels[13].duty_cycle=0xffff
    #os.system("aplay " + fire1)
    btnzcnt = 0
    time.sleep(button_delay)
  if (nbut - cwiid.NUNCHUK_BTN_Z - cwiid.NUNCHUK_BTN_C == 0):
    print ('nunchuk c plus z pressed')
    time.sleep(button_delay)

_________________
The impossible takes a while longer and goes over budget too...


Top
 Profile  
Reply with quote  
 Post subject: Re: Wiimote with nunchuk on linux via bluetooth
PostPosted: Sat Aug 29, 2020 3:21 am 

Service Number: A05/TQ2.0.32141E1
Country: United States
The code is super responsive. I am getting zero issues with things. I had to add a slight 200ms delay to allow for split servo movement.

The armature servo I set as a self leveler by subtracting x axis reading from 180 and used that as the armature servo angle. I had to space out some of the movement to allow for things to catch up.

_________________
The impossible takes a while longer and goes over budget too...


Top
 Profile  
Reply with quote  
 Post subject: Re: Wiimote with nunchuk on linux via bluetooth
PostPosted: Sat Aug 29, 2020 11:07 am 

Service Number: A05/TQ2.0.32141E1
Country: United States
40mm*40mm*20mm
standard servo size
65mm * 47mm * 30mm
large size servo
There are nano, sub-micro, micro, slim-wing, mini, lowprofile, giant form factors as well.

Standard servos typically have 25 or 26 tooth heads.

torque = radius * Force * sine angle
1 ft-lb = 1.356Nm
1 ft-lb = 13.8254954376 kg-cm
1 ft-lb = 191.99999948048 oz-in
1 ft-lb = 12 in-lb

35kg-cm = 2.531554847923463 ft-lbs
60kg-cm = 4.339808310725937 ft-lbs
3304 oz-in = 17.20833337989622 ft-lbs

Basically the weight is going to be somewhere in the ballpark of 460oz in o a 2kg load on the 226cm length of the armature.
but the torque calculation is basically weight times length.

https://www.robotshop.com/community/tut ... calculator
https://www.societyofrobots.com/mechani ... mics.shtml

So weight matters a lot. Plus you must factor in inertia with movement. Now the calculation for gravity at earth's surface is 9.8 m/s^2. Now an average gait is 1.4 meters per second and most are capable of 2.5 meters per second.

So lets do some rounding say the gait is 2m/s and the gravity is constant. So if we account for worst case falls and stops you are looking at a multiplier of about 3 for your finished torque calculations for a worse case scenario. But that is so much extra we could probably swing just multiplying the torque calculation on your arm setup by a factor of 4. So 460oz-in need times 4 is 1840. Times 3 it is 1380 and times 2 920. Weight, structure, and servo costs are your main factors here. If you under value things and have a 20% chance of maybe causing an issue it might be worth it but that is a personal decision. Replacing a 40 dollar part every few months is much more budget friendly than buying a 200 dollar part and losing it or having it fail and you have no spares.

So you got your torque calculations, now what?

Now you need to protect the servo horns and hubs from being damaged. This is done either through a gearbox assembly or a servo block. You take the torque and have it rely on the framework of the assembly instead of the servo itself for core strength so all the servo does is movement. Done properly you are not going to have too much frictional drag and even then it is not enough to really be concerned with as that only comes into play in larger higher torque setups like vehicles and large robots.

Bigger shops like Studio ADI and Stan Winston Studios machine their own custom parts. Many individuals either sculpt then cast their pieces or 3d print them. Additive printing techniques for metals is still too expensive to be doable for home every day use so the other option is to go to sites like servocity.com and just buy kits or parts and pieces to build your idea. Just do not expect to buy one set of parts and do not go in expecting to buy all the right parts the first time around.

_________________
The impossible takes a while longer and goes over budget too...


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Sun Sep 06, 2020 4:55 am 

Service Number: A05/TQ2.0.32141E1
Country: United States
I finally got the left canon assembly armature assembled and mounted on the test rig ahead of transplant to the actual backpack. I will have to build another pack from scratch and allow space for a channel of a linear actuator that I will have to integrate with the pi and allow control via a roboclaw control board. There are no really good 12v/5v control setups that are cheap that would play nicely with the pi. At this point I will need to finish the current build and see where else I am off on things. I am struggling to find or lay hands on reference photos and videos so accuracy will suffer as a result.

Code:
#!/usr/bin/python
#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#|R|a|s|p|b|e|r|r|y|P|i|-|S|p|y|.|c|o|.|u|k|
#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#
# wii_remote_1.py
# Connect a Nintendo Wii Remote via Bluetooth
# and  read the button states in Python.
#
# Project URL :
# http://www.raspberrypi-spy.co.uk/?p=1101
#
# Author : Matt Hawkins
# Date   : 30/01/2013
# Updated 8/2020 by Gabriel Vos aka Knoxvilles_joker
# http://alienslegacy.com
# updates done to allow for sound and servo controls and read full feature set of nunchuk
# Please note if using notepad and not notepad++ you must check for excess carriage returns in linux with the nano, vim, or your other preferred editor
# Please note python is very picky about syntax and spaces edit at own risk

# Licensed under GPL/GNU licensing distribute as you see fit but please include header above. 
# Not to be used for commercial gain or profit unless credit given to authors.

# -----------------------
# Import required Python libraries
# -----------------------
import cwiid
import time
#import i2c
import os
#from board import SCL, SDA
import board
from board import SCL, SDA
import busio
#import adafruit_pca9685
from adafruit_pca9685 import PCA9685
i2c_bus = busio.I2C(SCL, SDA)
pca = PCA9685(i2c_bus)
pca.frequency = 50
#from adafruit_motor import servo
#pca = PCA9685
# standard servo declearations for controls
from adafruit_servokit import ServoKit
#pca.frequency = 50
kit = ServoKit(channels=16)
# class adafruit_moter.servo.Servo(pwm.out, *, actuation_range=180, minPpulse=750, max_pluse=2250)
#import adafruit_moster.servo

# due to servo placement and positioning, you have to set the initial deployment angles at settings
# other than zero and ensure that time is given so proper travel can occur without causing undue binding issues.

time.sleep(0.1)
kit.servo[0].angle=160
time.sleep(3)
kit.servo[1].angle=20
kit.servo[2].angle=180
# 0-2 are basically place holders for armature.
kit.servo[3].angle=180
kit.servo[4].angle=0
kit.servo[5].angle=0
kit.servo[6].angle=0
kit.servo[7].angle=0
# These are the options for the pwm portion of the servo bonnett
#set_pulse_widge_range(min_pulse, max_pulse)
# kit.servo[0].set_pulse_width_range(1000, 2000)
pca.channels[15].duty_cycle = 0x7fff

button_delay = 0.1
# these are values for button depress bounces.  I use a counter to ensure accidental presses do not cause undue issues
# this also allows for gpio input if at some point there is a need to switch to RPi.GPIO button inputs with minimal change
# addressing for issues with debounce and system noise on button presses
# note that only ascii characters 0-128 are allowed.  Any special characters are not recognized for character counter names.
btn1cnt = 0
btn2cnt = 0
btnupcnt = 0
btnleftcnt = 0
btndowncnt = 0
btnrightcnt = 0
btnacnt = 0
btnbcnt = 0
btnccnt = 0
btnzcnt = 0
btnhomecnt = 0
btnminuscnt = 0
# I may have to use the sub process command set to allow for multi tasking but that is at a later stage
# These are the files for sound playback over the 3.5mm audio output going over the 3.5mm jack from the hdmi port.
# wav files are played with aplay and mp3 files are played with mpg123 engaged using the os.system command subset
# playsound does not appear to play nice with python 3.7 and is not an option currently
file1 = "/boot/minigun.wav"
file2 = "/boot/gameover.wav"
fileleft = "/boot/predator.mp3"
filedown = "/boot/alien.wav"
# canon and laser sounds
#filec =
#filez =
#fileb =


print ('Press 1 + 2 on your Wii Remote now ...')
time.sleep(1)

# Connect to the Wii Remote. If it times out
# then quit.
try:
  wii=cwiid.Wiimote()
except RuntimeError:
  print ("Error opening wiimote connection")
  quit()

print ('Wii Remote connected...\n')
print ('Press some buttons!\n')
print ('Press PLUS and MINUS together to disconnect and quit.\n')
wii.led = 1
wii.rpt_mode = cwiid.RPT_BTN  | cwiid.RPT_ACC | cwiid.RPT_NUNCHUK

while True:
#  Do not turn this line on unless you like spam in your command line output if you do comment the same line above first though
#  wii.rpt_mode = cwiid.RPT_BTN | cwiid.RPT_ACC | cwiid.RPT_NUNCHUK
#  below are values pulled from the wm.state data array and stored to be used to drive various functions
#  you can comment out the status display to troubleshoot button pushes.  all buttons are accounted for in the script
  time.sleep(0.1)
  battery = wii.state['battery']
  buttons = wii.state['buttons']
  # Wii Accelerometer readings are 0 - 255.  It is a true accelerommeter and it is meant to be used with the IR pointer for calibration in accurate use
  # Online documentation indicates that a light source can be used for referenc ein plcase of a light bar, but your mileage will vary.
  # this function is not used but is reported
  wacc= wii.state['acc']
  # I will be getting a wii motion device at some point and adding it but until then only the nunchuck accelerometer and joystick movements are used.
  nunbut = wii.state['nunchuk']
  nbut =nunbut['buttons']
  nacc =nunbut['acc']
  # Nunchuk stick range appears to be 226 - 26
  nstick= nunbut['stick']
  nstickx= int(((nstick[0]-26)/200)*180)
  nsticky= int(((nstick[1]-26)/200)*180)
  # Nunchuck range appears to be 250 - 26
  naccx  = int(((nacc[0]-20)/230)*180)
  naccy  = int(((nacc[1]-20)/230)*180)
  naccz  = int(((nacc[2]-20)/230)*180)
  time.sleep(button_delay)
# These are disabled as the wiimote accelerometer has too odd a range of settings and is not a true tilt sensor
# It was meant to be used in conjuction with a ir ptr for calibration and pointing ability
# This is great for calibration based upon device input
# waccx  = int(((
 # waccy  = int(((
 # waccz  = int(((
  print(wii.state)
  print('wb nb bat joyxy, accxyz')
  print(buttons, nbut, battery, nstickx, nsticky, naccx, naccy, naccz)
  time.sleep(0.1)
  # servo setup is as follows:
  # main track left is 0, 1 is tilt arm left. 2 is tilt arm left levelling servo, 3 is pan servo for left and right action
  # 5 is main tilt right servo, 6 is levelling servo right, 7 is right pan left right servo
  # 10 is pwm light for firing, 15 is head laser
  # I am still playing with pwm signaling with opto couplers with a full 5v laser setup.
  kit.servo[2].angle = nstickx
#  time.sleep(button_delay)
  kit.servo[3].angle = nsticky
  time.sleep(button_delay)
  # the midarm servo is being set to always maintain a level status regardless of arm tilt.  based on my calculations with a 1:1 gear ratio
  # the best way to acheive this is with a 180 -x = z factor.  You will need to adjust this if gearing is different.
#  kit.servo[2].angle = (nsticky/2)
#  angular calculations were proving problematic, switching to if else statement
#  if (0 < nsticky < 30):
 #   kit.servo[2].angle = 0
 # if (31 < nsticky <70):
  #  kit.servo[2].angle = 45
 # if (55 < nsticky < 65):
 #   kit.servo[2].angle = 45
 # if ( 66 < nsticky < 90):
 #   kit.servo[2].angle = 90
 # if (91 < nsticky < 130):
 #   kit.servo[2].angle = 180
 # if (nsticky > 131):
 # kit.servo[2].angle = nsticky # implemented design indicates that the geared unit needs to be the x tilt mechanism the main armature is just a placement deal
  kit.servo[4].angle = naccx
#  time.sleep(button_delay)
  kit.servo[6].angle = naccz
  time.sleep(button_delay)
  kit.servo[5].angle = (naccx)
  # If Plus and Minus buttons pressed
  # together then rumble and quit.
  # This is a great way to exit code if you set it to run at startup and need console control back.
  # This failsafe is a great way to ensure if you have buggy code you have an opportunity to fix it
  # By default I will typically place this in the \boot directory.
  if (buttons - cwiid.BTN_PLUS - cwiid.BTN_MINUS == 0):
    print ('\nClosing connection ...')
    wii.rumble = 1
    time.sleep(1)
    kit.servo[0].angle = 160
    time.sleep(3)
    kit.servo[1].angle = 20
    time.sleep(2)
    kit.servo[2].angle = 180
    kit.servo[3].angle = 180
    kit.servo[4].angle = 0
    kit.servo[5].angle = 0
    kit.servo[6].angle = 0
    kit.servo[7].angle = 0
    time.sleep(4)
    wii.rumble = 0
    exit(wii)
  # this notifies you that the battery is low and prevents comm errors by ensuring you change the battery out. 
  if (battery <= 79):
    print ('please change battery now')
    wii.rumble = 1
    kit.servo[0].angle = 160
    time.sleep(3)
    kit.servo[1].angle = 20
    kit.servo[2].angle = 180
    kit.servo[3].angle = 180
    kit.servo[4].angle = 0
    kit.servo[5].angle = 0
    kit.servo[6].angle = 0
    kit.servo[7].angle = 0
    time.sleep(1)
    wii.rumble = 0
# The battery replace code is a physical reminder that battery is low.
# This is a failsafe to ensure that battery drop off is not severe.
# The value is 0-255 but I have seen it drop to 70s before comms are lost.
# The most I have seen it in is the upper 100s.  Mileage will vary based upon batteries in use
# Please bear in mind wiimote is only designed for standard AA batteries.  Do not cheat with fancier batteries
# The setup and maintenance is intended to be a lower cost setup.


  # Check if other buttons are pressed by
  # doing a bitwise AND of the buttons number
  # and the predefined constant for that button.
  # I am using a counter based setup for actions.
  # Theoretically this could lead to infinite number of actions after sequential number is reached
  # This is great if you are wanting a sequential set of sounds to play in sequence, or a start and reset sequence on a set servo or light
  # Please note that at the beginning for servos you want them all to reset to their neutral start positions.
  # This ensures if things crashed on the last go around you are not hyper extending or retracting servos beyond their active range
  # This lowers power consumption and esures minimal breakage issues

  if (buttons & cwiid.BTN_LEFT):
    print ('Left pressed')
    btnleftcnt = btnleftcnt +1
    print (btnleftcnt, "presses so far")
    time.sleep(button_delay)
  if (btnleftcnt == 3):
    #os.system("aplay " + pred)
    btnleftcnt = 0
    time.sleep(button_delay)

  if(buttons & cwiid.BTN_RIGHT):
    print ('Right pressed')
    btnrightcnt = btnrightcnt +1
    print (btnrightcnt, "presses so far")
    time.sleep(button_delay)
  if (btnrightcnt == 3):
    #os.system("aplay " + kill)
    btnrightcnt = 0
    time.sleep(button_delay)

  if (buttons & cwiid.BTN_UP):
    print ('Up pressed')
    btnupcnt = btnupcnt +1
    print (btnupcnt, "presses so far")
    time.sleep(button_delay)
  if (btnupcnt == 3):
    #os.system("aplay " + drum)
    btnupcnt = 0
    time.sleep(button_delay)

  if (buttons & cwiid.BTN_DOWN):
    print ('Down pressed')
    btndowncnt = btndowncnt +1
    print (btndowncnt, "presses so far")
    time.sleep(button_delay)
  if (btndowncnt == 3):
    #os.system("aplay " + alien)
    btndowncnt = 0
    time.sleep(button_delay)

  if (buttons & cwiid.BTN_1):
    print ('Button 1 pressed')
    btn1cnt = btn1cnt +1;
    print(btn1cnt, "presses so far")
    time.sleep(button_delay)
  if (btn1cnt == 3):
    print ('btn cnt reached playing minigun snd');
    #os.system("aplay " + file1);
    btn1cnt = 0
    time.sleep(button_delay)

  if (buttons & cwiid.BTN_2):
    print ('Button 2 pressed')
    btn2cnt = btn2cnt +1;
    print(btn2cnt, "presses so far");
    time.sleep(button_delay)
  if (btn2cnt == 3):
    print ('btn2cnt reached playing gameover')
    #os.system("aplay " + file2)
    btn2cnt = 0;
    time.sleep(button_delay)

  if (buttons & cwiid.BTN_A):
    print ('Button A pressed engaging disengaging laser')
    btnacnt = btnacnt +1
    print(btnacnt, "presses so far")
    time.sleep(button_delay)
  if (btnacnt == 3):
    pca.channels[15].duty_cycle=0xffff
    time.sleep(button_delay)
  if (btnacnt == 5):
    pca.channels[15].duty_cycle=0x0000
    btnacnt = 0
    time.sleep(button_delay)

  if (buttons & cwiid.BTN_B):
    print ('Button B pressed')
    btnbcnt = btnbcnt +1;
    print(btnbcnt, "presses so far");
    time.sleep(button_delay)
  if (btnbcnt == 3):
    print('btnbcnt reached playing laser sound');
    #os.system("aplay " + fileb)
    btnbcnt = 0;
    time.sleep(button_delay);

  if (buttons & cwiid.BTN_HOME):
    print ('Home Button pressed')
    btnhomecnt = btnhomecnt +1;
    print(btnhomecnt, "presses so far");
    time.sleep(button_delay)
  if (btnhomecnt == 2):
    # Initial starting point.  This ensures no movements until you are ready and accounts for accidental presses as you fumble with things suiting up and powering stuff on.
    kit.servo[0].angle = 160
   # time.sleep(3)
    kit.servo[1].angle = 20
   # time.sleep(2)
    kit.servo[2].angle = 180
#    kit.servo[3].angle = 180
 #   kit.servo[4].angle = 0
    time.sleep(button_delay);
  if (btnhomecnt == 4):
    kit.servo[0].angle = 10
    kit.servo[1].angle = 95
   # time.sleep(4)
    #this is the operating position.  Other arms will get added as I get the build out further along.
    btnhomecnt = 0
    time.sleep(4)

  if (buttons & cwiid.BTN_MINUS):
    print ('Minus Button pressed')
    btnminuscnt = btnminuscnt +1;
    print(btn-cnt, "presses so far");
    time.sleep(button_delay);
  if (btnminuscnt == 2):
    print ("resetting count");
    btnminuscnt = 0
    time.sleep(button_delay);


  if (buttons & cwiid.BTN_PLUS):
    print ('Plus Button pressed')
    time.sleep(button_delay)

  if (nbut & cwiid.NUNCHUK_BTN_C):
    print ('nunchuk c pressed')
    btnccnt = btnccnt +1;
    print (btnccnt, "presses so far")
    time.sleep(button_delay)
  if (btnccnt == 2):
    print ('fire left cannon, lights')
    pca.channels[10].duty_cycle=0xffff
    #os.system("aplay " + fire1)
    time.sleep(1)
    btnccnt = 0
  if (nbut & cwiid.NUNCHUK_BTN_Z):
    btnzcnt = btnzcnt +1
    print (btnzcnt, "presses so far")
    print ('nunchuk z pressed')
    time.sleep(button_delay)
  if (btnzcnt == 2):
    print ('fire right cannon, lights')
    pca.channels[13].duty_cycle=0xffff
    #os.system("aplay " + fire1)
    btnzcnt = 0
    time.sleep(button_delay)
  if (nbut - cwiid.NUNCHUK_BTN_Z - cwiid.NUNCHUK_BTN_C == 0):
    print ('nunchuk c plus z pressed')
    time.sleep(button_delay)

_________________
The impossible takes a while longer and goes over budget too...


Top
 Profile  
Reply with quote  
 Post subject: Re: Wiimote with nunchuk on linux via bluetooth
PostPosted: Mon Sep 07, 2020 11:38 pm 

Service Number: A05/TQ2.0.32141E1
Country: United States
quick video upload that I did:

https://www.youtube.com/watch?v=vHM2tdNe_mE

_________________
The impossible takes a while longer and goes over budget too...


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Sat Sep 12, 2020 7:44 pm 
Marine Raider
User avatar

Location: Bosnia
Service Number: A05/TQ2.0.92155E1
Country: United States
Pretty neat stuff!


Top
 Profile  
Reply with quote  
 Post subject: Re:
PostPosted: Sat Sep 12, 2020 8:47 pm 

Service Number: A05/TQ2.0.32141E1
Country: United States
Bacta Baby wrote:
Pretty neat stuff!


You are more than welcome to do it yourself. Contact me if there are questions or issues doing so.

I specifically made the whole setup very modular and portable. It can literally do whatever you want it to.

_________________
The impossible takes a while longer and goes over budget too...


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Sun Sep 13, 2020 5:54 am 

Service Number: A05/TQ2.0.32141E1
Country: United States
OK, I did a few code hacks and I have sounds playing in the background. The concurrent limit appears to be about 4 sounds playing at once.
This was accomplished by:
import subprocess
subprocess.Popen(['aplay', '-q', file1])
or
subprocess.Popen(['mpg123', '-q', file2])

Aplay plays wav files. mpg123 plays mp3 files.

I also integrated an RC on/off light module:
https://www.amazon.com/Controlled-Recei ... WXBMY2HT0C

It allowed me to power on the 5v LED array I had without issues but I had to switch from LED lighting controls using duty cycle to doing it via angle control for a clean set as the control range is off is below 1200 and on is above 1800 but cut off is over 2200.
So I did:
kit.servo[15].angle = 180 for on
and
kit.servo[15].angle = 40 for off.

The elechawk unit appears to be a china made unit as I am not finding a factory but I am finding it all over wish, banggood, aliexpress. I am not finding a domestic equivalent outside of finding write ups on how to do the same with a servo guts hack.

I am finding that a lot of the RC parts and such are ONLY made in China. This will change over time I suspect.

_________________
The impossible takes a while longer and goes over budget too...


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Sat Sep 26, 2020 6:52 am 

Service Number: A05/TQ2.0.32141E1
Country: United States
OK, I added a gyroscope that I finally got in.
https://learn.adafruit.com/nxp-precisio ... cuitpython

import adafruit_fxas21002c
i2c= busio.I2C(board.SCL, board.SDA
sensor1 = adafruit_fxas21002c.FXAS21002C(i2c)
kit.servo[5].angle=90

while True:
gyro_x, gyro_y, gyro_z = sensor1.gyroscope
print(int(gyro_x))
print(int(gyro_z))

servox=(((int(gyro_x--256)/(256--256))*180))
print(servox)
kit.servo[14].angle = servox
servox=(((int(gyro_z--256)/(256--256))*180))
print(servoz)
kit.servo[5].angle = servoz


The above lines were added to the script and seem to provide decent head tracking. Remapping the values took a big of figuring as the range was -256 to +256. It was not clear in the manual documents for the chips, but that appears to be the actual range for the the gyroscope, and magnetometer readings. The accelerometer is a 16 bit value so I am thinking the value range on that is a bit higher, but acc values were outside of my scope of things and focus

You can not map values or do servo movements within an if statement. Something to do with the values not being able to be seen outside of the conditional statement. I did try as that would have been so much easier.

That this board is working and the nunchucky was not tells me that there is some sort of pullup voltage drop with the communications. Adafruit came out with an i2c booster board late last year so I am going to try it and see if that helps things.

Adafruit also added their own version of the mpu-6050 with qwiic connectors and with a qwiic bonnet board things might be much more doable. The qwiic connection standard appears to be a new standard for the circuit python boards that requires no soldering. This makes prototyping infinitely safer with no soldering for our younger generations.

I wonder if adafruit fixed the capacitor issues with the mpu-6050. They seem to have their own mpu-6050 library so it looks like they took ownership of the library and its related maintenance issues. Circuit python seems to be taking over so python seems to be coming back into dominance again until something replaces it temporarily.

The bosch bno055 I would go with as it is a cleaner setup and a better board even with a steeper price, but the qwiic board is cheaper on that one as well. The 6050 is very tempting as it is only 7 bucks. Once the hat comes in I may do some more research on options with qwiic connections, though all the options for it are for sensors and a few display options, some which may work on a predator bomb gauntlet digit display.

_________________
The impossible takes a while longer and goes over budget too...


Top
 Profile  
Reply with quote  
 Post subject: Re: Wiimote with nunchuk on linux via bluetooth
PostPosted: Sat Sep 26, 2020 8:56 am 

Service Number: A05/TQ2.0.32141E1
Country: United States
Updated code:

Code:
#!/usr/bin/python
#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#|R|a|s|p|b|e|r|r|y|P|i|-|S|p|y|.|c|o|.|u|k|
#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#
# wii_remote_1.py
# Connect a Nintendo Wii Remote via Bluetooth
# and  read the button states in Python.
#
# Project URL :
# http://www.raspberrypi-spy.co.uk/?p=1101
#
# Author : Matt Hawkins
# Date   : 30/01/2013
# Updated 8/2020 by Gabriel Vos aka Knoxvilles_joker
# http://alienslegacy.com
# updates done to allow for sound and servo controls and read full feature set of nunchuk
# Please note if using notepad and not notepad++ you must check for excess carriage returns in linux with the nano, vim, or your other preferred editor
# Please note python is very picky about syntax and spaces edit at own risk

# Licensed under GPL/GNU licensing distribute as you see fit but please include header above.
# Not to be used for commercial gain or profit unless credit given to authors.

# -----------------------
# Import required Python libraries
# -----------------------
import cwiid
import time
import os
import subprocess
import board
from board import SCL, SDA
import busio
from adafruit_pca9685 import PCA9685
i2c_bus = busio.I2C(SCL, SDA)
pca = PCA9685(i2c_bus)
pca.frequency = 50
#from adafruit_motor import servo
#pca = PCA9685
# standard servo declearations for controls
from adafruit_servokit import ServoKit
#pca.frequency = 50
kit = ServoKit(channels=16)
# class adafruit_moter.servo.Servo(pwm.out, *, actuation_range=180, minPpulse=750, max_pluse=2250)
#import adafruit_moster.servo

# due to servo placement and positioning, you have to set the initial deployment angles at settings
# other than zero and ensure that time is given so proper travel can occur without causing undue binding issues.

time.sleep(0.1)
kit.servo[0].angle=160
#time.sleep(3)
kit.servo[1].angle=24
kit.servo[2].angle=140
# 0-2 are basically place holders for armature.
kit.servo[3].angle=180
kit.servo[4].angle=0
kit.servo[5].angle=0
kit.servo[6].angle=0
kit.servo[7].angle=0
kit.servo[13].angle=0
kit.servo[14].angle=90


# These are the options for the pwm portion of the servo bonnett
#set_pulse_widge_range(min_pulse, max_pulse)
# kit.servo[0].set_pulse_width_range(1000, 2000)
#pca.channels[15].duty_cycle = 0x7fff

button_delay = 0.1
# these are values for button depress bounces.  I use a counter to ensure accidental presses do not cause undue issues
# this also allows for gpio input if at some point there is a need to switch to RPi.GPIO button inputs with minimal change
# addressing for issues with debounce and system noise on button presses
# note that only ascii characters 0-128 are allowed.  Any special characters are not recognized for character counter names.
btn1cnt = 0
btn2cnt = 0
btnupcnt = 0
btnleftcnt = 0
btndowncnt = 0
btnrightcnt = 0
btnacnt = 0
btnbcnt = 0
btnccnt = 0
btnzcnt = 0
btnhomecnt = 0
btnminuscnt = 0

# As a rule I place everything in /boot.  It is not neccessarily a recommend practice but makes later upgrades and midstream
# changes much easier to perform if there are major code updates.

# I may have to use the sub process command set to allow for multi tasking but that is at a later stage
# These are the files for sound playback over the 3.5mm audio output going over the 3.5mm jack from the hdmi port.
# wav files are played with aplay and mp3 files are played with mpg123 engaged using the os.system command subset
# playsound does not appear to play nice with python 3.7 and is not an option currently
#SFX
file1 = "/boot/minigun.wav"
file2 = "/boot/gameover.wav"
#themes
afam = "/boot/addamsfamily.mp3"
pred = "/boot/predator.mp3"
alienc = "/boot/alienscomplex.mp3"
combat = "/boot/combatdroppercussion.mp3"
liftoff = "/boot/liftoff.mp3"
lv426 = "/boot/lv426.mp3"
gb = "/boot/ghostbusters.mp3"
halloween = "/boot/halloweenteme.mp3"
filedown = "/boot/alienisolationintro.mp3"
laser = "/boot/laser.wav"
cannon = "/boot/cannon.wav"
# branches
army = "/boot/armyhymn.mp3"
af = "/boot/airforcesong.mp3"
usmc = "/boot/usmchymn.mp3"
navy = "/boot/navyhymn.mp3"
# sound tracks
b2 = "/boot/b2theme.mp3"
b3 = "/boot/b3introtheme.mp3"
everyrule = "/boot/everyrule.mp3"
jh = "/boot/jhsettingthewoodsonfire.mp3"
jumprope = "/boot/jumprope.mp3"
rammstein = "/boot/rammsteinhallelujah.mp3"
lithiumflower = "/boot/lithiumflower.mp3"
thriller = "/boot/thriller.mp3"

print ('Press 1 + 2 on your Wii Remote now ...')
time.sleep(1)

# Connect to the Wii Remote. If it times out
# then quit.
# note that this is a clean way to quit script if stuff is not connected at startup.
try:
  wii=cwiid.Wiimote()
except RuntimeError:
  print ("Error opening wiimote connection")
  quit()

print ('Wii Remote connected...\n')
print ('Press some buttons!\n')
print ('Press PLUS and MINUS together to disconnect and quit.\n')
wii.led = 1
wii.rpt_mode = cwiid.RPT_BTN  | cwiid.RPT_ACC | cwiid.RPT_NUNCHUK

while True:
#  Do not turn this line on unless you like spam in your command line output if you do comment the same line above first though
#  wii.rpt_mode = cwiid.RPT_BTN | cwiid.RPT_ACC | cwiid.RPT_NUNCHUK
#  below are values pulled from the wm.state data array and stored to be used to drive various functions
#  you can comment out the status display to troubleshoot button pushes.  all buttons are accounted for in the script
  time.sleep(0.1) # pause required to get time for readings.
  battery = wii.state['battery']
  buttons = wii.state['buttons']
  # Wii Accelerometer readings are 0 - 255.  It is a true accelerommeter and it is meant to be used with the IR pointer for calibration in accurate use
  # Online documentation indicates that a light source can be used for referenc ein plcase of a light bar, but your mileage will vary.
  # this function is not used but is reported
  wacc= wii.state['acc']
  # I will be getting a wii motion device at some point and adding it but until then only the nunchuck accelerometer and joystick movements are used.
  nunbut = wii.state['nunchuk']
  nbut =nunbut['buttons']
  nacc =nunbut['acc']
  # Nunchuk stick range appears to be 226 - 26
  nstick= nunbut['stick']
  nstickx= int(((nstick[0]-26)/200)*180)
  nsticky= int(((nstick[1]-26)/200)*180)
  # Nunchuck range appears to be 250 - 26
  naccx  = int(((nacc[0]-20)/233)*180)
  naccy  = int(((nacc[1]-20)/233)*180)
  naccz  = int(((nacc[2]-20)/233)*180)
  time.sleep(button_delay)
# These are disabled as the wiimote accelerometer has too odd a range of settings and is not a true tilt sensor
# It was meant to be used in conjuction with a ir ptr for calibration and pointing ability
# This is great for calibration based upon device input range is 0-255
# waccx  = int(((
 # waccy  = int(((
 # waccz  = int(((
  print(wii.state)
  print('wb nb bat joyxy, accxyz')
  print(buttons, nbut, battery, nstickx, nsticky, naccx, naccy, naccz)
  time.sleep(0.1)
  # servo setup is as follows:
  # main track left is 0, 1 is tilt arm left. 2 is tilt arm left levelling servo, 3 is pan servo for left and right action
  # 5 is main tilt right servo, 6 is levelling servo right, 7 is right pan left right servo
  # 10 is pwm light for firing, 15 is head laser
  # I am still playing with pwm signaling with opto couplers with a full 5v laser setup.
  # due to some issues with coding we have to do an if else to allow for servo2 the second tilt servo to function properly. 
  if (btnhomecnt == 1):
    kit.servo[2].angle=nstickx
    kit.servo[3].angle=nsticky
    kit.servo[14].angle=nstickx
# use naccx if you want to use nunchuk accelerometer settings
  else:
    kit.servo[2].angle = 140
    kit.servo[3].angle = 180
    kit.servo[14].angle = 90

  time.sleep(button_delay)
  #this was to determine that we need to loop y axis out of bound
  #kit.servo[3].angle = nsticky
  time.sleep(button_delay)
  # the midarm servo is being set to always maintain a level status regardless of arm tilt.  based on my calculations with a 1:1 gear ratio
 # kit.servo[2].angle = nsticky # implemented design indicates that the geared unit needs to be the x tilt mechanism the main armature is just a placement deal
  kit.servo[4].angle = naccx
  kit.servo[6].angle = naccz
  kit.servo[5].angle = (naccx)
  # If Plus and Minus buttons pressed
  # together then rumble and quit.
  # This is a great way to exit code if you set it to run at startup and need console control back.
  # This failsafe is a great way to ensure if you have buggy code you have an opportunity to fix it
  # By default I will typically place this in the \boot directory.
  if (buttons - cwiid.BTN_PLUS - cwiid.BTN_MINUS == 0):
    print ('\nClosing connection ...')
    wii.rumble = 1
    time.sleep(1)
    kit.servo[0].angle = 160
    time.sleep(3)
    kit.servo[1].angle = 24
    time.sleep(2)
    kit.servo[2].angle = 140
    kit.servo[3].angle = 180
    kit.servo[4].angle = 0
    kit.servo[5].angle = 0
    kit.servo[6].angle = 0
    kit.servo[7].angle = 0
    kit.servo[13].angle = 0
    kit.servo[14].angle = 90

    time.sleep(4)
    wii.rumble = 0
    exit(wii)
  # this notifies you that the battery is low and prevents comm errors by ensuring you change the battery out.
  # This will constantly rumble until battery is replaced.
  if (battery <= 79):
    print ('please change battery now')
    wii.rumble = 1
    kit.servo[0].angle = 160
    time.sleep(3)
    kit.servo[1].angle = 24
    kit.servo[2].angle = 140
    kit.servo[3].angle = 180
    kit.servo[4].angle = 0
    kit.servo[5].angle = 0
    kit.servo[6].angle = 0
    kit.servo[7].angle = 0
    kit.servo[13].angle = 0
    kit.servo[14].angle = 90

    time.sleep(1)
    wii.rumble = 0
# The battery replace code is a physical reminder that battery is low.
# This is a failsafe to ensure that battery drop off is not severe.
# The value is 0-255 but I have seen it drop to 70s before comms are lost.
# The most I have seen it in is the upper 100s.  Mileage will vary based upon batteries in use
# Please bear in mind wiimote is only designed for standard AA batteries.  Do not cheat with fancier batteries
# The setup and maintenance is intended to be a lower cost setup.


  # Check if other buttons are pressed by
  # doing a bitwise AND of the buttons number
  # and the predefined constant for that button.
  # I am using a counter based setup for actions.
  # Theoretically this could lead to infinite number of actions after sequential number is reached
  # This is great if you are wanting a sequential set of sounds to play in sequence, or a start and reset sequence on a set servo or light
  # Please note that at the beginning for servos you want them all to reset to their neutral start positions.
  # This ensures if things crashed on the last go around you are not hyper extending or retracting servos beyond their active range
  # This lowers power consumption and esures minimal breakage issues

  if (buttons & cwiid.BTN_LEFT):
    print ('Left pressed')
    btnleftcnt = btnleftcnt +1
    print (btnleftcnt, "presses so far")
    time.sleep(button_delay)
  if (btnleftcnt == 3):
    subprocess.Popen(['mpg123', '-q', pred])
    print (btnleftcnt, "playing pred1")
    btnleftcnt = 0
    time.sleep(button_delay)

  if(buttons & cwiid.BTN_RIGHT):
    print ('Right pressed')
    btnrightcnt = btnrightcnt +1
    print (btnrightcnt, "presses so far")
    time.sleep(button_delay)
  if (btnrightcnt == 2):
    subprocess.Popen(['aplay', '-q', file2])
    btnrightcnt = btnrightcnt +1
    print (btnrightcnt, "playing file2")
    time.sleep(button_delay)
  if (btnrightcnt == 5):
    subprocess.Popen(['mpg123', '-q', jumprope])
    btnrightcnt = btnrightcnt +1
    print (btnrightcnt, "playing jumprope")
    time.sleep(button_delay)
  if (btnrightcnt == 8):
    subprocess.Popen(['mpg123', '-q', afam])
    btnrightcnt = btnrightcnt +1
    print (btnrightcnt, "playing addamsfamily")
    time.sleep(button_delay)
  if (btnrightcnt == 11):
    btnrightcnt = 0
    time.sleep(button_delay)

  if (buttons & cwiid.BTN_UP):
    print ('Up pressed')
    btnupcnt = btnupcnt +1
    print (btnupcnt, "presses so far")
    time.sleep(button_delay)
  if (btnupcnt == 2):
    subprocess.Popen(['mpg123', '-q', filedown])
    btnupcnt = btnupcnt +1
    print (btnupcnt, "playing filedown")
    time.sleep(button_delay)
  if (btnupcnt == 5):
    subprocess.Popen(['mpg123', '-q', alienc])
    btnupcnt = btnupcnt +1
    print (btnupcnt, "playing alienc")
    time.sleep(button_delay)
  if (btnupcnt == 8):
    btnupcnt = btnupcnt +1
    subprocess.Popen(['mpg123', '-q', combat])
    print (btnupcnt, "playing combat")
    time.sleep(button_delay)
  if (btnupcnt == 11):
    btnupcnt = btnupcnt +1
    subprocess.Popen(['mpg123', '-q', liftoff])
    time.sleep(button_delay)
    print (btnupcnt, "playing liftoff")
  if (btnupcnt == 14):
    btnupcnt = btnupcnt +1
    subprocess.Popen(['mpg123', '-q', lv426])
    time.sleep(button_delay)
    print (btnupcnt, "playing lv426")
  if (btnupcnt == 17):
    btnupcnt = 0
    time.sleep(button_delay)


  if (buttons & cwiid.BTN_DOWN):
    print ('Down pressed')
    btndowncnt = btndowncnt +1
    print (btndowncnt, "presses so far")
    time.sleep(button_delay)
  if (btndowncnt == 2):
    subprocess.Popen(['mpg123', '-q', af])
    time.sleep(button_delay)
    btndowncnt = btndowncnt +1
    print (btndowncnt, "playing af")
  if (btndowncnt == 5):
    btndowncnt = btndowncnt +1
    subprocess.Popen(['mpg123', '-q', army])
    time.sleep(button_delay)
    print (btndowncnt, "playing army")
  if (btndowncnt == 8):
    subprocess.Popen(['mpg123', '-q', navy])
    time.sleep(button_delay)
    btndowncnt = btndowncnt +1
    print (btndowncnt, "playing navy")
  if (btndowncnt == 11):
    btndowncnt = btndowncnt +1
    subprocess.Popen(['mpg123', '-q', usmc])
    time.sleep(button_delay)
    print (btndowncnt, "playing usmc")
  if (btndowncnt == 14):
    btndowncnt = 0
    time.sleep(button_delay)
    print (btndowncnt, "resetting count, restarting loop")

  if (buttons & cwiid.BTN_1):
    print ('Button 1 pressed')
    btn1cnt = btn1cnt +1;
    print(btn1cnt, "presses so far")
    time.sleep(button_delay)
  if (btn1cnt == 3):
    print (btn1cnt, "reached playing minigun snd");
#    os.system("aplay " + file1);
#   I am replacing the above with a subprocess that will allow for multitasking/sub process concurrency.
#   It makes for some interesting sound combinations...
#   It appears that concurrency limit is about 4.  This is the only way to play sounds and keep the script read loop running
#    Moving servos and having sound effects
    subprocess.Popen(['aplay', '-q', file1])
    btn1cnt = 0
    time.sleep(button_delay)

  if (buttons & cwiid.BTN_2):
    print ('Button 2 pressed')
    btn2cnt = btn2cnt +1;
    print(btn2cnt, "presses so far");
    time.sleep(button_delay)
  if (btn2cnt == 3):
    print (btn2cnt, "reached playing gameover")
    subprocess.Popen(['aplay', '-q', file2])
    btn2cnt = 0;
    time.sleep(button_delay)

  if (buttons & cwiid.BTN_A):
    print ('Button A pressed engaging disengaging laser')
    btnacnt = btnacnt +1
    print(btnacnt, "presses so far")
    time.sleep(button_delay)
  if (btnacnt == 2):
    subprocess.Popen(['mplayer', laser])
    kit.servo[15].angle = 180
    time.sleep(button_delay)
    btnacnt = btnacnt +1
    print (btnacnt, "playing and lighting laser")
  if (btnacnt == 5):
    subprocess.Popen(['mplayer', laser])
    kit.servo[15].angle = 40
    btnacnt = btnacnt +1
    print (btnacnt, "playing laser and powering down")
  if (btnacnt == 8):
    btnacnt = 0
    print (btnacnt, "resetting count restarting a loop")
    time.sleep(button_delay)

  if (buttons & cwiid.BTN_B):
    print ('Button B pressed')
    btnbcnt = btnbcnt +1;
    print(btnbcnt, "presses so far");
    time.sleep(button_delay)
  if (btnbcnt == 3):
    print('btnbcnt reached playing laser sound');
    kit.servo[15].angle = 180
    subprocess.Popen(['mplayer', cannon])
    time.sleep(.1)
    kit.servo[15].angle = 40
    btnbcnt = 0;
    print (btnbcnt, "playing cannon sound and lighting up")
    time.sleep(button_delay);

  if (buttons & cwiid.BTN_HOME):
    print ('Home Button pressed')
    btnhomecnt = btnhomecnt +1;
    print(btnhomecnt, "presses so far");
    time.sleep(button_delay)
  if (btnhomecnt == 0):
    # Initial starting point.  This ensures no movements until you are ready and accounts for accidental presses as you fumble with things suiting up and powering stuff on.
    kit.servo[0].angle = 160
#    time.sleep(4)
    kit.servo[1].angle = 24
    kit.servo[3].angle = 180
    kit.servo[2].angle = 140
    kit.servo[13].angle = 0
    kit.servo[14].angle = 90
#   tilt angle control is done through an if or else statement at beginning of script to constrain movement in down position
    time.sleep(button_delay);
  if (btnhomecnt == 1):
    kit.servo[0].angle = 10
    kit.servo[1].angle = 95
    kit.servo[13].angle = 51
    #this is the operating position.  Other arms will get added as I get the build out further along.
#   I had to add a separate failsafe check to reset btnhome count to prevent erraneous readings for the angle of the cannon on the y axis.
  if (btnhomecnt == 2):
  #  time.sleep(4)
    btnhomecnt = 0

  if (buttons & cwiid.BTN_MINUS):
    print ('Minus Button pressed')
    btnminuscnt = btnminuscnt +1;
    print(btnminuscnt, "presses so far");
    time.sleep(button_delay);
  if (btnminuscnt == 2):
    subprocess.Popen(['mpg123', '-q', rammstein])
    btnminuscnt = btnminuscnt +1
    print (btnminuscnt, "playing rammstein")
    time.sleep(button_delay)
  if (btnminuscnt == 5):
    time.sleep(button_delay)
    subprocess.Popen(['mpg123', '-q', lithiumflower])
    btnminuscnt = btnminuscnt +1
    print (btnminuscnt, "playing lithiumflower")
  if (btnminuscnt == 8):
    subprocess.Popen(['mpg123', '-q', thriller])
    btnminuscnt = btnminuscnt +1
    print (btnminuscnt, "playing thriller")
  if (btnminuscnt == 11):
    print ("resetting count");
    btnminuscnt = 0
    time.sleep(button_delay);


  if (buttons & cwiid.BTN_PLUS):
    print ('Plus Button pressed')
    time.sleep(button_delay)

  if (nbut & cwiid.NUNCHUK_BTN_C):
    print ('nunchuk c pressed')
    btnccnt = btnccnt +1;
    print (btnccnt, "presses so far")
    time.sleep(button_delay)
  if (btnccnt == 2):
    btnccnt = btnccnt +1
    print (btnccnt, "playing gb")
    subprocess.Popen(['mpg123', '-q', gb])
  if (btnccnt == 5):
    btnccnt = btnccnt +1
    print (btnccnt, "playing halloween")
    subprocess.Popen(['mpg123', '-q', halloween])
  if (btnccnt == 8):
    btnccnt = btnccnt +1
    print (btnccnt, "playing jh")
    subprocess.Popen(['mpg123', '-q', jh])
  if (btnccnt == 11):
    time.sleep(button_delay)
  if (btnccnt == 14):
    print ('fire left cannon, lights')
    kit.servo[10].angle = 110
    subprocess.Popen(['mplayer', cannon])
    time.sleep(1)
    kit.servo[10].angle = 40
    btnccnt = 0

  if (nbut & cwiid.NUNCHUK_BTN_Z):
    btnzcnt = btnzcnt +1
    print (btnzcnt, "presses so far")
    print ('nunchuk z pressed')
    time.sleep(button_delay)
  if (btnzcnt == 2):
    btnzcnt = btnzcnt +1
    print (btnzcnt, "playing b2")
    subprocess.Popen(['mpg123', '-q', b2])
  if (btnzcnt == 5):
    btnzcnt = btnzcnt +1
    print (btnzcnt, "playing b3")
    subprocess.Popen(['mpg123', '-q', b3])
  if (btnzcnt == 8):
    btnzcnt = btnzcnt +1
    print (btnzcnt, "playing everyrule")
    subprocess.Popen(['mpg123', '-q', everyrule])
  if (btnzcnt == 11):
    print ('fire right cannon, lights')
    kit.servo[13].angle = 110
    subprocess.Popen(['mplayer', cannon])
    btnzcnt = 0
    time.sleep(button_delay)
    time.sleep(1)
    kit.servo[13].angle = 40

  if (nbut - cwiid.NUNCHUK_BTN_Z - cwiid.NUNCHUK_BTN_C == 0):
    print ('nunchuk c plus z pressed')
    time.sleep(button_delay)

_________________
The impossible takes a while longer and goes over budget too...


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 44 posts ]  Go to page 1, 2  Next



You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: