Wednesday, December 10, 2014
Laser Cut Part
The picture above is a screen shot of the assembly depicting the usage of our laser cut part. The blue cylinder is the stand that holds the barrel of the cannon. The green part shown is the laser cut part made from .25" acrylic. The open square area is where the stepper motor is situated. This part essentially created a more aesthetically appealing design as well as situated the stepper motor in a place that maximized its potential to pull on the barrel of the cannon.
Tuesday, December 9, 2014
The Finished Product
It's safe to say that while our project didn't come out exactly how we planned, we are still happy with the finished product and certainly had a lot of fun along the way. In our original design, we had planned to be able to move the cannon from side to side and up and down using a wireless Wii nun chuck. Due to difficulties with both the programming of the wireless nun chuck and weak stepper motors, we were unable to make this a reality. However, we did manage to rig the cannon up to a regular Wii nun chuck, allowing us to fire it by pushing the "C" button on the controller. Since we couldn't get the stepper motors to handle the load necessary to move the cannon, our laser cut part was no longer necessary in order for the cannon to function properly. Perhaps in the future we will be able to find a strong enough motor so that we can aim the cannon better, but that just wasn't possible given the window of time we had to work on the project. Luckily, the cannon does satisfy the most important goal of being able to use it to launch candy into our mouths. Although getting it to fire just right takes a little bit of trial and error, it is all part of the fun and makes actually being able to catch the candy that much better. As soon as the project expo is over, we look forward to applying an excessive amount of pressure to the tank to see just how far our cannon can launch candy.
Monday, December 1, 2014
Wii Made The Nunchuck Work!
After many hours of trials and numerous codes used, we finally found a code that works!! The following code incorporates two servo motor as well as a single LED. The servo motors are controlled via the accelerometer as well as the joystick of the Wii Nunchuck. The LED is turned on when the C Button is pressed on the Nunchuck.
"
// Honus 2007
// This allows the use of a Wii nunchuck as an input device and is modified/extended from the original code
// by Tod E. Kurt and Windmeadow Labs
// 2007 Tod E. Kurt, http://todbot.com/blog/
// The Wii Nunchuck reading code is taken from Windmeadow Labs, http://www.windmeadow.com/node/42
// Further updated and coded for Manual Mode of 2 servos when WiiNunchuck ZButton is pushed.
// By: Raymond Willis Jr., 2013, email at willisjr24@yahoo.com
#include "Wire.h"
int ledPin1 = 8; // Control pin for LED 1
int servoPin1 = 5; // Control pin for servo motor
int servoPin2 = 6; // Control pin for servo motor
int pulseWidth1 = 2; // Amount to pulse the servo 1
int pulseWidth2 = 2; // Amount to pulse the servo 2
int refreshTime = 30; // the time in millisecs needed in between pulses
long lastPulse1;
long lastPulse2;
int minPulse = 700; // minimum pulse width
int loop_cnt=0;
void setup()
{
Serial.begin(19200);
pinMode(servoPin1, OUTPUT); // Set servo pin as an output pin
pinMode(servoPin2, OUTPUT); // Set servo pin as an output pin
pulseWidth1 = minPulse; // Set the motor position to the minimum
pulseWidth2 = minPulse; // Set the motor position to the minimum
nunchuck_init(); // send the initilization handshake
Serial.print("NunchuckServo ready\n");
}
void loop()
{
checkNunchuck1();
updateServo1(); // update servo 1 position
checkNunchuck2();
updateServo2(); // update servo 2 position
if( nunchuck_cbutton() ) // light the LED if c button is pressed
digitalWrite(ledPin1, HIGH);
else
digitalWrite(ledPin1,LOW);
delay(2.5); // this is here to give a known time per loop
}
void checkNunchuck1()
{
if( loop_cnt > 100 ) { // loop()s is every 1msec, this is every 100msec
nunchuck_get_data();
nunchuck_print_data();
if( nunchuck_zbutton() ) // Manual Control if z button is pressed
{
float tilt = nunchuck_joyx(); // x-axis, in this case ranges from ~70 - ~185
tilt = (tilt - 70) * 1.5; // convert to angle in degrees, roughly
pulseWidth1 = (tilt * 9) + minPulse; // convert angle to microseconds
}
else
{
float tilt = nunchuck_accelx(); // x-axis, in this case ranges from ~70 - ~185
tilt = (tilt - 70) * 1.5; // convert to angle in degrees, roughly
pulseWidth1 = (tilt * 9) + minPulse; // convert angle to microseconds
}
loop_cnt = 0; // reset for
}
loop_cnt++;
}
// called every loop().
// uses global variables servoPin, pulsewidth, lastPulse, & refreshTime
void updateServo1()
{
// pulse the servo again if rhe refresh time (20 ms) have passed:
if (millis() - lastPulse1 >= refreshTime) {
digitalWrite(servoPin1, HIGH); // Turn the motor on
delayMicroseconds(pulseWidth1); // Length of the pulse sets the motor position
digitalWrite(servoPin1, LOW); // Turn the motor off
lastPulse1 = millis(); // save the time of the last pulse
}
}
void checkNunchuck2()
{
if( loop_cnt > 100 ) { // loop()s is every 1msec, this is every 100msec
nunchuck_get_data();
nunchuck_print_data();
if( nunchuck_zbutton() ) // Manual Control if z button is pressed
{
float tilt = nunchuck_joyy(); // y-axis, in this case ranges from ~70 - ~185
tilt = (tilt - 70) * 1.5; // convert to angle in degrees, roughly
pulseWidth2 = (tilt * 9) + minPulse; // convert angle to microseconds
}
else
{
float tilt = nunchuck_accely(); // y-axis, in this case ranges from ~70 - ~185
tilt = (tilt - 70) * 1.5; // convert to angle in degrees, roughly
pulseWidth2 = (tilt * 9) + minPulse; // convert angle to microseconds
}
loop_cnt = 0; // reset for
}
loop_cnt++;
}
// called every loop().
// uses global variables servoPin, pulsewidth, lastPulse, & refreshTime
void updateServo2()
{
// pulse the servo again if rhe refresh time (20 ms) have passed:
if (millis() - lastPulse2 >= refreshTime) {
digitalWrite(servoPin2, HIGH); // Turn the motor on
delayMicroseconds(pulseWidth2); // Length of the pulse sets the motor position
digitalWrite(servoPin2, LOW); // Turn the motor off
lastPulse2 = millis(); // save the time of the last pulse
}
}
//
// Nunchuck functions
//
static uint8_t nunchuck_buf[6]; // array to store nunchuck data,
// initialize the I2C system, join the I2C bus,
// and tell the nunchuck we're talking to it
void nunchuck_init()
{
Wire.begin(); // join i2c bus as master
Wire.beginTransmission(0x52); // transmit to device 0x52
Wire.write(0x40); // sends memory address
Wire.write(0x00); // sends sent a zero.
Wire.endTransmission(); // stop transmitting
}
// Send a request for data to the nunchuck
// was "send_zero()"
void nunchuck_send_request()
{
Wire.beginTransmission(0x52); // transmit to device 0x52
Wire.write(0x00); // sends one byte
Wire.endTransmission(); // stop transmitting
}
// Receive data back from the nunchuck,
// returns 1 on successful read. returns 0 on failure
int nunchuck_get_data()
{
int cnt=0;
Wire.requestFrom (0x52, 6); // request data from nunchuck
while (Wire.available ()) {
// receive byte as an integer
nunchuck_buf[cnt] = nunchuk_decode_byte(Wire.read());
cnt++;
}
nunchuck_send_request(); // send request for next data payload
// If we recieved the 6 bytes, then go print them
if (cnt >= 5) {
return 1; // success
}
return 0; //failure
}
// Print the input data we have recieved
// accel data is 10 bits long
// so we read 8 bits, then we have to add
// on the last 2 bits. That is why I
// multiply them by 2 * 2
void nunchuck_print_data()
{
static int i=0;
int joy_x_axis = nunchuck_buf[0];
int joy_y_axis = nunchuck_buf[1];
int accel_x_axis = nunchuck_buf[2]; // * 2 * 2;
int accel_y_axis = nunchuck_buf[3]; // * 2 * 2;
int accel_z_axis = nunchuck_buf[4]; // * 2 * 2;
int z_button = 0;
int c_button = 0;
// byte nunchuck_buf[5] contains bits for z and c buttons
// it also contains the least significant bits for the accelerometer data
// so we have to check each bit of byte outbuf[5]
if ((nunchuck_buf[5] >> 0) & 1)
z_button = 1;
if ((nunchuck_buf[5] >> 1) & 1)
c_button = 1;
if ((nunchuck_buf[5] >> 2) & 1)
accel_x_axis += 2;
if ((nunchuck_buf[5] >> 3) & 1)
accel_x_axis += 1;
if ((nunchuck_buf[5] >> 4) & 1)
accel_y_axis += 2;
if ((nunchuck_buf[5] >> 5) & 1)
accel_y_axis += 1;
if ((nunchuck_buf[5] >> 6) & 1)
accel_z_axis += 2;
if ((nunchuck_buf[5] >> 7) & 1)
accel_z_axis += 1;
Serial.print(i,DEC);
Serial.print("\t");
Serial.print("joy:");
Serial.print(joy_x_axis,DEC);
Serial.print(",");
Serial.print(joy_y_axis, DEC);
Serial.print(" \t");
Serial.print("acc:");
Serial.print(accel_x_axis, DEC);
Serial.print(",");
Serial.print(accel_y_axis, DEC);
Serial.print(",");
Serial.print(accel_z_axis, DEC);
Serial.print("\t");
Serial.print("but:");
Serial.print(z_button, DEC);
Serial.print(",");
Serial.print(c_button, DEC);
Serial.print("\r\n"); // newline
i++;
}
// Encode data to format that most wiimote drivers except
// only needed if you use one of the regular wiimote drivers
char nunchuk_decode_byte (char x)
{
x = (x ^ 0x17) + 0x17;
return x;
}
// returns zbutton state: 1=pressed, 0=notpressed
int nunchuck_zbutton()
{
return ((nunchuck_buf[5] >> 0) & 1) ? 0 : 1; // voodoo
}
// returns zbutton state: 1=pressed, 0=notpressed
int nunchuck_cbutton()
{
return ((nunchuck_buf[5] >> 1) & 1) ? 0 : 1; // voodoo
}
// returns value of x-axis joystick
int nunchuck_joyx()
{
return nunchuck_buf[0];
}
// returns value of y-axis joystick
int nunchuck_joyy()
{
return nunchuck_buf[1];
}
// returns value of x-axis accelerometer
int nunchuck_accelx()
{
return nunchuck_buf[2]; // FIXME: this leaves out 2-bits of the data
}
// returns value of y-axis accelerometer
int nunchuck_accely()
{
return nunchuck_buf[3]; // FIXME: this leaves out 2-bits of the data
}
// returns value of z-axis accelerometer
int nunchuck_accelz()
{
return nunchuck_buf[4]; // FIXME: this leaves out 2-bits of the data
}
"
// Honus 2007
// This allows the use of a Wii nunchuck as an input device and is modified/extended from the original code
// by Tod E. Kurt and Windmeadow Labs
// 2007 Tod E. Kurt, http://todbot.com/blog/
// The Wii Nunchuck reading code is taken from Windmeadow Labs, http://www.windmeadow.com/node/42
// Further updated and coded for Manual Mode of 2 servos when WiiNunchuck ZButton is pushed.
// By: Raymond Willis Jr., 2013, email at willisjr24@yahoo.com
#include "Wire.h"
int ledPin1 = 8; // Control pin for LED 1
int servoPin1 = 5; // Control pin for servo motor
int servoPin2 = 6; // Control pin for servo motor
int pulseWidth1 = 2; // Amount to pulse the servo 1
int pulseWidth2 = 2; // Amount to pulse the servo 2
int refreshTime = 30; // the time in millisecs needed in between pulses
long lastPulse1;
long lastPulse2;
int minPulse = 700; // minimum pulse width
int loop_cnt=0;
void setup()
{
Serial.begin(19200);
pinMode(servoPin1, OUTPUT); // Set servo pin as an output pin
pinMode(servoPin2, OUTPUT); // Set servo pin as an output pin
pulseWidth1 = minPulse; // Set the motor position to the minimum
pulseWidth2 = minPulse; // Set the motor position to the minimum
nunchuck_init(); // send the initilization handshake
Serial.print("NunchuckServo ready\n");
}
void loop()
{
checkNunchuck1();
updateServo1(); // update servo 1 position
checkNunchuck2();
updateServo2(); // update servo 2 position
if( nunchuck_cbutton() ) // light the LED if c button is pressed
digitalWrite(ledPin1, HIGH);
else
digitalWrite(ledPin1,LOW);
delay(2.5); // this is here to give a known time per loop
}
void checkNunchuck1()
{
if( loop_cnt > 100 ) { // loop()s is every 1msec, this is every 100msec
nunchuck_get_data();
nunchuck_print_data();
if( nunchuck_zbutton() ) // Manual Control if z button is pressed
{
float tilt = nunchuck_joyx(); // x-axis, in this case ranges from ~70 - ~185
tilt = (tilt - 70) * 1.5; // convert to angle in degrees, roughly
pulseWidth1 = (tilt * 9) + minPulse; // convert angle to microseconds
}
else
{
float tilt = nunchuck_accelx(); // x-axis, in this case ranges from ~70 - ~185
tilt = (tilt - 70) * 1.5; // convert to angle in degrees, roughly
pulseWidth1 = (tilt * 9) + minPulse; // convert angle to microseconds
}
loop_cnt = 0; // reset for
}
loop_cnt++;
}
// called every loop().
// uses global variables servoPin, pulsewidth, lastPulse, & refreshTime
void updateServo1()
{
// pulse the servo again if rhe refresh time (20 ms) have passed:
if (millis() - lastPulse1 >= refreshTime) {
digitalWrite(servoPin1, HIGH); // Turn the motor on
delayMicroseconds(pulseWidth1); // Length of the pulse sets the motor position
digitalWrite(servoPin1, LOW); // Turn the motor off
lastPulse1 = millis(); // save the time of the last pulse
}
}
void checkNunchuck2()
{
if( loop_cnt > 100 ) { // loop()s is every 1msec, this is every 100msec
nunchuck_get_data();
nunchuck_print_data();
if( nunchuck_zbutton() ) // Manual Control if z button is pressed
{
float tilt = nunchuck_joyy(); // y-axis, in this case ranges from ~70 - ~185
tilt = (tilt - 70) * 1.5; // convert to angle in degrees, roughly
pulseWidth2 = (tilt * 9) + minPulse; // convert angle to microseconds
}
else
{
float tilt = nunchuck_accely(); // y-axis, in this case ranges from ~70 - ~185
tilt = (tilt - 70) * 1.5; // convert to angle in degrees, roughly
pulseWidth2 = (tilt * 9) + minPulse; // convert angle to microseconds
}
loop_cnt = 0; // reset for
}
loop_cnt++;
}
// called every loop().
// uses global variables servoPin, pulsewidth, lastPulse, & refreshTime
void updateServo2()
{
// pulse the servo again if rhe refresh time (20 ms) have passed:
if (millis() - lastPulse2 >= refreshTime) {
digitalWrite(servoPin2, HIGH); // Turn the motor on
delayMicroseconds(pulseWidth2); // Length of the pulse sets the motor position
digitalWrite(servoPin2, LOW); // Turn the motor off
lastPulse2 = millis(); // save the time of the last pulse
}
}
//
// Nunchuck functions
//
static uint8_t nunchuck_buf[6]; // array to store nunchuck data,
// initialize the I2C system, join the I2C bus,
// and tell the nunchuck we're talking to it
void nunchuck_init()
{
Wire.begin(); // join i2c bus as master
Wire.beginTransmission(0x52); // transmit to device 0x52
Wire.write(0x40); // sends memory address
Wire.write(0x00); // sends sent a zero.
Wire.endTransmission(); // stop transmitting
}
// Send a request for data to the nunchuck
// was "send_zero()"
void nunchuck_send_request()
{
Wire.beginTransmission(0x52); // transmit to device 0x52
Wire.write(0x00); // sends one byte
Wire.endTransmission(); // stop transmitting
}
// Receive data back from the nunchuck,
// returns 1 on successful read. returns 0 on failure
int nunchuck_get_data()
{
int cnt=0;
Wire.requestFrom (0x52, 6); // request data from nunchuck
while (Wire.available ()) {
// receive byte as an integer
nunchuck_buf[cnt] = nunchuk_decode_byte(Wire.read());
cnt++;
}
nunchuck_send_request(); // send request for next data payload
// If we recieved the 6 bytes, then go print them
if (cnt >= 5) {
return 1; // success
}
return 0; //failure
}
// Print the input data we have recieved
// accel data is 10 bits long
// so we read 8 bits, then we have to add
// on the last 2 bits. That is why I
// multiply them by 2 * 2
void nunchuck_print_data()
{
static int i=0;
int joy_x_axis = nunchuck_buf[0];
int joy_y_axis = nunchuck_buf[1];
int accel_x_axis = nunchuck_buf[2]; // * 2 * 2;
int accel_y_axis = nunchuck_buf[3]; // * 2 * 2;
int accel_z_axis = nunchuck_buf[4]; // * 2 * 2;
int z_button = 0;
int c_button = 0;
// byte nunchuck_buf[5] contains bits for z and c buttons
// it also contains the least significant bits for the accelerometer data
// so we have to check each bit of byte outbuf[5]
if ((nunchuck_buf[5] >> 0) & 1)
z_button = 1;
if ((nunchuck_buf[5] >> 1) & 1)
c_button = 1;
if ((nunchuck_buf[5] >> 2) & 1)
accel_x_axis += 2;
if ((nunchuck_buf[5] >> 3) & 1)
accel_x_axis += 1;
if ((nunchuck_buf[5] >> 4) & 1)
accel_y_axis += 2;
if ((nunchuck_buf[5] >> 5) & 1)
accel_y_axis += 1;
if ((nunchuck_buf[5] >> 6) & 1)
accel_z_axis += 2;
if ((nunchuck_buf[5] >> 7) & 1)
accel_z_axis += 1;
Serial.print(i,DEC);
Serial.print("\t");
Serial.print("joy:");
Serial.print(joy_x_axis,DEC);
Serial.print(",");
Serial.print(joy_y_axis, DEC);
Serial.print(" \t");
Serial.print("acc:");
Serial.print(accel_x_axis, DEC);
Serial.print(",");
Serial.print(accel_y_axis, DEC);
Serial.print(",");
Serial.print(accel_z_axis, DEC);
Serial.print("\t");
Serial.print("but:");
Serial.print(z_button, DEC);
Serial.print(",");
Serial.print(c_button, DEC);
Serial.print("\r\n"); // newline
i++;
}
// Encode data to format that most wiimote drivers except
// only needed if you use one of the regular wiimote drivers
char nunchuk_decode_byte (char x)
{
x = (x ^ 0x17) + 0x17;
return x;
}
// returns zbutton state: 1=pressed, 0=notpressed
int nunchuck_zbutton()
{
return ((nunchuck_buf[5] >> 0) & 1) ? 0 : 1; // voodoo
}
// returns zbutton state: 1=pressed, 0=notpressed
int nunchuck_cbutton()
{
return ((nunchuck_buf[5] >> 1) & 1) ? 0 : 1; // voodoo
}
// returns value of x-axis joystick
int nunchuck_joyx()
{
return nunchuck_buf[0];
}
// returns value of y-axis joystick
int nunchuck_joyy()
{
return nunchuck_buf[1];
}
// returns value of x-axis accelerometer
int nunchuck_accelx()
{
return nunchuck_buf[2]; // FIXME: this leaves out 2-bits of the data
}
// returns value of y-axis accelerometer
int nunchuck_accely()
{
return nunchuck_buf[3]; // FIXME: this leaves out 2-bits of the data
}
// returns value of z-axis accelerometer
int nunchuck_accelz()
{
return nunchuck_buf[4]; // FIXME: this leaves out 2-bits of the data
}
"
This should be easily translatable to a stepper motor instead of two servos. We will also be able to use the LED function to control the inline sprinkler valve to control the air flow and pressure release.
Saturday, November 29, 2014
Are We There Yet?
Progress: This is the SolidWorks sketch for the laser cut part. It will be the base in which the motor and the stand will be placed in. Today we as well drew up the final sketch for how the cannon will be attached and moved. The programming is still a work in progress. We have attempted to interface multiple codes with our board and Wii Nunchuck. None of them have worked. We will continue to search for codes that work and try to make progress on a possible Nunchuck - Arduino interaction.
Wednesday, November 19, 2014
Incorporating Arduino
The following code was used to create the launch using a push button and a relay:
"
int relay = 8;
int button = 2;
void setup(){
pinMode(led,OUTPUT);
pinMode(relay,OUTPUT);
pinMode(button, INPUT_PULLUP);
digitalWrite(relay, LOW);
}
void loop(){
boolean buttonState = digitalRead(button);
if(buttonState == 0){
digitalWrite(relay, HIGH);
delay(100);
digitalWrite(relay, LOW);
}
if(buttonState == 1){
digitalWrite(relay, LOW);
}
}
"
Sunday, November 16, 2014
First Launch!
Progress
![]() |
Design sketch |
Our cannon! |
Monday, November 10, 2014
Shopping Excursion
Yesterday the group went on an excursion to Home Depot and the ever exciting Walmart. At Home Depot we encountered an employee named Dave, who throughout his adolescence tinkered with various schematics of potato guns and the sort. He was able to give us some helpful advice so to what sorts of parts that we need. One of the most important pieces of the design, a sprinkler head, was not able to be procured, which will delay the production of our project. We were able to find various pieces of PVC piping that will be used to create the air pressure tank as well as the barrel of the cannon. We made a quick stop at Walmart to acquire a few cartons of Whopper Candies. These seem more likely to create an effective launch rather than the previously thought of M&M's. Following this post is a picture of Andrew and Kevin thoroughly enjoying shopping in Home Depot expertly taken by the group photographer Jackie.
Thursday, November 6, 2014
The Popinator!
Here is a much more complicated, slightly saltier version of what we hope to accomplish!
Change of Plans!
Due to the complexity of both building and programming a coil gun, we have decided to rethink our overall design, shifting our focus away from using electromagnetism to launch our projectiles to using air pressure. By creating a pressure tank and controlling the release of air using a sprinkler valve connected to an Arduino board, we hope to be able to successfully send our sweets flying.
Below is a rough sketch of what our pneumatic cannon will look like:
Below is a rough sketch of what our pneumatic cannon will look like:
We hope to have all the supplies purchased and the cannon built by Tuesday, November 11 so we can start working on the remote controlled pan and tilt function on the cannon!
Thursday, October 30, 2014
Interesting Projects!
The following video will be helpful for the design of our M&M launcher.
The arduino project in this video is similar to our project plans because it uses stepper motors to control a turret.
This arduino project consists of an array of lights that are controlled by music input.
Project Overview
This project is centered around creating "something" that interacts with the environment. This "something" is left to our imagination and contains very few guidelines or constrains. Other than a necessary interaction with the environment, the end result of the project must have at least one 3-D printed part.
Our project, Soaring Sweets, will be based off of a common food trick. Many children, as well as adults, enjoy challenging each other to catch pieces of food in their mouths by tossing them in the air. Our project is aimed at taking this challenge one step further. Rather than tossing a piece of food in the air, we aim to launch that piece of food from a cannon. To use our project well, you will need a general understanding of projectile motion principles that will govern the flight path of the piece of food. Growing up, the most common food items used for this from our experiences were popcorn, M&M's, and Goldfish. In order to combine both appeal and an item heavy enough to follow a steady flight path we are going to be using M&M's.
Our project, Soaring Sweets, will be based off of a common food trick. Many children, as well as adults, enjoy challenging each other to catch pieces of food in their mouths by tossing them in the air. Our project is aimed at taking this challenge one step further. Rather than tossing a piece of food in the air, we aim to launch that piece of food from a cannon. To use our project well, you will need a general understanding of projectile motion principles that will govern the flight path of the piece of food. Growing up, the most common food items used for this from our experiences were popcorn, M&M's, and Goldfish. In order to combine both appeal and an item heavy enough to follow a steady flight path we are going to be using M&M's.
Greetings and welcome to our blog! This is the official blog of the Soaring Sweets Initiative. We are three sophomore students enrolled in professor Sullivan's 22.201 Design Lab 1 course as a part of our mechanical engineering undergraduate curriculum at the University of Massachusetts Lowell.
Let's meet the team! This team consists of all-star members: Kevin Falco from Chelmsford MA, Jackie Solimine from Haverhill MA, and Andrew Latulippe from Derry NH. Shown from left to right in the picture below.
Let's meet the team! This team consists of all-star members: Kevin Falco from Chelmsford MA, Jackie Solimine from Haverhill MA, and Andrew Latulippe from Derry NH. Shown from left to right in the picture below.
Subscribe to:
Posts (Atom)