Got python code talking to the board, have a joystick working and sending commands over the final protocol.
basically all that remains is putting together the CV code.
also, I just realized I could do a pan-tilt fairly easily. The only tricky part is having to connect sideways. Maybe I could glue something onto the side of my little webcam.
Tuesday, February 26, 2013
Monday, February 25, 2013
Slower Progress
Ended up doing crap yesterday while I figured out how I wanted to handle the PC side of things. Decided that I didn't really want to learn win32 so I ended up switching to python.
Meanwhile I write a new serial driver, complete with debug mode. Generally the idea is that the micro will ask the computer for locations, and the computer will respond in a somewhat timely manner. That way I don't have to worry about the computer overwhelming the micro or the serial bus. The messages will be fixed length, and i'll just pad them out.
The micro message is just 'g', for 'get data'.
There are two computer>micro messages, of 6 bytes length:
"pXX000" where XX is a 12 byte number spread over two bytes and masked with 01xxxxxx01xxxxxx. This is the position and legal values will just be 0-1024.- "s00000": Stop.
edit: no this is dumb, I will just use begin/end message characters, and escape characters. way way easier.
Debug mode occurs when the handshake fails and is just a terminal interface. For some reason it seems a little slow/buggy, but I think it's just the terminal program in AVR Studio.
Since I can now move the servo from the computer, I can also check how well the camera goes on the servo. Realized I can just tape the flat bottom of the webcam to the servo flange, at least as a basic method. Then I moved it around. Works fine, except the servo needs to be taped down too, and the cord on the webcam is a mini-issue. I think I can just get some double-sided poster tape and have a nice solid connection for now, and tape on a strain relief for the cord.
Saturday, February 23, 2013
PWM on the Atmega328P
OK, this was kind of confusing, but not too bad really. The PWM works via the timers. You set a timer and it starts counting until it hits its max (ICR). You set a threshold (OCR), and then if the timer is under the threshold, the output pin will go high. Otherwise it goes low. There's some finicky stuff about phase correctness but that's about it.
The timers have a frequency that's going to be a divider of the main clock rate. We're at 16Mhz. I use the f/8 divider. Putting it in phase correct mode means it counts up and then down again, so for a full cycle it's another half that.
TCCR1B|=(1<<WGM13)|(1<<WGM11)|(1<<CS11); //PRESCALER= MODE 10(phase correct)
ICR1=20000; //50Hz (Period = 20ms).
DDRB|=(1<<PB1); //PWM Pins as Out
}
void initPWM()
{
TCCR1A|=(1<<COM1A1)|(1<<COM1B1)|(1<<WGM11);
}
ICR 1 contains basically what the timer will count up to. So at 2 Mhz, we're going to count to 20,000 and back down again. That means 20ms per cycle. Finally, turn the pin on.
I had hoped to use timer 2, but it doesn't seem to have the ICR feature. Will have to figure that one out later.
Setting the PWM duty is pretty easy too. OCR1A is the output compare register, and since things have worked themselves out, the units will just be a microseconds again.
OCR1A = on_time;So that's a PWM timer with 1usec resolution, on a 50hz cycle, with no processor overhead.
Initializing the ADC on an ATMega328
Decent tutorial on AVRFreaks, however his micro gets put into free-run a different way. I used ADATE instead, which is in ADCSRA.
void initADC0()
{
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // set prescale to 128; (table 23-5)
ADMUX |= (1 << REFS0); // reference to vcc (table 23-3)
//ADCSRA |= (1 << ADFR); // put into free-running mode. (not in 328??)
ADMUX |= (1 << ADLAR); // put into 8-bit mode.
ADCSRA |= (1 << ADEN);
ADCSRA |= (1 << ADSC); // start taking measurements
ADCSRA |= (1 << ADATE); // Auto-trigger
ADCSRA |= (1 << ADIE); // Enable ADC Interrupt
}
Then the interrupt handler is just:ISR(ADC_vect)
{
ADCRead = ADCH;
}
Make sure interrupts are actually on! (use sei();)
ADCRead is a static, not sure if that's the best idea. But it makes the getter easy:
uint8_t getADC()
{
return ADCRead;
}
The only thing I'm not sure about is how often ISR gets called. It kind of seems like it would get called a lot.
Back from the store.
Scratch that. Went and bought a servo for $10. Makes much more sense.
goal for tonight:
1) make servo move w/ pot control
2) make joystick serial program on PC
3) interface those two.
goal for tomorrow:
OpenCV stuff.
General architecture and risks
So, the general idea is that the computer vision will occur on the host PC, and that the host pc will send some sort of command to the atmega. And then the atmega will handle the real-time control. Some of these details are a bit sketch at the moment.
Breakdown of the tasks:
- Computer:
- Minimum function: handshake w/ atmega
- Basic functionality A: console "joystick" program
- Basic functionality B: run face-detection example, and generate distance from center
- Basic functionality B2: if the face thing doesn't work, try using a light.
- Full functionality: Combine these two!
- super functionality: auto-tuning.
- Atmega:
- Basic functionality A: handshake with PC
- Basic functionality B: loop that blinks LEDs based on PC commands
- Basic functionality C: timed open-loop moves in response to PC commands
- Full function: PID control? feed-forward control?
- other test case: light detector
- Hardware design:
- Blink LEDs
- Motor drivers
- Motor physical mounting etc, camera mounting
- OpenCV. Haven't used it before. Hoping to mitigate this by largely using samples.
- USB on Windows. really haven't used this before. before I've used linux and everything was just file-like and life was fairly easy, although there's probably some details I'm forgetting. Same for MATLAB. Looks like some good info here: http://playground.arduino.cc/Interfacing/CPPWindows
- Reading from serial on the atmega.
- Loop speeds. The vision loop is going to be limited to probably 10-60hz. The motor control may need to be faster than that. I might want the motor to make small movements and then wait for new as opposed to doing a naive PID.
- Motor power. I remember my motor being a 12V motor. Not sure how much current it will pull at 5v. Probably more than the USB can handle. I have 9V battery too, not sure if that will power the 5V side. I think it does. There's a 1A regulator, ON 117-5 on the board.
- Affixing camera to motor, affixing motor to something rigid. We'll start with tape.
Friday, February 22, 2013
Weekend Project #1

Pretty much, tie webcam to top of motor, run OpenCV to do a face tracker. Face tracker finds face and sends an error signal to Arduino, Arduino controls h-bridge, moving the motor.
The only H-bridge I have is an L298 in an annoying package, so I'll see if Fry's has one, or just make one from transistors. Or else, I do know Fry's has some cheap servos which wouldn't be a big deal either.
Computer side, haven't used OpenCV, but face tracking is one of the pretty common demos.
Subscribe to:
Posts (Atom)
