Remote Controlled Wiitar

From Mech
Jump to: navigation, search
Remote Controlled Wiitar

Contents

Team Members

Nathan Hirsch (left) and George Randolph (right)
  • Nathan Hirsch - Mechanical Engineering - Class of 2010
  • George Randolph - Mechanical Engineering - Class of 2010


Overview

Overview Graphic

The goal of our project was to create a system that allows a user to use a remote control to play a guitar. The Remote Controlled Wiitar uses a Nintendo Wii Remote to control an array of solenoids and a motor that are capable of playing several different chords on a guitar. A video of our project can be found here.




Mechanical Design

Our design consisted of two major components. The solenoid bridge, which was responsible for depressing strings on the neck of the guitar, and the strumming bridge, which was responsible for strumming the strings of the guitar.


Solenoid Bridge

Solenoid Bridge

The solenoid bridge was constructed out of wood. Its table shape was designed to allow the neck of the guitar to fit under it, with enough clearance for several solenoids to be attached to the underside of the bridge.


Brackets made of eighth inch aluminum sheet metal were fashioned to mount the solenoids on the bridge. The brackets also included holes where elastic cable was attached. The elastic cable retracted the solenoids when they were not powered.


The solenoids were originally attached to bridge using nuts and bolts. Though this worked, it was difficult to attach the solenoids precisely enough to accurately depress the guitar strings. In the final design, Velcro was used instead of nuts and bolts. This allowed for more precise mounting of the solenoids on the solenoid bridge and facilitated easy reconfiguration of the solenoids into different chord shapes. A second solenoid bridge was added in the final design to allow additional notes to be fretted near the body of the guitar.


Strumming Bridge

Strummer

The strumming bridge was also constructed out of wood. Two 2x4 legs were cut and connected at the top by a strip of plywood. The strumming bridge was designed to allow the body of the guitar to fit underneath, with enough clearance for a strumming arm to sweep across the strings.


The motor was attached at the center of the top of the strumming bridge using nuts and bolts. A thin plywood strip that served as a strummer was attached to the shaft of the motor using a set screw. The circular motion of the motor caused the strummer to be closer to the guitar strings in the center than the guitar strings on the outside. For this reason, a rotational spring was attached to one side of the strummer which deflected as it swept across the springs resulting in an even strum.


A hall effect sensor was mounted about six inches from the motor on the strumming bridge. A magnet was attached to the strummer that aligned with the hall effect sensor when the strummer was parallel to the ground. When these components were aligned, the hall effect sensor sent signals to the PIC, providing feedback on the position of the strummer.



Electrical Design

The circuity used to control the Wiitar is relatively simple. The figure to the right shows the basic concept of our project. The Wiimote communicates with a laptop via Bluetooth. When a user shakes the Wiimote or presses a button on the Wiimote, a signal is sent to the computer. The computer then sends a message to the PIC via RS 232. The PIC takes those signals and outputs voltages to control the solenoids or strum the guitar, depending on the signal from the Wiimote.


Parts List

Here are the electrical components required to build the circuitry used to control the Wiitar. The parts that are needed can all be found in the mechatronics lab.

They are:

  • PIC 32 microcontroller
  • 100 Ω, 1 KΩ resistors and a 10 KΩ potentiometer
  • 0.1 uF capacitor
  • LM311N voltage comparator
  • L293D H-Bridge
  • Diodes (1N4003)
  • Hall Effect Sensor (A3240LUA-T)
  • NPN Darlington Pair Transistors (2N 6045)
  • LEDs
  • Wiimote
  • Computer with Bluetooth


Motor Circuit

Circuit Used To Drive Motor

The 6W Maxon motor with 6:1 gearhead that drives the strummer is operated by the PIC. Details on this motor can be found on the Actuators Available in the Mechatronics Lab page. The circuit to the right gives pin-outs and shows how to connect the motor to the PIC. Three pins on the PIC are used. A direction pin, an enable pin and a pin for PWM. The following table shows how they are related

Direction PWM Motion
0 0 Brake
0 1 Forward
1 0 Reverse
1 1 Brake


