Skip to main content

more options


Introduction

Several studies have shown that various insects possess learning and memory abilities. One approach researchers use to demonstrate such abilities is to "teach" the insect to exhibit a specific behavior in response to a stimulus. This "teaching" process is called Pavlovian conditioning. Such studies are often difficult to conduct because they require accurate timing of stimuli application and many trials to obtain significant results. In addition, data analysis is extremely tedious.

A system was previously developed at Hoy Lab, under the Cornell Neurobiology and Behavior department, for electronically automating Pavlovian conditioning of an insect species with minimal human involvement (due to confidentiality issues, we are unable to disclose the species at this time). The goal of our project was to improve this system by porting the controller from a National Instruments PCI-6070E data acquisition card, to an Atmel mega644 microcontroller. This involved programing the mega644 to perform time-dependent and sensor driven control of motors, stimuli, and video recording, as well as serial communication between a microcontroller and Matlab graphical user interface (GUI). The resulting system was significantly less expensive and more flexible; however, we sacrificed ADC performance in the process. This was reasonable trade-off since we expect that the mega644 ADC will be sufficient for the future implementation of physiological recording.

High Level

The main rationale of this project is to facilitate a simple and cost-effective means of reproducing conditioning experiments with insects. Previously, a more costly and less flexible solution was in place, using a National Instruments data acquisition card (PCI-6070E) as a controller. The system requires the PCI card, a shielded cable, and a connector block, all of which cost around $3000. In addition, this system only has 8 digital I/O pins which must have their I/O directions set together as a group. Our system replaces PCI-6070E with an Atmel Mega644 microcontroller. Not only is the cost significantly cheaper (around $30), the Mega644 has 32 bidirectional digital I/O pins which can be set individually. This eliminated the need for several ICs in the previous implementation (e.g. the 7400 inverter and 7402 NOR chips) and granted control of additional inputs to step motor ICs, which were formerly hardwired to constant values due to the lack of pins. By switching to the Atmel mega644, we lost the higher performance ADC available on the PCI-6070E. This was reasonable trade-off since we expect that the mega644 ADC will be sufficient for the future implementation of physiological recording. Figure 1 pictures the two controllers.

PCI and PCB

(Click to Enlarge) Figure 1. A picture of the old PCI board (bottom) vs the new protoboard (top).

Our project consists of a GUI, implemented in Matlab, that communicates with the mega644 microcontroller through an RS-232 connection. Mechanically, the automating system consists of a feeding apparatus, insect magazine, and stimuli apparatus. A step motor rotates a feeding station. The feeding station is a plastic disk with one or two syringes containing a sucrose solution used to feed the insects. Another step motor is used to move a magazine which contains several insect restraining mechanisms. Each motor is provided with position feedback through an IR emitter and detector pair. The IR sensors trigger an external interrupt ISR to stop the motors at the appropriate position.

More specifically, for the feeding station, four small plastic slits are attached to the bottom of the disk spaced 90 degrees apart. These slits block IR sensor light and trigger an ISR which stops the motor. The insect magazine works in a similar manner. When the magazine stepper motor moves an new insect into position, it blocks the IR sensor light and stops the motor in front of the feeding mecahnism. The magazine is oriented so that in its stop position, only one insect can be fed at a time. For stimulis application, the mega644 digitally controls two odor pumps and an LED light. Sound stimuli are generated in Matlab. Matlab is also used to control video data acquisition. Figures 2,3,4 and 5 depict the entire system.

high level

(Click to Enlarge) Figure 2. A high level view of the system

whole thing

(Click to Enlarge) Figure 3. A shot of the entire system

Side view of feeder

(Click to Enlarge) Figure 4. A side view of the feeding station.

Magazine

(Click to Enlarge) Figure 5. A closeup of the magazine and insect restraining unit

The Matlab GUI allows the user to design experiments. A typical conditioning experiment consist of moving insects one at a time to a position where it can be fed. Then a neutral stimulus such as odor or sound is applied, simultaneously, behavior is recorded via a video camera. Following the stimulus, the feeder station is rotated so that the sucrose solution is in position for the insects to be fed. After a specified amount of time, the feeder is rotated away, the video recorder is turned off, and the insect magazine is moved forward to repeat the experiment for the next insect. In addition to the conditioning experiment described above, a wide variety of other experiments can be conducted by specifying different stimuli, timing, and trial attributes.

