Main Board v0.4
I received Main Board v0.3 back from OSHPark and the TB6612FNG IC did not seem to line-up with the contacts on the board. It was, in fact, about a millimeter too wide. I had anticipated a challenge, as this was to be my first attempt at soldering surface-mount. But this footprint problem was not an issue that I had not expected to encounter. I had taken a SSOP-24 footprint from KiCad's library and modified it only in that I joined adjacent pads for the motor connections. Looking at the TB6612FNG datasheet, I confirmed from the drawings that the footprint I used was not wide enough.
Yet another reminder to check and double-check datasheets.
So I did attempt to bend the IC pins to see if I couldn't work the chip on somehow, so that I could test the board functionality. But, with the pins bent back, even a bit, they became impossible to solder. I did briefly consider attempting to bodge wires onto the chip and in that way connect it to the board. But it looked like an exercise in frustration and I decided to just fix the footprint and order another round, which will be Main Board Revision 4.
I think that I managed to discover and fix some other board problems, as well. The chip was not getting power from the programming-header connection. So, one issue I am experiencing with KiCad right now is that it does not consider copper traces from my motor-controller ICs to the motor terminals to be valid. I think that this must be my fault somehow, due to the way I set up design rules for the varying widths of copper trace or somesuch. Anyway, I wrestled with it for a while before giving up. But the upshot of all that was that I nearly missed some actual missed connections on the board, due to the noise I was getting about motor connections, which, I'm pretty damn sure, are valid.
So, anyway. KiCad is a strange beast but in every previous instance of trouble I eventually figured out that I was doing it wrong and I'll have to assume that this is the case here.
So the smaller IC (U3) to the right of the microcontroller is the shift-register, which I added because each motor IC takes two control inputs as well as a PWM speed input. For three motors, this means nine pins, which is more than I wanted to dedicate to motors. So, preserving the direct PWM connections, I hooked up the control lines to a shift-register, which is in turn controlled by the microcontroller using three pins (data, clock, and clear). Six of the eight shift-register output pins are connect to the motor-controller inputs. So, now I need six pins to control my motors instead of nine. With the limited number of GPIO ports on the ATMega328, this makes a difference! In retrospect, I could have skipped the serial-clear pin, since I am writing eight new control bits each time.
Before designing this board, I played around with a shift-register and some LEDs on a breadboard, just enough to convince myself that I understood the basics. So, with the new revision on order, I got back to the programming side of things.
To control the motors, I now needed to push six control bits + two padding bits out to the shift-register. In my code, I have a struct with the definition:
And then I initialize the struct like:
So, each motor-direction has it's own value, which is specifically a power of two, representing a bit set to "1" in a 6-bit number.
Here, maybe this diagram will help illustrate:
So, in the above diagram, each motor is set to spin clockwise (or maybe counter-clockwise, in all the confusion, I've lost track ...).
Oh, one other thing, in search for open-source examples of TB6612FNG, I did find this simple breakout in the shared projects on OSHPark. I ordered some samples, just in case I managed to get the footprint wrong once again. While the design files are downloadable, unfortunately they are in Eagle's format and I haven't gotten Eagle working yet on my computer.
Yet another reminder to check and double-check datasheets.
So I did attempt to bend the IC pins to see if I couldn't work the chip on somehow, so that I could test the board functionality. But, with the pins bent back, even a bit, they became impossible to solder. I did briefly consider attempting to bodge wires onto the chip and in that way connect it to the board. But it looked like an exercise in frustration and I decided to just fix the footprint and order another round, which will be Main Board Revision 4.
Main Board PCB as seen in KiCad |
So, anyway. KiCad is a strange beast but in every previous instance of trouble I eventually figured out that I was doing it wrong and I'll have to assume that this is the case here.
So the smaller IC (U3) to the right of the microcontroller is the shift-register, which I added because each motor IC takes two control inputs as well as a PWM speed input. For three motors, this means nine pins, which is more than I wanted to dedicate to motors. So, preserving the direct PWM connections, I hooked up the control lines to a shift-register, which is in turn controlled by the microcontroller using three pins (data, clock, and clear). Six of the eight shift-register output pins are connect to the motor-controller inputs. So, now I need six pins to control my motors instead of nine. With the limited number of GPIO ports on the ATMega328, this makes a difference! In retrospect, I could have skipped the serial-clear pin, since I am writing eight new control bits each time.
Before designing this board, I played around with a shift-register and some LEDs on a breadboard, just enough to convince myself that I understood the basics. So, with the new revision on order, I got back to the programming side of things.
To control the motors, I now needed to push six control bits + two padding bits out to the shift-register. In my code, I have a struct with the definition:
struct motor_control_mapping {
uint8_t left_track_reverse;
uint8_t left_track_forward;
uint8_t right_track_reverse;
uint8_t right_track_forward;
uint8_t turret_left;
uint8_t turret_right;
};
And then I initialize the struct like:
struct motor_control_mapping _motor_control_mapping = {32, 16, 8, 4, 2, 1};
Here, maybe this diagram will help illustrate:
Motor control code. Actually, I think the padding bits would be on the left, here. Oh well. |
The motor-control code is composed as follows:
unsigned char control_code = 0;
if (_left_motor_state.direction == motor_forward) {
control_code |= _motor_control_mapping.left_track_forward;
} else if (_left_motor_state.direction == motor_reverse) {
control_code |= _motor_control_mapping.left_track_reverse;
}
if (_right_motor_state.direction == motor_forward) {
control_code |= _motor_control_mapping.right_track_forward;
} else if (_right_motor_state.direction == motor_reverse) {
control_code |= _motor_control_mapping.right_track_reverse;
}
if (_turret_motor_state.direction == motor_forward) {
control_code |= _motor_control_mapping.turret_left;
} else if (_turret_motor_state.direction == motor_reverse) {
control_code |= _motor_control_mapping.turret_right;
}
And this control code is fed one bit at a time to the shift-register. Not rocket science, I realize, but I was pretty happy how this came together.
So that's pretty much it for the motor-control logic. I also added logic that sets the motor speed to zero for an interval following a motor reversal, so that the motors cannot be instantly reversed, which will hopefully preserve the life of the motors a bit.
Right now, I have an Arduino, a breadboard with a TB6612FNG and a shift-register, and a DC motor setup, so that I can test this code. As I wait for my new boards, I'll keep adding components and testing the software with them.
I've already started sketching out the basics in the code but over the coming days I will be adding logic to control debugging functions. The idea is that the user, with an IR remote, can control all of the tank's functions manually (drive around, rotate the turret, "shoot" the IR transmitter). This can be useful when, say, first powering-up a newly-assembled tank, to verify that all the hardware works. It can also be useful for narrowing-down issues (Why isn't my obstacle-avoidance code working in the way I expect? Are the sonar sensors functioning normally?).
Though my IR receiver code worked initially, I quickly ran into problems. It would regularly block, waiting for the rest of a signal that would never come. I switched back to the IRremote library and it worked great (and I'm not sure what caused my initial problem with it). I enjoyed the little foray into lower-level stuff but had to concede that, without a lot of time and dedication, whatever I was going to write wasn't going to be near the quality of established library code.
One of the first things I did when experimenting with the motor-control logic was to hook-up my 4-LED light bar. It's hugely useful for debugging. Writing to the serial line is great, too, but a lot of information can be transmitted with four blinking lights! I'm pretty happy with the LED driver code I wrote, which makes it really easy to make a light blink in a simple pattern.
Though my IR receiver code worked initially, I quickly ran into problems. It would regularly block, waiting for the rest of a signal that would never come. I switched back to the IRremote library and it worked great (and I'm not sure what caused my initial problem with it). I enjoyed the little foray into lower-level stuff but had to concede that, without a lot of time and dedication, whatever I was going to write wasn't going to be near the quality of established library code.
One of the first things I did when experimenting with the motor-control logic was to hook-up my 4-LED light bar. It's hugely useful for debugging. Writing to the serial line is great, too, but a lot of information can be transmitted with four blinking lights! I'm pretty happy with the LED driver code I wrote, which makes it really easy to make a light blink in a simple pattern.
Arduino with TB6612FNG breakout, a single DC motor, and a sonar sensor. Connections get complicated quickly! |
Comments
Post a Comment