The H-Bridge we used to drive the motor was an L293D. It's data sheet can be found here


Hall Effect Sensor Circuit

We used a hall effect sensor to monitor the position of the strummer. The concept behind a hall effect sensor is simple: it's a device that senses a change in magnetic fields. So, if a magnet is waved across the sensor, it outputs varying voltages. We put a pill magnet on one end of the strummer bar so when the motor spun, the hall effect sensor could detect the bar's rotation. The hall effect sensor basically acted like an ultra-low resolution encoder, but worked for our purposes. The hall effect sensor was an A2340LUA-T which is stocked in the mechatronics lab. Its data sheet can be found here.

Hall Effect Sensor Circuit

The graphic at the right illustrates the circuit we used for the hall sensor. There is an LED and 1 KΩ in the hall sensor portion of the circuit. This is just for user feedback. When a magnet is in the vicinity of the sensor, the light will turn on. If that doesn't happen, then the circuit is wired incorrectly.

The circuit outputs HIGH when the hall sensor is engaged and LOW when not. However, a hall effect sensor is an analog device. We needed it to output either high or low and not voltages in between. To solve this problem, we used a LM311D voltage comparator. This chip is basically a really fancy op-amp. It's data sheet can be downloaded here.

We used the comparator to compare the voltage coming from the hall sensor against some variable threshold which we set. The inverting input of the comparator was connected to the output of the hall sensor and the noninverting input was connected to a 10 KΩ potentiometer. By playing with the resistance of the potentiometer, we were able to set the comparator to the correct sensitivity level. A pull up resistor was connected to the output so that the comparator had sensible outputs. That is, we wanted the comparator to output HIGH when the LED was on (and thus when the magnet was near the hall sensor) and not the other way around.


Solenoid Circuit

Circuit to drive Solenoids

All the solenoids we used on the Wiitar are stocked in the mechatronics lab. These solenoids are rated at +12 volts. The power supply in our mechatronics kit could supply that voltage, but the PIC could not output enough current to drive the solenoids with force required to press the guitar strings. To overcome this, we used an NPN Darlington Pair transistor. The part number is 2N6045 and its data sheet can be downloaded here.

The circuit we used can be seen at the right. Using the transistor to increase the current through the solenoid, we were able to successfully drive the solenoids with the PIC. The output from the PIC was connected to the base of the transistor. The solenoid was connected between power and the collector. The emitter was grouned. There is a 100 Ω resistor between the PIC and the base of the transistor to produce a voltage potential. We used a 100 Ω resistor because we wanted as much current to go into the base as possible. More current into the base means more current through the solenoid and thus more force produced by the solenoid.

An important note is the suppression diode in parallel with the solenoid. Remember, a solenoid is basically like an inductor. When the voltage is shut off, the inductor still wants to emit current. To prevent the transistor from being on, even after the PIC was outputting a LOW signal, a 1N4003 diode was placed in parallel with the solenoid.

Our Wiitar used 6 solenoids and thus this circuit was produced 6 times on our protoboard.


Note: When assembling these circuits it is important to keep a common ground with the PIC. Without a common ground, the PIC may confuse digital HIGH LOW signals.



Code

There are two separate sets of code for the Wiitar. One set runs on the laptop and is the interface between the wiimote and the PIC. The IDE we used was Code::Blocks. It's open source, multi-platform and very easy to learn. It can be downloaded here. This code connects the wiimote to the laptop. Remember that the computer code will only work if there is a bluetooth stack present on the laptop. If the laptop does not have built in bluetooth, a bluetooth dongle may be used instead.

The other set of code used is downloaded directly on to the PIC using MPLAB. To learn more about the use of this program see the Getting Started with PIC32 page. The code downloaded to the PIC recieves signals from the computer and outputs digital signals and a PWM signal to control the actuators on the guitar.


Overview

The code used for the Wiitar is relatively simple. The wiimote talks to the computer through wiiuse.c. The computer then talks to the PIC using transmit.c. The transmit code runs on the PIC and the wiiuse code runs on the PC. The structure of the code is as follows:

  • An event occurs on the wiimote. This can be a change in the accelerometer orientation, a button pressed or a button released
  • The computer recognizes this event and sends a character to the PIC via RS232
  • The PIC receives the signal and either activates digital outputs or the PWM signal.


