Thursday, November 17, 2016

Star Spangled Banner using a Floppy Disc and Moppy

Figure 1
Just a little fun project to attempt to play music with a floppy drive.  There are great directions online for how to do this in various locations.  I originally worked with a stepper motor and developed an Arduino sketch which played the Star Spangled Banner.  The trick to generating a note with a stepper motor is causing the stepper to step with a frequency which matches a musical note.  The timing between steps (the period) is the reciprocal of a frequency (Hz).  If the frequency is between 20 Hz and 20kHz, the human ear can hear it.  In practice, I used frequencies from middle C (C4, 261Hz) to an octave and a half above or G5 (784 Hz) which is the range for the Star Spangled Banner in the key of C.
The Arduino function "note" in Figure 1 calculates the period for a given frequency, and then plays that note.  I have borrowed this code from Arduino Forum user "raschemmel" as published on this website:  https://forum.arduino.cc/index.php?topic=343270.0.

Figure 2

I setup a big array containing notes in the first row, and durations in the second row.  The notes and durations were defined in musical terms making transposition from sheet music relatively painless although tedious (Figure 2).  The full array defining the song can be found in Github with the rest of the Arduino sketch.  Finally, playing the song itself is as simple as a double "for" loop which iterates over the columns of the song array and plays the note for the duration specified in the second "for" loop.  I'm proud of the simplicity of the loop function (Figure 3).  I also included two scalar variables (tempo and pitch_multiplier) which modify all the duration variables (tempo) or pitch variables (pitch_multiplier) allowing for transposition and tempo control.

Figure 3
While this setup worked, the volume of the stepper was too quiet even when I mounted it on a large piece of metal to use as a resonator.  I played around with a piezoelectric pickup and an amplifier circuit (see descriptions later in this post), but the piezo picked up too much vibration noise from the motor and sounded pretty awful.

I stumbled on Moppy, which seems to be the most popular way of playing music from an actual floppy drive.  The principle is presumably similar to my Arduino sketch, except that you feed it a midi file (the equivalent of my array) and it provides a clean Java based user interface.  In addition, Moppy supports multitrack midi files so that you can play different "voices" with different floppy drives.

Setup of the floppy was pretty easy once I figured out which pins to connect to the Arduino (Figures 4 and 5).  
Figure 4
Figure 5
I modified an existing Star Spangled Banner midi file to leave only the melody line using the program Anvil Studio.  The result is shown in the Youtube video below.
Figure 6

Finally, I used an LM386 chip to breadboard an amplifier circuit driving a small 8 Ohm speaker with the piezoelectric pickup mounted on the case of the floppy drive (Figures 7 and 8).  The circuit was adapted from CircuitBasics.  This worked much better than mounting the piezo directly on the stepper, and compounded with the fact that the floppy was much louder than the stepper, I was able to record a decent rendition of the song.  I will be playing the video at the opening ceremony of a robotics tournament which my school is hosting.

Figure 7

Figure 8


I made a PCB board (Figure 9) for a semi permanent installation of this circuit.  The EagleCAD files are located here:  https://github.com/gcronin/StepperTest/tree/master/LM386%20Amp.


