STATUS:

This project is a bit different in that it is mostly focused towards a course. I will not be doing any further work on the subject outside of the course, but would be happy to share my experiences or answer any questions.

Intro:

The Sophomore lab at CU is called, simply, the "Electronics Design Lab." With a simple name comes a simple goal, to build a basic 2 wheel robot and move it using an Arduino. This is done from the bottom up using a robot platform not unlike the Arduino Robot. We are given a platform with 2 motors and 2 encoders, as well as some general guidance and are set free to build a working robot. This page will explain how that was done.

Part 1: Speed sensor:

A speed sensor is important to be able to see where your bot is moving, and get constant data on what exactly is going on inside. For that reason, that was our starting point. The encoder given was active low, so the first step was to add a pull-up resistor. After that was done, we arrived at the following output:

Output from the encoder test (simply running the motor at full speed)

After that, the motor was modeled using various methods. We used a standard motor model which is mapped as follows:

Full motor model (Credit goes to Prof. Dan Seltzer for the layout)

Each of those parameters match the real life motor and were determined using lots of experimentation. The result of this is that we can model the motor in SPICE to a great degree of accuracy. This will come into play much more as the full circuit comes together. Speaking of the full circuit, it's about time that we got into the actual speed sensor part. To start, the speed sensor was modeled in SPICE as follows:

Full speed sensor circuit. Varies the voltage on "speed" depending on how fast the wheel is turning.

You were probably expecting something more complicated, weren't you? Well, this is it. The full circuit is simply a steady on time 555 timer that ticks along with the encoder. The idea is that as you get faster the pulse width stays the same, but the total period decreases, so you get a higher voltage. The high pass filter on the end simply ensures that the end result isn't a PWM signal but a clean output voltage. Eventually a comparator was added before the PWM signal to ensure that the output voltage was always 5V high, instead of the varying voltages that the 555 can tend to give out. The final result is as follows:

Result (post transient) of the tachometer

After simulation, the real-life circuit was built, and surprise surprise, it worked almost exactly as planned.

PART 2: Motor Driver

As with the previous lab, we started with building a simulation. This was done in 2 parts, first with the internals of the motor driver.

Motor driver internals

This is what will be a separate hand soldered piece from the bread boarded driver circuitry. This is mostly done due to heat concerns, as the transistors can get quite hot at full speed. Next up was the full test circuit:

Full motor driver circuit using the internal circuit built previously

The resistor values were chosen to limit the current below 1A for each wheel (which ends up being more around 750mA per wheel). A few locked wheel tests (the omega output held at 0) results in exactly this. The next step gets a little more complicated, as now we need to build a closed loop speed control. This is done using the speed sensor from the previous part and an integral compensator to make sure the wheel is always around some Vref. 

Integral compensator circuit

This circuit takes the PWM output from the speed sensor and compares it to a voltage that comes in via the Vref pin. We use a MOSFET in order to be able to change the wheel's direction using digital signals. This is put together in a closed-loop speed control circuit which is as follows:

Full closed-loop speed control circuit

The final simulation is as follows:

Simulation output from closed loop speed control circuit

However, this isn't perfect. The biggest issues is that it is overcompensating for the speed in the beginning, which is not what we want. Overcompensation gets us close, but if we want precise speeds as fast as we can get them, we need perfect compensation, or in mathematical terms, critical damping. This is done with a provided script and Matlab's sisotool, and the result is an RC of about .086s. The adjusted output is as follows:

Critically damped compensator circuit output

As you can see, it doesn't do that wobble that we see in the original simulation. Granted, this result is still a bit underdamped, but it gets the job done. The last improvement we need to make is to add a filter for Vref. We will be using an Arduino to control our bot, which uses PWM signals. Since we don't want our compensator getting "confused," a simple filter will help balance it out.

RC filter for a cleaner input signal

Output signal before and after the filter

After the whole thing was put together, a few tests were run to find output voltages with different duty cycle inputs. At about 70% is max speed, 50% is about 9.1V, 30% 6.6V, and 10% 4.1V. Around 2V is where the wheel won't move at all, so there is still plenty of room to work at low speeds. The idea behind this seemingly over-complicated motor driver circuit is that the robot is always moving at the speed that the software thinks that it is moving. If we based our software solely on the voltage we are providing to the motors, simply hitting a rock could completely ruin any potential computations.

Part 3: Arduino Programming:

Due to the integrity and structure of the motor drivers, hooking up the Arduino to the bot is fairly trivial. It only requires linking into the main structure and using the various pins we setup in order to drive the bot. The first thing to do is to get the direction under control. The best way we found to do this was have a function that simply set the pins based on the direction and have the MOSFETs take care of the rest. The basic function turned out as follows:

void set_LCC(boolean LCC){
    if (LCC){
        digitalWrite(pinCC_Left, HIGH);
        digitalWrite(pinCW_Left, LOW);}
    else{
        digitalWrite(pinCW_Left, HIGH);
        digitalWrite(pinCC_left, LOW);}}

With this, we can simply call a function for each wheel to setup direction. We also setup a stop function, which simply turns every output pin to low. With these two functions, it was easy to configure a set of basic direction functions similar to "forward" below.

void forward(unsigned int distance, char spd){
  Serial.print("Forward: ");
  go(true, false, distance, spd);}

But wait, how are we going to do distance? Well, we could do it mathematically, but the more sound method is to do it using the bot's encoder, which will also allow us to do speed compensation within go. To do this, we simply link the encoder to the Arduino's 2 interrupt pins and increment a count whenever it is read as high (which is 12 times per motor rotation). With all of that, we are ready for "go."

void go(boolean LCC, boolean RCC, unsigned int distance, char spd){
  stop();
  enc_left = 0; //reset counts
  enc_right = 0;
  set_LCC(LCC); //set direction
  set_RCC(RCC);
  analogWrite(pinSpeed_Right, spd); //set speed
  analogWrite(pinSpeed_Left, spd);
  do{compensate(spd);} while((enc_left < distance)&&(enc_right < distance)); //go!
  stop();
  return;}

This ends up being pretty simple due to the nature of how we went about setting it up. All in all, all we need to do is set directions and speeds and wait for it to go forward. With this and a few more direction functions, it is trivial to drive the bot around using just Arduino code.

Part 4: Wireless

I'm going to make a statement that most electrical engineers have already heard or experienced, "wireless communication is hard." I've been a computer and general tech geek for a long time now, and wireless was always one of those things that pretty much just worked. Yeah, people have their gripes with WiFi and Bluetooth, but for the most part tons and tons of work went into making reliable protocols and ensuring good error handling. For this section of the project, our goal was to build a wireless control and run our robot based on different pulse lengths.

The first step is to build a filter. For this project, our wireless was not address based, but rather frequency based. This meant that we had to build a filter that had a high enough quality factor for our bot to only be controlled off of our signal, and a low enough quality factor to not overload the op amp. This was mostly done with a provided script that built a Chebyshev filter given center frequency and order. This was then put into LTSpice and adjusted to our op amp to make sure that it was of the highest quality and closest to the desired center frequency as possible. After that was done, a peak detector and comparator circuit was used to get a clean output signal. The peak detector makes sure that the circuit stays on for the correct amount of time, and the comparator turns that into a square wave instead of some sort of funky output (the output after the bandpass filter is a sine wave). The final filter circuit can be seen below.

Full final filter complete with bandpass filter, peak detector, and comparator

With that linked to a simple receiver (we used Sparkfun's basic receiver), it will receive signals transmitted at 1680Hz. However, we also need to build the transmitter, which starts with the receiver's counter part, which can be found here. This will transmit in a way that the receiver can receive properly, and takes a simple data signal input. However, we will have to build the 1680Hz portion ourselves, which will be done with a simple 555 astable circuit. Going off of the data sheet, 50% duty cycle 555 timer circuits can be a bit grumpy, so we use a special circuit for just that purpose. The final circuit is as follows:

555 Astable circuit for 50% duty cycle and 1680Hz operating frequency

Once we have this, it is simply a matter of putting a signal in through the 555's reset pin. Once this is put together with the receiver, it will transmit a signal from the input and come out of our filter on the other end the same way it came in. The last step is to make it so that we can control our bot using just that signal, which ends up being done using timed pulses. If we have a steady frequency signal and modify the pulse width, then read that pulse width on the other end, we can control the bot with a series of pulses. This is done with a signal generator on the 555 end (although an Arduino or some other analog circuitry would work just as well, or better), and the Arduino's pulseIn function (as follows) on the filtered end.

void readPulse(){
  cur_pulse=0;
  while(cur_pulse < 14000){cur_pulse = pulseIn(pulsePin, HIGH);}
  return;}

This was built with the decided minimum pulse width at 14ms. Once this is done, the varied pulses can be simply read from cur_pulse and different movements can be performed from there.

Conclusion and final thoughts

Overall, this was just a start to an actual useful robot. However, at this point we can go on to build any kind of robot we want, as the platform we built is extremely adaptable. In order to wrap up our course, we went on to build a Twitter based robot called Cardinalis^2. The page on Cardinalis^2 can be found here. On top of that, the final, full schematic can be found below, and all code on Github.

The full, final circuit. LTSpice schematic here. I highly recommend going off of that if you want to use any of this circuitry, as this image isn't the highest quality due to the amount of content.