Notes about Wiiuse

The code used to talk to the Wii was downloaded and modified from www.wiiuse.net. The download section includes the wiiuse.h header file, a custom header file that formats all the outputs from the wiimote and includes easy to use functions. This can be downloaded here. Included in the zip file are the header file, and a few .dll files. These dynamic link library files allow the code to interact with Windows, but can prevent wiiuse from operating correctly on UNIX systems. Code::Blocks makes it easy to link these files to a project. Once a new project has been created, go to Project-->build options. A dialog box will appear and click on the Linker Settings tab. There is a link libraries window. Click the add button and direct the program to look where the .dll files are. When the program asks if you want to add it as a relative path, click No. The .dll file should be linked to the project.


Computer Code

The first part of the computer code deals with buttons being pressed on the wiimote. Each time a user presses a button, it constitutes as an event. Unintuitively, when a user releases a button, that also constitutes an event.

// If a button is pressed, report it and send appropriate signal to PIC
 printf("\n\n--- EVENT [id %i] ---\n", wm->unid);
	if (IS_PRESSED(wm, WIIMOTE_BUTTON_A)){
		printf("A pressed\n");
		buttonPressed = 'A';
		WriteFile(serial_port, &buttonPressed, sizeof(char), &bytes_written, NULL);
		printf("%d bytes (char = %c) successfully transferred to PIC!\n", (int) bytes_written, buttonPressed);

IS_PRESSED is a built in function in the wiiuse.h file that lets you point directly to the various buttons. This part of the code says if a user presses the "A" button, print a message saying so and then send the character "A" to the PIC. Finally, it prints a message indicating successful data transmission. The WriteFile function will be discussed in detail later. Several of these if statements are in wiiuse.c, specific to every button on the wiimote. For our code, we only use buttons A, B, 1 and 2.


A similar function is used when users release a button.

//If a button is released, print it and send 0 to PIC
	if (IS_RELEASED(wm, WIIMOTE_BUTTON_A)){
		printf("A Released.\n");
		buttonPressed = 'N';
		WriteFile(serial_port, &buttonPressed, sizeof(char), &bytes_written, NULL);
		printf("%d bytes (char = %c) successfully transferred to PIC!\n", (int) bytes_written, buttonPressed);

IS_RELEASED is another built in function. We need these statements so that the PIC knows that the "A" button is not being pressed anymore. This portion of the code prints a message when a user releases a button and sends the character "N" to the PIC via RS232. The code then prints a message indicating successful data transmission.


By default, the code does not monitor accelerometer values. This is simply to conserve battery life. If we want to monitor the accelerometers in the wiimote, all we need to do is press the ONE button. To turn the accelerometer off again, simply press the TWO button.

// Accelerometer Info: Pressing two will tell the Wii Mote that we are interested in movement	
	if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_TWO))
		wiiuse_motion_sensing(wm, 0);

// Accelerometer Info: Pressing one will tell the Wiimote athat we are no longer interested in movement.  This may
// be useful for conserving batterly life.  
	if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_ONE))
		wiiuse_motion_sensing(wm, 1);

IS_JUST_PRESSED is another built in function. This function changes based on the button that was just pressed. In this case, we are using the ONE and TWO buttons to toggle the accelerometer. For our project, we only used pitch. The image below shows what orientation of the wiimote pitch corresponds to.

wiimote pitch orientation


Now we need to set some threshold so that the strummer knows when to activate. The if loops below do this.