The Matlab GUI communicates with the microcontroller through RS-232 by sending commands that we defined. The microcontroller parses these commands and controls the hardware accordingly. Some examples of commands include setting the motor speed, changing the motor direction, and turning on the odor pump etc. The Matlab GUI is picture in figure 4.

GUI

(Click to Enlarge) Figure 6. A screenshot of the Matlab GUI

The mega644 microcontroller acts as a slave to a Matlab GUI. The GUI allows the user to intuitively design a wide variety of experiments. As depicted in figure 6, the user designs an experiment by entering the start and end time for each event he wants to occur during the experiment. An experiment is defined as the sequence of events that each insect will be individually subjected to. For each experiment, the user must specify the number of trials and number of insects on the magazine. The user is also allowed to perform several different experiments, one after the other, with a specified delay between each experiment. Behind the GUI, a linked list is being created based on the user input as depicted figure 7. Each list is a sequence of chronologically ordered events such as: "get new insect", "feed insect", "stimulate with odor", etc.

fig

(Click to Enlarge) Figure 7. User Experiment Figure

Hardware Design

Stepper Motor Circuit


Both stepper motors (one for the feeding station and the other moving the magazine) have similar circuits. The two main ICs driving the motor are the EDE1200 and the ULN2003A. The EDE1200 is a unipolar stepper motor IC, which outputs timed 5v pulses to drive the motor. The chip has 8 pins which are connected to the microcontroller that control various aspects of the motor. The figure below shows the pinouts for the EDE1200.

EDE1200

(Click to Enlarge) Pinout of the EDE1200 Stepper Motor Control IC.

Pins 6-13 on the IC are connected to the microcontroller on pins 0 - 7. For the feeding station motor, we used port A of the Mega644, and for the magazine motor, we used port C. In the oscillator pins (pins 15 and 16) we attached a 4 MHz crystal oscillator for the IC to correctly time pulses. The output of the EDE1200 goes to the input of the ULN2003A, a 7 Darlington transistor array. The ULN2003A acts as the motor driver, stepping up the 5V pulses from the EDE1200 to the larger voltage pulses provided in the common power input pin. Our main power supplies 15V to the circuit. For the magazine motor, we sourced the main power supply into the common power input pin to drive the larger motor. For the feeding station motor, we used a 5V regulator (LM7805) to drop down the voltage to the 5V necessary to drive the motor. In addition, 16? resistors are added between the output of the ULN2003A and the feeding station motor. This is because when the motor is driven with 5V, it consumes 1A of current. The ULN2003A is designed only to handle 500mA. The resistors are in place to protect the IC. The magazine motor is designed to draw much less current so the resistors are not needed.

Originally, we had tested the circuit with much smaller stepper motors so we could check our design. After the motors exhibited correct functionality, we attached them to the larger motors in the research lab. However, these motors did not turn on. This was due to instability caused by the voltage regulators and the fast switching of the ICs. In order to provide stability to the power supply, we added 1 µF capacitors between the supply voltage and ground in each of the ICs.

15V Step Motor

(Click to Enlarge) A schematic of our 5 V step motor circuit.

5V Step Motor

(Click to Enlarge) A schematic of our 15 V step motor circuit.

Digital Stimuli Toggling Circuit


Our system allows the use of 4 extra pins to be toggled for stimuli application. Ports B0 - B3 are connected to the ULN2003A with a 12V common power input. These pins can be used to control odor pumps, or other stimuli / data collection equipment. The power supply is stepped down from the 15V power supply using a 12V voltage regulator (LM7812). This component could be changed to fit in the power requirements of different desired hardware.

Ports

(Click to Enlarge) A schematic of our circuit to turn on and off ports.

Sensor Hardware


We use an IR emitter-detector pair for each motor to detect when the motors are in the correct position. In our microcontroller, port D2 (feeding station sensor) and port D3 (magazine station sensor) were set as input pins to trigger an ISR. We found it necessary to use the LM358 op amp to make a digital switch from our sensors, similar to the lab 4 fan speed circuit. When we tried to make the circuit without the op amp, the ISR was triggered unpredictably. Sometimes the motors would skip stop position completely. Other times, when the motor was resumed from the stop position, it would immediately stop before reaching the next stop position.

Sensor Emitter

(Click to Enlarge) A schematic of our sensor emitter circuit.

Other hardware


In the actual apparatus, the motors, and the ISR sensors are connected to a 25 pin DSUB connector for ease of connectivity to our circuit. The pinouts are shown in the appendix.

Software Design