Figure 9
I made a JFET board (Figures 10-11) which was designed by Cafe Walter (http://www.cafewalter.com/cafewalter/fetpre/) and is open source!  Thank you so much!!!  The schematic for this circuit can be found here.  The Eagle CAD files for my version of this board can be found here.  

Figure 10

Figure 11

Monday, November 14, 2016

Animatronics Demo with VSA

https://www.youtube.com/watch?v=J2nnmYpLG8Q&feature=youtu.be
Figure 1
Visual Show Automation (VSA) is a software package which coordinates movement, lights, sound and video.  The demo version is free at available from Brookshire Software, however it does not allow you to save files.  I learned about this software from a colleague who had done a basic automation project and used this website as a starting point:  http://animatronicsworkshop.com/.

The process involves making characters which are animated by use of servo motors, recording a script, and then using the VSA software to sync up motion of the servos to the songs in the audio. IMPORTANT:  if you are using the demo version, make sure the Arduino is connected to the computer before you run the software.  Otherwise, you will need to restart the software and you will lose all of your work.  The simple demo that is linked above using two servos and a relay to control a red light (Figure 1).  The setup is done through Tools -> Settings.  Use the audio tab to import an audio file (Figure 2).  
Figure 2

Figure 3
Under the Device Settings tab (Figure 3), choose Disable All from the dropdown menu in the lower left corner, then reselect only those tracks that correspond to pins that you have servos or relays plugged into on your Arduino.  For example, I used two servo motors with the control wires plugged into Arduino pins 2 and 5.  I plugged the base of a transistor controlling a relay into pin 8.  Rename the device with a logical name in the second column.  The 3rd column will remain MiniSCC Servo if you are using a servo attached to an Arduino, or MiniSCC Relay if you are driving a relay using an Arduino.  The fourth column needs to be the COM port that the Arduino is using.  The Default (8th column) will be the starting point for the servo or relay.

From this point, when you go back to the main screen, you will see the audio waveform in the bottom.  There is a tool which will automatically synchronize the motion of a servo to amplitude of the waveform.  This can be found under Tools -> Waveform Analysis.  For this demo, I entered servo and relay values manually.  

Figure 4
For a servo, if you drag your mouse in the row which corresponds to the servo in the top pane, you will create a servo motion event (Figure 4).  You can move the "dial" on the left to adjust the Stop Position; the servo will move in real time.  When it is in the correct position, either click on Capture or manually enter the number on the left (not the angle) into the Stop Position field on the right.  The Start Position is set by the previous motion event, or by the default position for the starting point. You can roughly sync up the motion to the sound waveform as you will see vertical timelines as you drag your mouse to create the event.  You can drag the event to move it, or change the beginning or end times by placing your mouse over the beginning or end of the event. 
Figure 5

A relay works pretty much the same way (Figure 5), although you only have options for on (1 output) or off (0 output).   Put a 1 or a 0 in the field which is called Pulse Value.

You can copy and paste, or select different events by using the right mouse button in the top window.  My demo is very repetitive, which was done using copy  and paste functionality.  It takes a bit of practice to get used to the interface... if you are used to dragging with your left mouse button, you will find that you are creating events instead of selecting.

Figure 6
The finished view for my demo is shown below (Figure 6).  There are three sets of rectangles in the top pane which correspond to the events for the two servos and the relay.  We can see the values which go with those events in the second pane, where I have used the scale and offset arrows to separate the three devices so they don't lie on top of each other.  The bottom pane shows audio.   To run your creation, use the buttons in the top right corner.  The fourth one loops through the program over and over until you stop it.

On the Arduino side, the software which allows the Arduino to act like a MiniSCC is available here: http://animatronicsworkshop.com/?page_id=458.  I tailored this sketch slightly to allow it to work for relays as well.   The full sketch can be found on github.  The picture below shows the modifications to the original sketch.


Here are a couple links to animatronic videos that were made in a class I teach.  These were made without VSA, and I hope that future projects are of even higher quality.



Monday, September 12, 2016

T-shirt Cannon


CLICK ON THE PICTURE FOR DOCUMENTATION

Addendum... The T-shirt cannon now has an airhorn!


I figured this would be a good addition both for the impact and also for safety.  I purchased a couple kits from Amazon, this one and this one, the first as the original and the second when the plastic horns from the first kit broke.  The kits come with three parts... the horns, an electronic compressor, and a relay.  I thought the kit was broken because when I wired the compressor to 12V through a momentary switch and pressed the switch, no sound came out.  The compressor made a weak noise like it was a small outboard motor, but that was it.  The wires also got very hot.

I wired up the product in the manner instructed which uses a relay activated by a momentary switch to drive the compressor.  This diagram in Figure 1 shows how this wiring is done (taken from a video on youtube)
Figure 1
Figure 2
This worked well.  Next, I wanted to remove the human from the equation and automate the air horn.  I used a transistor in place of the momentary switch to turn on the relay.  A 2N2222A NPN transistor with a 220 Ohm resistor wired to the base is driven by the output of the Arduino Mega 1280 "brain" of the T-shirt cannon.  I fabricated a custom PCB board, the layout of which is shown below in Figure 2.  A diode, an LED/resistor, and the relay (pins 85 and 86 of the automotive relay) are in parallel between 12V and the transistor.  When the transistor is turned on, the relay is activated, and the LED turns on.  The flywheel diode takes up any reverse EMF generated when the magnetic field of the relay collapses, and thus protects the transistor.  Eagle CAD files for the PCB are available here.

Figure 3 shows the actual automotive relay and the pins labelled for reference/troubleshooting.
Figure 3
Figure 4 shows the layout of wiring on the actual T-shirt cannon (again for reference).
Figure 4



Wednesday, September 7, 2016

Pong Game: Joystick Controlled

This version of the Pong Game builds on the previous, but the paddles are controlled by a logitech controller's two joysticks.  This version of the game is for two players, each of which control one of the joysticks.  The game keeps track of the number of times that the ball has hit each player's paddle and displays this score on the screen.

Currently the program does not end nicely; there is a Null Pointer Exception which terminates the run when the ball runs off the edge of the screen.   I am not sure on the source of the exception.

The video below shows the game being played.

Much of the code is the same as the previous post including the classes Ball, Paddle, and ButtonListener.  The class Listener is similar, but now the mouseMoved method doesn't do anything.  GamePanel now includes two more labels which display the player's scores (scoreLabel1 and scoreLabel2).  It is also passed a JoyStickController object which gives axes to the method GetYAxesValues and the variables Y1Value and Y2Value which contain the most recent values of the two joysticks on the Logitech Controller (more on that below).


The picture shows that the left and right paddles' ycor variables are set to increase with the value of the left and right joysticks on the Logitech controller (respectively).  So if the left joystick is centered (Y1Value is zero), then leftPaddle.ycor stays constant.  If the left joystick is pressed up, then Y1Value is negative and leftPaddle.ycor decreases causing the leftPaddle to move up on the screen (recall that the y-coordinate increases as you move down the screen).  If the left joystick is pressed down, then Y1Value increases and the leftPaddle moves down the screen.  The multiplier *20 just makes the paddles move at a reasonable rate.

The class JoystickController includes two methods, SetController and GetYAxesValues.  The first method is called once when the main method of the PongGame class is run, and it scrolls through all the attached devices looking for one of type "Stick" .  It then sets a local variable (logitech) of type Controller to be that device.

The GetYAxesValues method calls a Controller method called poll, then sets an array called components to include the names of each of the parts of the Logitech controller.  It scrolls through the components array until it finds the array element called "Z Rotation" then stores the value of that component using getPollData in Y1Value.  Similarly, it stores the value of "Y Axis" in Y2Value.  Each value is subjected to a deadband, so that if the value is between -0.1 and 0.1 it is set to 0.

In the PongGame class, most everything is the same, but the main method now just creates an instance of PongGame, then called two methods (setupPlayers and initializeGame).  This is a much more elegant way compared to the mouse version, which does all the work in the main method.

Full game code can be found here:  https://github.com/gcronin/PongGame/blob/JoystickControl/PongGame/src/ponggame/PongGame.java .

Tuesday, September 6, 2016

NXT Security System

MIT App Inventor 2 is a great tool to develop Android apps.  It also has some robotic functionality as there is built in support for LEGO NXTs and EV3s.  I just finished a very small test program to try out this functionality.



I wrote an app which uses a light sensor and sound sensor on an NXT to simulate detecting an intruder. The light sensor normally has a laser pointer flooding the input, but if something crosses the path of the laser, the light reading drops much lower. This triggers an alarm which is indicated by a moving motor, a beeping sound, and a visual indicator ("Alarm!") on the Android phone. Similarly, a sound above the threshold (set at 125) on the sound sensor trips the alarm. The Android interface allows you to turn on and off the alarm, shows the values of the sound and light sensors, and shows whether you are connected to the NXT.

When creating an app in MIT App inventor, you first create the interface (Designer) then create the code (Blocks).  Coding is drag and drop just like Scratch or Enchanting.   The interface for this app is shown below:

There are several button to connect and disconnect to an NXT over Bluetooth, and to turn on or off the security system.  There are also several NXT specific objects: an NXT Sound Sensor, an NXT Light Sensor, and an NXT Direct Commands (which gives access to motor control).  A clock is setup with a one second increment.  Finally, there are several "labels" which are places where text is displayed.  One label (status) shows whether the alarm is on, off, or triggered.  Another label (SoundReading) shows the sound sensor reading or "not connected" if there is no Bluetooth connection.  The last label (misnamed UltrasonicReading from previous experiments) shows the light reading or or "not connected".

The coding is all event driven.  Events can be triggered by pressing a button on the App interface, by a recurrent timer, or by certain sensor criteria being met.
The Connect to Robot and Disconnect buttons give Bluetooth functionality.  When you click the Connect To Robot button (which is actually a list picker), it brings up a list of available Bluetooth devices.  When you select one, the App makes a connection to that NXT.  The Disconnect button ends that connection.

Two global variables are used to control whether the alarm is on (on?), and whether it has been triggered (AlarmTripped?).  The OnButton sets on? to true.  Once that criteria is met, either a NXTSoundSensor.AboveRange or a NXTLightSensor.BelowRange event can make the second variable (AlarmTripped?) true.

A clock event is triggered every second.  This event displays the sound and light sensor readings if there is a Bluetooth connection.  Otherwise it displays "Not Connected".  If the value of AlarmTripper? is true, it plays a tone, and spins a motor.  Because the duration of the tone is half of a second and the clock event is triggered every second, the overall aural effect is a periodic beeping sound which sounds like an alarm.

The OffButton resets both global variables to false and stops the motor.

Overall, this was a simple but great way to learn MIT App Inventor 2.  The project has been published on the App Inventor 2 website:  http://ai2.appinventor.mit.edu/?locale=en#4626597671075840.


Monday, August 29, 2016

Pong in Java: Mouse Controlled Paddle

The previous post discussed command line Java.  I went a little deeper to make two versions of the classic game Pong.  This first one uses the mouse to control one of the paddles.  The other paddle is controlled automatically by the computer.


Java is an object oriented language.  Pong lends itself to programming in this manner because the game is based on objects... specifically a ball and two paddles.  Objects in Java are instances of a class.  A class can contain its own variables, own methods (functions), and requires a constructor which describes how an instance of the class should be created.  For example, the following is the class for a ball:

Each instance of the Ball class has an x-coordinate, y-coordinate, heading, speed, and a diameter.  The diameter is always the same, but the other variables are set when the Ball instance is created.
Elsewhere in the program, an instance of Ball called "ball" is created using the command:

Ball ball = new Ball(200, 100, 30, 10);

The constructor assigns the variables for "ball" (eg its xcor equals 200, etc).

There is also a method for the Ball called "move", which changes the values of xcor and ycor depending on the Ball's speed and heading.



Another object is a Paddle.  The following is the class for a paddle.


This class is similar in many ways to a ball; it has several variables which describe its geometry, but it also interacts with a Ball, and so one variable describes a property of a Ball.

The constructor requires an instance of a Ball to be passed to it:

Paddle leftPaddle = new Paddle(0, 100, 20, 100, ball);

This is important because the "overlaps" method for a Paddle checks to see if the middle of the ball (ballycor + ballDiameter/2) is below the bottom of the paddle (this.ycor + height) or above the top of the paddle (this.ycor).  The relevant geometry is shown below.


The real action for the game happens in the GamePanel class, which includes the methods "paintComponent" and "animate".  "paintComponent" colors two rectangles and an oval at the locations of the left and right paddles, and the ball.  When an instance of GamePanel is created, the constructor requires two Paddles and a Ball.  paintComponent is a method of the class JPanel.  GamePanel extends JPanel, and I have overridden the default method paintComponent.



The "animate" methods causes the ball to move, to deflect off the upper/lower values, and to deflect off of a paddle.  It also causes the right paddle to have the same height location as the ball: rightPaddle.ycor = ball.ycor - rightPaddle.height/2;

The deflection works as follows:  we first check if the ball is within the paddle's width of the left side of the JPanel:  if( ball.xcor  < leftPaddle.width). If so, we want to know if the ball's y-coordinate overlaps with the location of the left paddle.  If so, we do some fancy math to change the heading of the ball so it looks like it bounced off the paddle.   Note that this code does not currently end the game if the paddle and ball don't overlap... the ball goes off the screen to the left, but then it will eventually "bounce" offscreen because the original "if" statement is still true, and the ball will "overlap" with the paddle at some point.  This is a bug.

Next we check to see if the ball is within the paddle's width of the right side of the JPanel:

if(( ball.xcor + ball.ballDiameter)  > getWidth() - rightPaddle.width).  

getWidth() is a built in method for a JPanel which returns the width of the JPanel.  If so, we then check to see if the ball's y-coordinate overlaps with the location of the right paddle, in which case the ball's heading is changed to Pi minus its original heading.

Finally, we check to see if the ball is either at the top of the JPanel (ball.ycor < 0) or at the bottom of the JPanel (ball.ycor > getHeight() - ball.ballDiameter).  In either case, a vertical bounce is done by making the original heading negative.

The class Listener allow the user to interact with the game through the mouse.  Listener implements the interfaces ActionListener and MouseMotionListener.  The latter gives us access to the methods mouseDragged and mouseMoved.  I only use mouseMoved (although you have to override mouseDragged ...my method for mouseDragged does nothing).



When the mouse if moved, it triggers a MouseEvent called e.  We can read the vertical location of the mouse (e.getY()) and then we position the left paddle accordingly.  If the mouse is at the bottom or below the JPanel, the left paddle stays at the bottom of the JPanel.  If the mouse is at the top or above the JPanel, the left paddle stays at the top.  Otherwise, the position of the paddle is set according to the vertical location of the mouse:

gamePanel.leftPaddle.ycor = e.getY() - gamePanel.leftPaddle.height/2;






The ActionListener interface includes the method actionPerformed, which is invoked anytime an action occurs.  Actions are occurring all the time, and so this method occurs constantly.  I have overridden the method to have it call the GamePanel.animate method discussed above.







There is another ActionListener called ButtonListener which includes a timer which is started and stopped by two buttons in the main JPanel, called startButton and stopButton.









The main class for the pong game is a JFrame class called PongGame.  It has no constructor and no instances; everything in the class occurs in the method main.  Main creates a JFrame with two JPanels.  The "top" JPanel (called settingsPanel) includes start and stop buttons.   The other JPanel is the gamePanel already discussed.

In main, we create the ball and two paddles for the left and right sides of the screen.  We create a timer which runs when the start button is pressed and stops when the stop button is pressed.  We create an instance of ButtonListener. We create a Listener so we can have the game animate and detect mouse movement.

I am still confused by aspects of the code.  I know that they work but I just stole them from online.  In particular, these lines are tough:

           Listener listener = new Listener(gamePanel);
      Timer timer = new Timer(50, listener);
      gamePanel.addMouseMotionListener(listener);
      gamePanel.requestFocusInWindow();
   
      ButtonListener buttonListener = new ButtonListener(startButton, stopButton, timer);
      startButton.addActionListener(buttonListener);
      stopButton.addActionListener(buttonListener);


The PongGame class is shown below:
Full code for this game can be found here.

Learning Java: Command Line and LeJos

FIRST switched to Android Studio for robotics coding for the 2015-16 season.  Android Studio is a Java based platform used to create Apps for Android phones.  I spent part of last summer trying to get up to speed with Java.  Rather than dealing with Android Studio (which is a whole different can of worms), I worked with command line Java, and then with Java in NetBeans.

The command line programs described below are on GitHub at https://github.com/gcronin/LearningJava.

Program 1: Parabola
This program uses the scanner to take in  the coefficients of a parabola written in standard form, and converts to vertex form.












Here's an example of the output; the parabola y = x^2 + 2x + 5 is equivalent to y = (x+1)^2 + 4 with a vertex at (-1, 4).



Program 2: Distance Formula
Using the scanner again, the user inputs the x and y coordinates of two points, and the program calculates the distance between the points.









Here's an output showing that the distance between (0,0) and (1,1) is the square root of 2.





Program 3: Add Text to a File
This very simple program requires dealing with exceptions, which is a big part of Java.  When you open and write to a file, you must catch two exceptions... the first is given if the file doesn't exist, and the second is given if the program cannot write to the file.  We deal with exceptions by using the Try... Catch syntax.

A much more complex version of this program with user input can be found here (I didn't write it).



Using LeJos:  Java for NXT:
You can program a LEGO NXT in Java.  One of my students setup the compiler for me.  Once LeJos is installed on your computer, you first need to turn .java files into .class files using "nxjc".  Then you need to use "nxjlink" to create an "nxj" file from one of your class files.  Finally, you use "nxjupload" to upload the .nxj file.  In total, this series of commands will do the work for you:

nxjc *.java  //create .class files from .java files
set /p mclass= "Please enter the name of the main class file: " %=%  //chose a .class file
nxjlink -o linked.nxj %mclass%  //create linked.nxj from the .class file
nxjupload -r *nxj   //upload linked.nxj to the NXT


Here are a few Java programs for the NXT:
 This program just prints "Hello World" to the screen until any button is pressed.
This program shows the value of a light sensor attached to port 1 in several different formats.
This program moves motors attached to ports B and C at 50% power.
This program is a line follower using PID control.  I am not sure that it has been tuned correctly, as it was written by a former student.