// If the accelerometer is active, print the appropriate angles.  We only used pitch in our code, but if you want to use the other
// orientations, uncomment them.  
	if (WIIUSE_USING_ACC(wm)){
		//printf("wiimote roll  = %f [%f]\n", wm->orient.roll, wm->orient.a_roll);
		printf("wiimote pitch = %f [%f]\n", wm->orient.pitch, wm->orient.a_pitch);
		//printf("wiimote yaw   = %f \n", wm->orient.yaw);
		
		// If the Wiimote is tilted beyond 50 degrees or -100 degrees, then send data to the PIC, indicating that we want the motor to spin
		if((wm->orient.pitch > 50) | (wm->orient.pitch <-100)){
            motor_signal = 'S';
			WriteFile(serial_port, &motor_signal, sizeof(char), &bytes_written, NULL); // Sends the data
            printf("%d bytes (char = %c) successfully transferred to PIC!\n", (int) bytes_written, motor_signal);
				// Prints a message to indicate successful data transmission
		}
		
		// Once Wiimote has been brought back to horizontal, the system has been "reset" and the user can restrum the guitar
		else if((wm->orient.pitch > -25) & (wm->orient.pitch < 25)){
			motor_signal = 'T';
			WriteFile(serial_port, &motor_signal, sizeof(char), &bytes_written, NULL); // Sends a "reset" message
			printf("%d bytes (char = %c) successfully transferred to PIC!\n", (int) bytes_written, motor_signal);
				// Prints a message to indicate successful data transmission
		}
	}

WIUSE_USING_ACC(wm) will return 0 if the accelerometer is disabled or 1 if the accelerometer is enabled. Assuming the accelerometer is enabled, the code will monitor the accelerometer and not do anything until the wiimote is tilted above 50 degress or below -100 degrees. The accelerometers report absolute values. That is, the closer you tilt the wiimote upwards to vertical, the more positive the numbers become. The thresholds we set were determined from just playing around with the wiimote and observing the accelerometer values. When the wiimote passes one of these thresholds, the character "S" is sent to the PIC. When the wiimote is brought back to a roughly horizontal position, the computer sends the character "T" to the PIC. These values will all make sense when the PIC code is discussed. Note that there are two different pitch values. There is an absolute pitch value and a corrected pitch value. The corrected pitch value can be changed by altering the sensitivity in the wiiuse.h file. We did not change this because we thought the sensitivity of the accelerometer was okay.

Writing to the PIC involved sending data via an RS232 cable through a COM port. The process involved in writing to a COM port in a Windows environment is cumbersome. Aggravatingly, this whole process could have been avoided if a UNIX based OS was used, as all the COM port information is kept in the dev folder. Unfortunately, the wiiuse code does not work on UNIX systems because of its dependency on .dll files. The steps to send data through a COM port are:

  • Create a handle to point to the serial port
  • Initialize the serial port
  • Open the serial port
  • Write the data to the serial port
  • Send the data
  • Close the port

The portions of the code that do this are scattered throughout the entire wiiuse.c file. But the most important chucks of the code are

	HANDLE serial_port;				/* Handle to the serial port */
	long baud_rate = 9600;		    /* Specified baud rate */
	char port_name[] = "COM7:";		/* Name of the serial port */  

 //Initialize Serial Port ------------------------------------------------------------
	
	/* Open up a handle to the serial port */
	serial_port = CreateFile(port_name, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);

	/* Make sure port was opened */
	if (serial_port == INVALID_HANDLE_VALUE)
	{
		fprintf(stderr, "Error opening port\n");
		CloseHandle(serial_port);
		exit(0);
	}

	/* Set up the serial port */
	set_up_serial_port(serial_port, baud_rate);
	
//End Serial Port Initialization ----------------------------------------------------

These commands are all located at the beginning of main().


The WriteFile() function has several inputs, all of which are somewhat confusing.

WriteFile(
  __in         HANDLE hFile,
  __in         LPCVOID lpBuffer,
  __in         DWORD nNumberOfBytesToWrite,
  __out_opt    LPDWORD lpNumberOfBytesWritten,
  __inout_opt  LPOVERLAPPED lpOverlapped
);
  • HANDLE hFile: hFile is the handle that points to the COM port. In our case it's called "serial_port"
  • LPCVOID lpBuffer: lpBuffer is a pointer to the buffer containing the data that's to be written. In our case it's "buttonPressed" or "motor_signal" depending on the application
  • DWORD nNumberOfBytesToWrite: The number of bytes to be written to the device. Since we're sending characters, it's 1 byte and the variable is "sizeof(char)"
  • LPDWORD lpNumberOfBytesWritten: A pointer to the variable that receives the number of bytes written when using a synchronous hFile parameter. In our case it's just "&bytes_written"
  • The rest of the parameters are just NULL because they aren't used.