The software on the microcontroller is contained in serialcontrol.c. This can be found in the appendix below. The functionality of the code can be broken up into three main sections. These include receiving commands from the Matlab program through a serial connection and parsing the commands, calling the corresponding functions in the code, and controlling interrupt service routines for the sensors.

Serial Communication and Parsing


After initialization of the microcontroller ISRs for external interrupts, PORT pins and directions, and the usart used for serial communication, the program enters an infinite while loop. During each iteration of this loop we call the fscanf() function, which reads off data from the serial line and stores the data into a length 5 char array. The software then parses the command based on whether the first character is an 'm' or a 'p'. An 'm' character signifies that the command is controlling the motor, and the other characters in the array act as parameters to change the motor number, direction, speed, and whether the motor is on or off. If a 'p' command is received, the microcontroller has received a port command and will toggle the pin associated with the character in the2nd position in the array (cmd[1]). Our GUI allows up to 4 different pins to be connected the microcontroller. After the function is called, an iteration of the loop has completed, and the microcontroller is ready to take in the next command.

Consequently the receiver takes one command at a time from the Matlab program, executes it, and then gets ready to receive another command from the Matlab program. The table below shows the protocol we created for sending commands.

Command Type cmd[0] Parameter 1 cmd[1] Parameter 2 cmd[2] Parameter 3 cmd[3] Parameter 4 cmd[4]
Motor (m) Speed (0-7) Direction Motor # (0 or 1) Power (0 or 1)
Port (p) Toggle Port (0-3) -- -- --

Function Description
void stepInitialize(void) Sets the direction of the two ports connected to the stepper motors and their initial default values (motor off, clockwise, run mode, and speed 0).
void stepSpeed(char motor,char speed) Sets the speed of the specified motor. Speed values range from 0-7 (See appendix for EDE1200 datasheet)
void stepPower(char motor, char pwr) Sets whether the specified motor is turned off or on (1 for on).
void stepSize(char motor, char stepsize) Sets whether the specified motor moves in half steps or full steps when running in step mode.
void stepDir(char motor, char dir) Sets the direction of the specified motor (dir = 1 for clockwise)
void stepMode(char mode) Sets whether the specified motor is in run mode or step mode. In run mode, the motor spins continuously. In step mode, the motor moves a specific number of degrees when given a step pulse. (mode = 1 for run mode)
void stepPulse(char motor) When the specified motor is in step mode, provides a falling edge pulse to cause the motor to step once.

In our parsing code, several of the functions are never called such as the stepMode, stepSize, and stepPulse functions. The operation of the motors is always in run mode, since there is no need for fine movements of the motor. However, these functions were left in the motor driver code in case different hardware designs require the use of finer control in the motors.

Sensor Interrupt Service Routines


During the initialization method of the microcontroller, the external interrupts are turned on. These are interrupts that are triggered when the input pins connected to the ports have a rising edge. Our hardware circuits are designed to have a rising edge when our IR sensors are blocked. The feeding station sensor is triggered using external int0, and the magazine sensor is triggered using external int1. The ISRs turn off the power to their respective motors using the stepPower() motor function.

Design Results

For the time scale of these experiments the speed of execution was not an issue. We noticed slight delay over the serial connection but it was insignificant. If in the future this becomes an issue, it could be fixed by simply sending the microcontroller all of the commands at the beginning and then start the experiment. The accuracy of the timing of the events relative to one another is excellent. Matlab generates a sound command as a conditioned stimulus event for the correct duration and with the right frequency.

We were careful to include resistors and capacitors in our design to make sure IC chips were not damaged. In addition, we implemented pushbuttons on the microcontroller to allow for manual controlling of the magazine stepper motor to aid in ease of use.

For our Matlab GUI, we included a time graph so that the user can easily see the sequential order of events during the experiment. In adding this functionality, we also enabled stimuli and data collection to occur in any order, whereas before, the order of events was conformed to a particular sequence (though the timing could be changed).

Conclusions

Our design met our main goals for the project which were to eliminate the use of the expensive PCI-6070E card and replace it with the Atmel Mega644 microcontroller. In addition, we allowed the program to control the speed of the stepper motors and if necessary, run the motors in step mode. In terms of convenience and usability, we added push buttons on the microcontroller to manually move the motors, and upgraded our GUI program on Matlab for more flexibility to schedule experiments.

