====== Videotuvastusrobot ====== ===== Meeskond ===== * Oleg Movko * Artjom Terestsenko * Valeri Tverdohleb * Dmitri Perederi * Arkadi Pristavko ===== 1.Lähteülesanne ===== Videotuvastusrobot on robot mis peab leidma üles punast pallit ja sõita tema järgi. ===== Aruanne ===== ===== 2.Nõuded ja piirangud süsteemile ===== * Peame kasutama kamerat CMUcam3 * Maksimaalsed gabariidid: 20 cm x 20 cm x 20 cm * Täisautonoomne ===== 3.Süsteemi üldine mudel ===== {{:et:projects:tudengid11:skeemx.png|}} ===== 4.Ideelahendused ===== {{:et:projects:tudengid11:lalax.jpg|}} {{:et:projects:tudengid11:lala2x.jpg|}} ===== 5.Mehaanika ===== Roboti komponendid on paigutatud alusraamile, mis on valmistatud 3 mm paksusest alumiiniumist. Servo mootorid ja kaamera on kinnitatud metallnurkadega. Meie robot seisab 2 ratastel. Lisaks on väike toetusrullik. Niisugune skeem annab võimalust pööratada ühe mootori pöörlemisega ja teise pidurdamisega. Ratad on ühendatud mootoriga. Patareihoidikud on ühendatud kruvide ja mutritega. * Rattas Rattas on tehtud freesipingil. {{:et:projects:tudengid11:rattas.jpg|}} * Servohack(how its made?) Meie õnneks cmucam'ile on võmailik kaasata 4 servomootorit (otse). Selleks et nad töötaksid nägu alalisvoolumootorid me tegime neid ümber. Seda annab meile võimalust teha roboti ilma lisa draiverita. As for the details, there are actually only two modifications to make to the servo. Replace the position sensing potentiometer with an equivalent resistor network Remove the mechanical stop from the output shaft Here are the steps. You will need a few supplies - small philips screwdriver for opening the case - a soldering iron - a desoldering pump or solder wick for removing the potentiometer - a sharp knife or wire cutters for removing the mechanical stop - Two 2.2k resistors (actually, anything between 2.2k and 3.3k will work, as long as they are equal values) The following steps will help you make the modifications. Open the case by removing the 4 screws located at the bottom of the servo. The bottom plate should come off easily. Remove the top of the case. You will find a set of gears under the top case, a several blobs of white grease. Try hard to save the grease by leaving it on the gears. {{:et:projects:tudengid11:servo1.png|}} Be careful to note how the gears are arranged, and remove them from the top of the servo. I usually place them as the are supposed to sit. The large fine tooth gear in the middle does not need to be removed. See the picture below. {{:et:projects:tudengid11:servo2.png|}} Servo with top and gears removed Locate and remove the two small philips head screws on the left shaft in the picture above. These screws go through the top case and into the drive motor. Next, you need to remove the circuit board from the case. To do this, you will probably need to press down hard on the brass shaft on the right side. This is the top of the position potentiometer. I find that pressing that brass shaft against the edge of the workbench helps push it through. From the bottom, very carefully pry up on opposing corners of the circuit board. The board should slide out with the motor and potentiometer attached. You should end up with the following parts on the table. {{:et:projects:tudengid11:servo3.jpg|}} Disassembled servo motor. Now for the actual modifications. You will need to desolder the potentiometer from the board. I usually cut the long leads off a quarter inch or so from the bottom. I then use solder wick on the back side of the board. Once the pot has been removed, you need to wire in the resistor network in its place. To do this, place the resistors side by side and twist one pair of leads. Solder them together, but leave one of the leads long enough to make a 3 wire part. Then replace the pot with this 3 wire pot. As seen in the picture below, the pot has been replaced by the resistor network. {{:et:projects:tudengid11:servo4.png|}} An unmodified (left) and modified circuit board. Now, reassemble the circuit board into the case. Note that the pot is now missing, so only the motor will protrude through the top of the case. Before reinstalling the gears, you will need to modify the gear with the output shaft so the mechanical stop is removed. The mechanical stop is a small tab of plastic on the lower gear surface. In the picture below, you can see the tab on the left gear. This should be cut down flush with the surface. Try to get all of the tab removed, as is shown with the gear on the right side. An unmodified (left) and modified output shaft gear Replace the gears as they were when you took the motor apart, replace the top of the case, the bottom plate, and the two screws. Your done! {{:et:projects:tudengid11:1.jpg|}} {{:et:projects:tudengid11:2.jpg|}} {{:et:projects:tudengid11:3.jpg|}} {{:et:projects:tudengid11:3d.png|}} ===== 6.Ideelahendused ===== Esiplaan oli kasutada kontrollerit, driverit, alalisvoolumootorit. Aga mugav kaamerakonstruktsioon annab võimalust ehitada robotit ainult kahe ümberehitatutega servomootoridega. {{:et:projects:tudengid11:skeem.jpg|}} ===== 7.Juhtimine ===== Roboti juhtimine toimub kaamera abil. Kood: #include #include #include #include #include #include "spoonBot.h" #include #include #include #include void simple_track_color (cc3_track_pkt_t * t_pkt); void simple_get_mean (cc3_color_info_pkt_t * s_pkt); int main (void) { cc3_track_pkt_t t_pkt; cc3_color_info_pkt_t s_pkt; spoonBot_calibrate_t my_cal; uint32_t x_mid, y_mid; uint32_t threshold, x0, y0, x1, y1; int32_t tmp, spoon_loc; cc3_uart_init (0, CC3_UART_RATE_115200, CC3_UART_MODE_8N1, CC3_UART_BINMODE_TEXT); cc3_camera_init (); printf ("Starting up...\n"); cc3_led_set_state (0, true); cc3_gpio_set_mode (0, CC3_GPIO_MODE_SERVO); cc3_gpio_set_mode (1, CC3_GPIO_MODE_SERVO); cc3_gpio_set_mode (2, CC3_GPIO_MODE_SERVO); cc3_gpio_set_mode (3, CC3_GPIO_MODE_OUTPUT); //printf ("Get calibration...\n"); //spoonBot_get_calibration(); // Before you use spoonbot, you must calibrate the servos. // See the spoonBot wiki for more details // // SpoonBot Calibration Points // Assume Left = Servo 0 // Assume Right = Servo 1 // Assume Spoon = Servo 2 my_cal.left_mid = 130; my_cal.right_mid = 95; my_cal.spoon_down = 100; my_cal.spoon_mid = 202; my_cal.spoon_up = 255; my_cal.left_dir = 1; my_cal.right_dir = -1; my_cal.spoon_dir = 1; // Set the calibration points spoonBot_calibrate (my_cal); printf ("SpoonBot!\n"); spoonBot_stop (); spoonBot_wait (100); printf ("SpoonBot Down\n"); spoonBot_spoon_pos (-75); spoonBot_wait (100); printf ("SpoonBot Up\n"); spoonBot_spoon_pos (75); spoonBot_wait (100); printf ("SpoonBot Mid\n"); spoonBot_spoon_pos (0); spoonBot_wait (200); printf ("SpoonBot Right\n"); spoonBot_right (30); spoonBot_wait (100); spoonBot_stop (); printf ("SpoonBot Left\n"); spoonBot_left (30); spoonBot_wait (100); spoonBot_stop (); printf ("SpoonBot Done\n"); cc3_camera_init (); cc3_camera_set_auto_exposure (true); cc3_camera_set_auto_white_balance (true); //cc3_camera_set_colorspace(CC3_COLORSPACE_YCRCB); cc3_camera_set_resolution (CC3_CAMERA_RESOLUTION_LOW); //cc3_pixbuf_frame_set_subsample(CC3_SUBSAMPLE_NEAREST, 2, 2); cc3_led_set_state (0, false); printf ("Waiting for image to stabilize\n"); cc3_timer_wait_ms (2000); cc3_camera_set_auto_exposure (false); cc3_camera_set_auto_white_balance (false); cc3_led_set_state (0, true); printf ("Hold up colored object and press button...\n"); while (cc3_button_get_state () == 0); printf ("Grabbing Color\n"); // init pixbuf with width and height cc3_pixbuf_load (); threshold = 30; // set window to 1/2 size x0 = cc3_g_pixbuf_frame.x0 + cc3_g_pixbuf_frame.width / 4; x1 = cc3_g_pixbuf_frame.x1 - cc3_g_pixbuf_frame.width / 4; y0 = cc3_g_pixbuf_frame.y0 + cc3_g_pixbuf_frame.width / 4; y1 = cc3_g_pixbuf_frame.y1 - cc3_g_pixbuf_frame.width / 4; cc3_pixbuf_frame_set_roi (x0, y0, x1, y1); // call get mean simple_get_mean (&s_pkt); // set window back to full size x0 = 0; x1 = cc3_g_pixbuf_frame.raw_width; y0 = 0; y1 = cc3_g_pixbuf_frame.raw_height; cc3_pixbuf_frame_set_roi (x0, y0, x1, y1); // fill in parameters and call track color tmp = s_pkt.mean.channel[0] - threshold; if (tmp < 16) tmp = 16; if (tmp > 240) tmp = 240; t_pkt.lower_bound.channel[0] = tmp; tmp = s_pkt.mean.channel[0] + threshold; if (tmp < 16) tmp = 16; if (tmp > 240) tmp = 240; t_pkt.upper_bound.channel[0] = tmp; tmp = s_pkt.mean.channel[1] - threshold; if (tmp < 16) tmp = 16; if (tmp > 240) tmp = 240; t_pkt.lower_bound.channel[1] = tmp; tmp = s_pkt.mean.channel[1] + threshold; if (tmp < 16) tmp = 16; if (tmp > 240) tmp = 240; t_pkt.upper_bound.channel[1] = tmp; tmp = s_pkt.mean.channel[2] - threshold; if (tmp < 16) tmp = 16; if (tmp > 240) tmp = 240; t_pkt.lower_bound.channel[2] = tmp; tmp = s_pkt.mean.channel[2] + threshold; if (tmp < 16) tmp = 16; if (tmp > 240) tmp = 240; t_pkt.upper_bound.channel[2] = tmp; printf ("Got color min=[%d,%d,%d] max=[%d,%d,%d]\n", t_pkt.lower_bound.channel[0], t_pkt.lower_bound.channel[1], t_pkt.lower_bound.channel[2], t_pkt.upper_bound.channel[0], t_pkt.upper_bound.channel[1], t_pkt.upper_bound.channel[2]); // Load in your tracking parameters // t_pkt.lower_bound.channel[CC3_CHANNEL_RED] = 200; // t_pkt.upper_bound.channel[CC3_CHANNEL_RED] = 255; // t_pkt.lower_bound.channel[CC3_CHANNEL_GREEN] = 0; // t_pkt.upper_bound.channel[CC3_CHANNEL_GREEN] = 110; // t_pkt.lower_bound.channel[CC3_CHANNEL_BLUE] = 0; // t_pkt.upper_bound.channel[CC3_CHANNEL_BLUE] = 20; t_pkt.noise_filter = 4; t_pkt.track_invert = false; x_mid = cc3_g_pixbuf_frame.width / 2; y_mid = cc3_g_pixbuf_frame.height / 2; spoon_loc = 0; while (true) { uint8_t track_flag; simple_track_color (&t_pkt); track_flag = 0; if (t_pkt.int_density > 10 && t_pkt.num_pixels > 100) { printf ("centroid = %d,%d bounding box = %d,%d,%d,%d num pix= %d density = %d\n", t_pkt.centroid_x, t_pkt.centroid_y, t_pkt.x0, t_pkt.y0, t_pkt.x1, t_pkt.y1, t_pkt.num_pixels, t_pkt.int_density); if (t_pkt.centroid_x > (x_mid + 20)) { track_flag = 1; spoonBot_right (10); } else if (t_pkt.centroid_x > (x_mid + 5)) { track_flag = 1; spoonBot_right (3); } if (t_pkt.centroid_x < (x_mid - 20)) { track_flag = 1; spoonBot_left (10); } else if (t_pkt.centroid_x < (x_mid - 5)) { track_flag = 1; spoonBot_left (3); } if (t_pkt.centroid_y > (y_mid + 10)) { track_flag = 1; spoonBot_drive (10); } if (t_pkt.centroid_y < (y_mid - 10)) { track_flag = 1; spoonBot_drive (-10); } if (spoon_loc > 100) spoon_loc = 100; if (spoon_loc < -100) spoon_loc = -100; spoonBot_spoon_pos (spoon_loc); } if (track_flag == 0) spoonBot_stop (); } return 0; } void simple_track_color (cc3_track_pkt_t * t_pkt) { cc3_image_t img; img.channels = 3; img.width = cc3_g_pixbuf_frame.width; img.height = 1; // image will hold just 1 row for scanline processing img.pix = cc3_malloc_rows (1); if (img.pix == NULL) { return; } cc3_pixbuf_load (); if (cc3_track_color_scanline_start (t_pkt) != 0) { while (cc3_pixbuf_read_rows (img.pix, 1)) { // This does the HSV conversion // cc3_rgb2hsv_row(img.pix,img.width); cc3_track_color_scanline (&img, t_pkt); } } cc3_track_color_scanline_finish (t_pkt); free (img.pix); return; } void simple_get_mean (cc3_color_info_pkt_t * s_pkt) { cc3_image_t img; img.channels = 3; img.width = cc3_g_pixbuf_frame.width; img.height = 1; // image will hold just 1 row for scanline processing img.pix = malloc (3 * img.width); cc3_pixbuf_load (); if (cc3_color_info_scanline_start (s_pkt) != 0) { while (cc3_pixbuf_read_rows (img.pix, 1)) { cc3_color_info_scanline (&img, s_pkt); } cc3_color_info_scanline_finish (s_pkt); } free (img.pix); } ===== 8.Majanduskalkulatsioonid ===== * Cmucam3-----------------260 eur * Servo-------------------15 eur * Alusplaatide materjal---5 eur * Tööjõukulud-------------100 eur * **Kokku-------------------380 eur** ===== 9.Kokkuvõte ja järeldused ===== Mehatroonikaprojekt andis meile plaju kogemusi. Selline projekt haarab mittu erinevad distsipliinid: programeerimine, CAD proekteerimine, oskus töötama tööristetega, elektroonika, disaini alused. Arvame, et see projekt on väga kasulik sest tutvub meid meie erialaga. Avaldame tänu Raivo Sellile, kes andis kasulikud nõuanned. Ta on loonud lahedad tingimused töö jaoks. ===== 10.Viited ja kasutatud materjal ===== * [[http://roboticlab.eu|Roboticlab]] * [[http://cmucam.org|Cmucam]] * [[http://myrobot.ru|Myrobot]]