PIC Code

The code for the PIC is not as complicated as the wii code. Basically, all the PIC needs to do is monitor a UART port and based on the data it receives and either set digital outputs to HIGH or LOW, or enable the PWM. The UART stuff is all handled by an interrupt service routine (ISR).

// UART 2 interrupt handler and is set at priority 7
void __ISR(_UART2_VECTOR, ipl7) IntUart2Handler(void)
{
	// Is this an RX interrupt?
	if(mU2RXGetIntFlag())
	{
		// Clear the RX interrupt Flag
	    mU2RXClearIntFlag();

		data = ReadUART2(); // Read data in the UART
		
		if(data == 'A')
		{	
			mLED_0_On();
			PIN_D4 = 1;
			PIN_D3 = 1;
			PIN_D10 = 1;
			PIN_D9 = 1;
		}
		else if(data == 'B')
		{
			mLED_1_On();
			PIN_D8 = 1;
			PIN_D9 = 1;
			PIN_D11 = 1;
 		}
     		else if(data == 'D')
		{
			mLED_2_On();
		}
		else if(data == 'L')
		{
			mLED_3_On();
		}
		else if(data == 'S' && dummy == 1) 
		// When the first "S" is sent to the PIC, the dummy variable resets, so the sturmmer doesn't constantly strum.
		// We only want the strummer to strum once and this is what the code does. 
		{
			DIRECTION_PIN = 0;
			ENABLE_PIN = 1;
			mLED_3_On();
			dummy = 2;
		}	

		else if(data == 'N')
		{
			mLED_0_Off();
			mLED_1_Off();
			mLED_2_Off();
			mLED_3_Off();
			PIN_D11 = 0;
			PIN_D3 = 0;
			PIN_D4 = 0;
			PIN_D10 = 0;
			PIN_D9 = 0;
			PIN_D8 = 0;
		}
		else if(data == 'T')
		// Resest the dummy variable when the Wiimote is brought to horizontal so the user can strum the guitar again.
		{
			dummy = 1;
			mLED_3_Off();
		}

	}
	// We don't care about TX interrupts
	if(mU2TXGetIntFlag())
	{

	}
}  

The code may look long, but the theory behind it is very simple. Depending on what character is read from the UART, some pins will ether be HIGH or LOW. For example, when the "A" character is read from the UART, pins D4, D3, D10 and D9 are all turned HIGH, and their corresponding solenoids are depressed. The layout of the solenoids correspond to a G chord. When the user releases the "A" button, the character "N" is sent, which sets all the pins back to LOW. The character "N" is like our "off" switch.

One confusing detail in the code involves the strummer. The computer is monitoring the wiimote constantly, so when the accelerometer is engaged data is constantly being streamed to the PIC. When the user brings the wiimote into the "strumming zone" lots and lots of "S" characters are sent to the PIC. We don't want this. We only want the PIC to react after the first "S" is sent. To solve this problem we use a dummy variable, aptly called "dummy." This variable is initially set at 1. When the first "S" is sent to the PIC, the IF loop corresponding to character "S" and dummy = 1 is executed. Note that in the "S" loop "dummy" is set to 2. Only when the user brings the wiimote back to horizontal does the dummy variable get reset back to 1 (the IF branch that corresponds to this is the one with IF data = 'T'). Thus moving the wiimote like you would strum an actual guitar translates to the strummer only playing intermittently, simulating a guitar. This was tested pretty rigorously and seemed to work pretty well, though sometimes the "T" would not get sent and thus the strummer would seem to lag.

For reasons not known, the Delayms() function (included in LCD.h) did not work with our code, so we made our own. This delay function counts NOPs instead of using a dummy counter variable. The code for this can be seen below.