One of the features that we wished to implement was to use the microcontroller analog to digital converter (ADC) to record insect physiological data and store this on some medium. This would have made our project completely replace all of the functions of the expensive pci-express card. One problem that we would have had to address in implementing this function is the storage of this data, which has a frequency of 2 kHz. The bandwidth of serial communication would approach its maximum capacity had we implemented this using the RS-232 connection. One possible solution would be to use the SPI port and store data to a Secure Digital (SD) card. Since this functionality of physiological data collection is not being used yet, there is still time in implementing this in Mega644.

In addition, because of the numerous wires in our circuit and the possibility of a wire being disconnected or shorted, it would be advantageous to have a custom PCB made for our design.

Our project used the RS-232 port for communication between our Matlab GUI and our microprocessor. As we used an existing uart implementation for serial communication with the microprocessor, and we were able to successfully receive commands from the GUI, we assume that the RS-232 standard was met.

For our project, we used the external interrupt ISR sensor circuit in lab 4 of the ECE4760 course in our design to stop the stepper motors. We also used the uart implementation written by Joerg Wunsch, that was provided in our ECE4760 class. The other parts of the hardware and software were all designed by us.

Ethical Considerations


We strictly adhered to the IEEE code of ethics in designing this project. The apparatus that was designed does not pose any safety hazards.

Legal Considerations


As far as we know, our project does not violate any regulations.

Appendix

Parts List

Part Description Part # Cost
Step motor controller x2 EDE1200 $6
Motor Driver x3 ULN2003A $2
NAND gate 7404 $.50
Inverter 7402 $.50
4 Mhz Crystal x2 CTX080-ND $1.0
Mega644+ PCB+ external components NA $30
Diode 1N4004 $0.27
5V regulator LM7805 $0.43
12V regulator LM7812 $0.43
Serial cable NA $5
Firewire cable NA $10
Video camera NA $150
Step motor x 2 In possession $50
Plexi-glass scrap NA $50
IR sensor emitter pair x 2 LTE4208/LTR4206 $1.50
Gear and Rack pair 2 of part# 6325k94
1 of part# 6295k243
$50
1"x.125" steel dowels pins x14 NA $2
450 Ohm resistors NA $0.50
10uf capacitors NA $0.50
Microscope with Camera Lens NA NA

25 Pin DSUB Connector

B1 Magazine Sensor +
B2 Feed 4
B3 Feed 2
B4 Feed 3
B5 Feed 1
B6 Feed Com
B7 Feed Com
B8 Magazine 4
B9 Magazine 3
B10 Magazine 2
B11 Magazine 1
B12 Magazine Com
B13 Magazine Com
B14 Magazine S -
B15 Magazine E+
B16 Magazine E-
B17 Feed E-
B18 Feed E+
B19 Feed S-
B20 Feed S+
B21 No Connect
B22 No Connect
B23 No Connect
B24 No Connect
B25 No Connect

Task Group Member(s)
Hardware Design Darbin
Microcontroller Receiver Software All
Step Motor Drivers Justin
Matlab Serial Comm Kyle
Matlab GUI Darbin
MCU Sensor ISR's All

References

Data Sheets

Atmel ATMega 644 Microcontroller

Vendor Sites

Digi-Key

Code/Designs borrowed from others


Lab 4 Circuit Design

uart.c

/*

 * ----------------------------------------------------------------------------

 * "THE BEER-WARE LICENSE" (Revision 42):

 * <joerg@FreeBSD.ORG> wrote this file.  As long as you retain this notice you

 * can do whatever you want with this stuff. If we meet some day, and you think

 * this stuff is worth it, you can buy me a beer in return.        Joerg Wunsch

 * ----------------------------------------------------------------------------

 *

 * Stdio demo, UART implementation

 *

 * $Id: uart.c,v 1.1 2005/12/28 21:38:59 joerg_wunsch Exp $

 *

 * Mod for mega644 BRL Jan2009

 */

 

 

/* CPU frequency */

#define F_CPU 16000000UL

 

/* UART baud rate */

#define UART_BAUD  9600

 

 

#include <stdint.h>

#include <stdio.h>

 

#include <avr/io.h>

 

#include "uart.h"

 

/*

 * Initialize the UART to 9600 Bd, tx/rx, 8N1.

 */

void

uart_init(void)

{

#if F_CPU < 2000000UL && defined(U2X)

  UCSR0A = _BV(U2X);             /* improve baud rate error by using 2x clk */

  UBRR0L = (F_CPU / (8UL * UART_BAUD)) - 1;

#else

  UBRR0L = (F_CPU / (16UL * UART_BAUD)) - 1;

#endif

  UCSR0B = _BV(TXEN0) | _BV(RXEN0); /* tx/rx enable */

}

 