//********************** Counts "Nops" so that we can use them as a delay function, instead of the Delayms function built into "LCD.h".
void Delayms( unsigned t)
// This uses Timer 1, can be changed to another timer. Assumes FPB = SYS_FREQ
{
	int i=0;
    for (i=0;i<t;i++)
    {  // t x 1ms loop
        Nop();
	}
}

The only code that is in main() involves monitoring the hall sensor. One pin, A10, was coded as a digital input and is connected to the output of the voltage comparator. Recall, when the hall sensor is on, the comparator outputs HI and when the hall sensor is off, the comparator outputs LOW.

		// Interrupt to control the CN pin to stop the bar with the hall Effects sensor when it goes low to high
		if(INPUT_A10 == 1)
		{	
			DIRECTION_PIN = 1; // When the Hall Effects sesnsor gets tripped, delay and reverse the motor by the following commands
			Delayms(200000);   // Delay
			DIRECTION_PIN = 0; // Reverse the motor
			ENABLE_PIN = 0;    // Brake the motor
			
		}

This IF loop brakes the motor after the hall sensor is tripped. The set up of our strummer has the strummer end up in roughly the same place every time. The weight of the strummer is unbalanced due to the magnet at one end and thus after the motor brakes, it settles down to approximately the same place.


To Sum Up

To sum up, the functionality of the code follows these steps:

  • When a user presses a button or tilts the wiimote, characters are sent via RS232 to the PIC
  • The PIC reads the UART port and depending on what the character is, sets particular pins HIGH or LOW
  • Moving the wiimote in a strumming fashion simulates a guitar because the PIC only reacts to some of the accelerometer data it receives



Results and Reflections

When we first envisioned the Remote Controlled Wiitar, we wanted to create a system that could play many different chords and songs very easily. We originally wanted an array of eighteen solenoids (one for each string on the first three frets) that would allow us to play dozens of chords and thousands of songs. Our final project had only six solenoids and could play a grand total of three chords.


Despite a creating a system that was simpler than intended, our project was very successful. At the beginning of the quarter, we had some knowledge of electronic circuitry, almost no knowledge of microcontrollers, and no experience programming in C. Using knowledge that we gained throughout the quarter, we were able to design and build a system that was fun for anyone to use and could control a guitar using a Wii Remote.


There are many things that we could have done to improve our project. Perhaps the largest problem we encountered was the fact that the smallest solenoids available to us were too large to fit more than a couple solenoids per fret on the guitar. This was the main reason for the simplification of the solenoid array from eighteen solenoids to only six. To fix this problem, we could have positioned the solenoids away from the neck of the guitar and used a system of levers to push the guitar strings. This would have allowed us to depress more strings and enabled us to play more chords.


Another improvement would be made to the strummer. We wanted to be able to strum the strings up and down, but our final system could only strum down (from the lowest string to the highest). This was primarily an issue of feedback. We decided early in our project that we did not need the resolution of an encoder to control the strumming bar, so we opted for a hall effect sensor instead. We quickly realized that there was significant overshoot when using the feedback from the hall effect sensor that prevented us from being able to strum the strings in both directions. Had we used an encoder, we would have had better control over the position of the strummer and we would have been able to strum both up and down.


It was also suggested that we add a "player piano" mode to our system. This mode would have had the PIC automatically play a song using timed strums and chord changes without input from a Wii Remote. Due to a number of other issues we were having with our project, we did not have time to add the player piano mode. This would have been a great addition to the system that could have really demonstrated its capabilities.


Over the course of building our Wiitar, we burnt out one PIC. We noticed that when the PIC was powered on it was getting very hot, even when it was completely disconnected from the rest of our circuit. We could not find the cause of this, but we suspect that something on the PIC board was shorting. When a new PIC was placed into the circuit, the system returned to functioning properly.


Despite having little experience in electronic design or programming, most of our issues were a result of mechanical problems. The underlying circuitry and code functioned exactly as originally planned. Coding entirely in C, we were able to receive signals from a Wii Remote on a computer, relay those signals to our PIC using RS232 communication, and have the PIC depress appropriate guitar strings and strum a guitar. Learning how to do all of this and applying it to our project was our greatest success.

Personal tools