/*

 * Send character c down the UART Tx, wait until tx holding register

 * is empty.

 */

int

uart_putchar(char c, FILE *stream)

{

 

  if (c == '\a')

    {

      fputs("*ring*\n", stderr);

      return 0;

    }

 

  if (c == '\n')

    uart_putchar('\r', stream);

  loop_until_bit_is_set(UCSR0A, UDRE0);

  UDR0 = c;

 

  return 0;

}

 

/*

 * Receive a character from the UART Rx.

 *

 * This features a simple line-editor that allows to delete and

 * re-edit the characters entered, until either CR or NL is entered.

 * Printable characters entered will be echoed using uart_putchar().

 *

 * Editing characters:

 *

 * . \b (BS) or \177 (DEL) delete the previous character

 * . ^u kills the entire input buffer

 * . ^w deletes the previous word

 * . ^r sends a CR, and then reprints the buffer

 * . \t will be replaced by a single space

 *

 * All other control characters will be ignored.

 *

 * The internal line buffer is RX_BUFSIZE (80) characters long, which

 * includes the terminating \n (but no terminating \0).  If the buffer

 * is full (i. e., at RX_BUFSIZE-1 characters in order to keep space for

 * the trailing \n), any further input attempts will send a \a to

 * uart_putchar() (BEL character), although line editing is still

 * allowed.

 *

 * Input errors while talking to the UART will cause an immediate

 * return of -1 (error indication).  Notably, this will be caused by a

 * framing error (e. g. serial line "break" condition), by an input

 * overrun, and by a parity error (if parity was enabled and automatic

 * parity recognition is supported by hardware).

 *

 * Successive calls to uart_getchar() will be satisfied from the

 * internal buffer until that buffer is emptied again.

 */

int

uart_getchar(FILE *stream)

{

  uint8_t c;

  char *cp, *cp2;

  static char b[RX_BUFSIZE];

  static char *rxp;

 

  if (rxp == 0)

    for (cp = b;;)

      {

                loop_until_bit_is_set(UCSR0A, RXC0);

                if (UCSR0A & _BV(FE0))

                  return _FDEV_EOF;

                if (UCSR0A & _BV(DOR0))

                  return _FDEV_ERR;

                c = UDR0;

                /* behaviour similar to Unix stty ICRNL */

                if (c == '\r')

                  c = '\n';

                if (c == '\n')

                  {

                    *cp = c;

                    uart_putchar(c, stream);

                    rxp = b;

                    break;

                  }

                else if (c == '\t')

                  c = ' ';

 

                if ((c >= (uint8_t)' ' && c <= (uint8_t)'\x7e') ||

                    c >= (uint8_t)'\xa0')

                  {

                    if (cp == b + RX_BUFSIZE - 1)

                      uart_putchar('\a', stream);

                    else

                      {

                                *cp++ = c;

                                uart_putchar(c, stream);

                      }

                    continue;

                  }

 

                switch (c)

                  {

                  case 'c' & 0x1f:

                    return -1;

 

                  case '\b':

                  case '\x7f':

                    if (cp > b)

                      {

                                uart_putchar('\b', stream);

                                uart_putchar(' ', stream);

                                uart_putchar('\b', stream);

                                cp--;

                      }

                    break;

 

                  case 'r' & 0x1f:

                    uart_putchar('\r', stream);

                    for (cp2 = b; cp2 < cp; cp2++)

                      uart_putchar(*cp2, stream);

                    break;

 

                  case 'u' & 0x1f:

                    while (cp > b)

                      {

                                uart_putchar('\b', stream);

                                uart_putchar(' ', stream);

                                uart_putchar('\b', stream);

                                cp--;

                      }

                    break;

 

                  case 'w' & 0x1f:

                    while (cp > b && cp[-1] != ' ')

                      {

                                uart_putchar('\b', stream);

                                uart_putchar(' ', stream);

                                uart_putchar('\b', stream);

                                cp--;

                      }

                    break;

                  }

      }

 

  c = *rxp++;

  if (c == '\n')

    rxp = 0;

 

  return c;

}

 


Contact Information

Darbin Reyes
der34@cornell.edu

Justin Park
jhp35@cornell.edu

Kyle Markowitz
ksm38@cornell.edu