//------------------------------------------------------------------------------ // CoinCountB.c Written by Andreas Dreier (alias ®³) for CC8 (second entry) //------------------------------------------------------------------------------ // This bot reuse parts from my first entry of CC8. It was my first idea to // realize the given exercise. But it was to slow :-( So I build the other type // of bot (CoinCountA) and send it first to CC8 committee. // // After I heard, that there was a elongation of CC8 deadline ... I reconstruct // the bot CoinCountA and use two main parts for CoinCountB: Seperation unit // with conveyor belt and sorting unit with collecting slots :-) // // CoinCountB used two different additional parts: Feeder unit and other type of // scanning unit. It realized my first solution of given exercise. The main // problem was to detect the coin type. All coins have nearly the same thickness // and some of them had the same colour. The eseast way to detect the right coin // was the diameter of the coin! But the difference between some of them was to // less to detect it on the direct way. My idea was to expand this difference of // diameter! I solve this, by using two straight line which are closer on the // left side than on the right side. The coins entered this tow staight lines // from right side and stoped after touching tho upper line and clamped between // the two lines. By this way, every coin of European currency will stop at a // different place. A light sinsor, wich is parallel to the lower line, moved // from right to left and detected the right and left side of the coin. So I can // detect with this two informations which kind of coin are detected :-) // Next problem was to release the coin from this detection area. I solved this // by the same way: The detection unit moved to left end of rail and lift up the // upper line for releasing the coin :-) Please take a look to the pictures and // videos, which are linked at the end of this documentation. // // This bot will count, detect and calculate a lot of coins. It detect all eight // different coins of the European currency: EURO-Coins // // 1 ct = 0.01 € Coins of the following countries are supported: // 2 ct = 0.02 € - Austria - Italy // 5 ct = 0.05 € - Belgium - Luxembourg // 10 ct = 0.10 € - Finland - Netherlands // 20 ct = 0.20 € - France - Portugal // 50 ct = 0.50 € - Germany - Spain // 1 € = 1.00 € - Greece // 2 € = 2.00 € - Ireland >>>>> 96 different coins :-) // //------------------------------------------------------------------------------ // How does it works? // // The process will seperated into 4 tasks: // // 1. Isolate the coins --> Isolation unit // 2. Serve the coins --> Feeder unit // 3. Scan the coins --> Scanner unit // 4. Sort the coins --> Sorting unit // // +--------------------------+ // | Isolation | // | Coins unit | // | | | // | \ V / | +-------------------+ // | \ / | | Feeder unit | // | \ OOOOOO/ | | | // | \ OOOO/ | | \ O / | // | O O O O S2L | | S1 \ / | // | MB-------------------------------------------- o ______|__________ >>> // | conveyor belt | | MC| | // +--------------------------+ | | | // | | // +-------------------+ // +------------------+- // | Scanner | // | *._ unit | // | "*._ | // | "*._ | +--------------------------------------+ // | O "'._ | | Sorting unit | // >>> ----------------------------| | // | | |1ct 2ct 10ct 5ct 20ct 1€ 50ct 2€ | // | +--|--+ | +--------------------------------------+ // | |S2 S3| | | | | | | | | | | | | | | | | | // | ---| |------ | | | | | |O| |O| | | | | | | |O| // | | M3| | |O| | | |O| |O| | | |O| | | |O| // | +-----+ | |O| |O| |O| |O| |O| |O| |O| |O| // +------------------+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ // //------------------------------------------------------------------------------ // I have build a little machine, which realize this. The heart of this bot is // the LEGO Mindstorms RCX. The machine consists of 3 motors, 1 rotation // sensors and 2 light sensors. This devices are connected on the following // scheme: // // +-----------------------+ Sensors: // | +---+ +---+ +---+ | // | |Lgt| |Lgt| |Rot| | S1 : Light sensor of feeder unit // | |Fed| |Sen| |Sen| | // | +---+ +---+ +---+ | S2 : Light sensor of sensor unit // | 1 2 3 | // | View Prgm | S3 : Rotation sensor for sensor unit // | +-----------+ | // | | -8888 X 8 | | Motors: // | +-----------+ | // | On-Off Run | MA : Motor for feeder unit // | A B C | // | +---+ +---+ +---+ | MB : Motor for conveyor belt // | |Mot| |Mot| |Mot| | // | |Fed| |con| |Sen| | MC : Motor for sensor unit // | +---+ +---+ +---+ | // +-----------------------+ // //------------------------------------------------------------------------------ // On which way will the bot count the coins? // // Short description: // // The conveyour belt will serialize the coins and fill the feeder unit. The // Feeder unit will send coin by coin into the scanning unit where the RCX // recognize the type of coin. On the last step the coin will released by the // scanner unit and sorted into the slots of the sorter unit. // // Detail description: // // The program contains four background processes, which controlls the counting // process of coins: // // P1 : Feeding of coins // P2 : Displaying values of sensor values // P3 : Displaying status of coin detector sensors // P4 : Main control program // // P1: This background process delivers the coins from conveyor belt to feeder // unit. If no coin is available at feeder unit, the motor of conveyor belt // (MB) will be started. It stops, if there is recognized a coin at the // light sensor (S1) at feeder unit. If there will be no coin delivered for // MAX_WAIT_FOR_COIN from conveyor belt, the delivering process will stop. // // P2: I build this background process for debugging case. It shows the value // of the selected Sensor. You can select the sensors by pressing the button // VIEW at RCX: // 0 - no refresh for sensor value (default) // 1 - Display value of light sensor for feeder unit // 2 - Display value of light sensor for scanning unit // 3 - Display value of rotation sensor for scanning unit. // // P3: This background process shows the status of both light sensors. It shows, // by setting quarters at the circle on RCX, if there is a coin at the // sensor. The lower right quarter will symbolize the coin at sensor S1 - // the lower left quarter shows, if there is a coin at sensor S2. // // P4: Main background process! This process controls the delivery of coins from // feeder unit into scanner unit, scanning of coins and releasing into the // sorter unit. This process will divided into several steps: // // 1. Initialize global variables // 2. Fill the queue of feeder unit // 3. While coins are available do: // 3.1. Get next coin from feeder unit into scanning unit // 3.2. Scan the coin - get the coin type, display result and release it // 4. Calculate the total time for scanning process of all coins // 5. Display the result within a endless loop // // //------------------------------------------------------------------------------ // Additional functions: // // By pressing the button VIEW you can show the sensor values: // 0 - no periodically update of display (normal function) // 1 - show value of rotation sensor S1 (vertical position of sensor) // 2 - show the raw value of sensor S2T and S2L // 3 - show value of rotation sensor S3 (relative position to legt end) //------------------------------------------------------------------------------ // Display update for a normal process: // // // Init << Initialize the bot // // Repeat until coins are available // SErvE << Serve next coin from feeder to scanner unit // ScAn << Start of scan process // 1 ct .. 2 EUR << Show the detected coin type // #0.00€ << Show the actual total amount // // Repeat for all coins: // xxxxx << Show the name of the coin // ###0n << Show the number of the coin // #0.00€ << Show the amount of the coin // // TOTAL << Start of displaying of total displaying // ###0n << Show the total count of coins // #0.00€ << Show total amount of all coins // #0.00t << Show total time of scanning process // // End << End of Program (after pressing RUN button) // //------------------------------------------------------------------------------ // Electrical parts: 1 RCX // 1 Rotation sensor // 2 Light sensor // 3 9V Power motor 71427c01 //------------------------------------------------------------------------------ // Programming: brickOS 0.2.6 // // Why? Because brickOS is the best programming language // For the RCX! // // Many thanks to Marcus L. Noga and all the people who // developed brickOS! //------------------------------------------------------------------------------ //Pictures of the TypeWriter: // // Album: // http://festum.de/1000steine/myimages/CC8B // // Video: // http://festum.de/1000steine/album/CC8B/CC8b_Action_seperator_unit.mov // http://festum.de/1000steine/album/CC8B/CC8b_Action_feeder_unit_2.mov // http://festum.de/1000steine/album/CC8B/CC8b_Action_scanner_unit.mov // http://festum.de/1000steine/album/CC8B/CC8b_Action_sorter_unit.mov // http://festum.de/1000steine/album/CC8B/CC8b_Action_sorter_unit.mov // http://festum.de/1000steine/album/CC8B/CC8b_Feeder_unit_detail.mov // http://festum.de/1000steine/album/CC8B/CC8b_Filling_feeder_unit.mov // http://festum.de/1000steine/album/CC8B/CC8b_Filling_feeder_unit1.mov // http://festum.de/1000steine/album/CC8B/CC8b_LCD_scanner_in_action.mov // // Photo: // http://festum.de/1000steine/album/CC8B/TotalView1.jpg // http://festum.de/1000steine/album/CC8B/SeperatorUnit.jpg // http://festum.de/1000steine/album/CC8B/FeederUnit.jpg // http://festum.de/1000steine/album/CC8B/ScannerUnit.jpg // http://festum.de/1000steine/album/CC8B/SorterUnit.jpg // http://festum.de/1000steine/album/CC8B/SeperationUnit1.jpg // http://festum.de/1000steine/album/CC8B/SeperationUnit_coins.jpg // http://festum.de/1000steine/album/CC8B/FeederUnit_backstage.jpg // http://festum.de/1000steine/album/CC8B/FeederUnit_motor_sensor.jpg // http://festum.de/1000steine/album/CC8B/FeederUnit_Step1.jpg // http://festum.de/1000steine/album/CC8B/FeederUnit_Step2.jpg // http://festum.de/1000steine/album/CC8B/FeederUnit_Step3.jpg // http://festum.de/1000steine/album/CC8B/FeederUnit_Step4.jpg // http://festum.de/1000steine/album/CC8B/ScannerUnit_DetailMotor1.jpg // http://festum.de/1000steine/album/CC8B/ScannerUnit_DetailMotor2.jpg // http://festum.de/1000steine/album/CC8B/Scanning_1_WaitForCoin.jpg // http://festum.de/1000steine/album/CC8B/Scanning_2_CoinArrives.jpg // http://festum.de/1000steine/album/CC8B/Scanning_3_ScanReady.jpg // http://festum.de/1000steine/album/CC8B/Scanning_4_ReleaseCoin.jpg // http://festum.de/1000steine/album/CC8B/SortingUnit1.jpg // http://festum.de/1000steine/album/CC8B/SortingUnit_backstage.jpg // //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ // Including of brickOS routines //------------------------------------------------------------------------------ #include #include #include #include #include #include #include #include #include //------------------------------------------------------------------------------ // Constants //------------------------------------------------------------------------------ #define MAX_HASH 32 #define MAX_COIN 8 #define MAX_SCAN_AREA 0x0018 #define SCANNER_RELEASE_COIN 0x0022 #define MAX_WAIT_TIME 4000 // 4 s #define MAX_WAIT_FOR_COIN 8000 // 8 s #define MAX_WAIT_FIRST_COIN 20000 // 20 s #define TIME_TO_DISPLAY 500 // 0,5 s //------------------------------------------------------------------------------ // Output Macro //------------------------------------------------------------------------------ #define CONVEYOR_BELT_ON motor_b_dir( fwd ); motor_b_speed( MAX_SPEED ); #define CONVEYOR_BELT_OFF motor_b_speed( 0 ); motor_b_dir( brake ); #define FEEDER_FWD motor_a_dir( fwd ); motor_a_speed( MAX_SPEED ); #define FEEDER_REV motor_a_dir( rev ); motor_a_speed( MAX_SPEED ); #define FEEDER_STOP motor_a_speed( 0 ); motor_a_dir( brake ); #define FEEDER_ON FEEDER_FWD; #define FEEDER_OFF FEEDER_REV; msleep( 10 ); FEEDER_STOP; #define SCANNER_LEFT motor_c_dir( rev ); motor_c_speed( MAX_SPEED ); #define SCANNER_LEFT_SLOW motor_c_dir( rev ); motor_c_speed( MAX_SPEED/4 ); #define SCANNER_RIGHT motor_c_dir( fwd ); motor_c_speed( MAX_SPEED ); #define SCANNER_RIGHT_SLOW motor_c_dir( fwd ); motor_c_speed( MAX_SPEED/4 ); #define SCANNER_STOP motor_c_speed( 0 ); motor_c_dir( brake ); #define SCANNER_LEFT_STOP SCANNER_RIGHT; msleep( 10 ); SCANNER_STOP; #define SCANNER_RIGHT_STOP SCANNER_LEFT; msleep( 10 ); SCANNER_STOP; //------------------------------------------------------------------------------ // Input Macro //------------------------------------------------------------------------------ #define LIGHT_FEEDER LIGHT_1 #define LIGHT_SCANNER LIGHT_2 #define ROTATION_SCANNER ROTATION_3 #define COIN 0x002B #define FEEDER_COIN_DETECTED ( LIGHT_FEEDER > COIN ) #define SCANNER_COIN_DETECTED ( LIGHT_SCANNER > COIN ) #define END_OF_SCAN_AREA ( ROTATION_SCANNER > MAX_SCAN_AREA ) //------------------------------------------------------------------------------ // Defining complex structur //------------------------------------------------------------------------------ typedef struct // Complex structur for hash table. This { // structur contains the position of all int von; // possible left and right edges of the int bis; // coins. The RCX will compare the scanned int index; // values with the content of this struc- } // ture and get with index the right coin. CoinRef; // typedef struct // Complex structure with detail informa- { // tion of all coins. It contains the int value; // amount of one coin, the count of the int count; // scanned coins and the name of the coin. char name[6]; // This structure will be used by scanning } // and for displaying the result CoinInfo; // //------------------------------------------------------------------------------ // Defining of complex structure values //------------------------------------------------------------------------------ static const note_t Sound0[] // Melody to played on every detected = { // Frequenz Duration // { PITCH_C4, 4 }, // { PITCH_END, 0 } // }; // static const CoinRef coinref[ MAX_HASH ] // Information about coin sizes = { // right left index // { 0x0014, 0x0017, 0 }, // 1 ct coin { 0x0014, 0x0018, 0 }, // { 0x0015, 0x0017, 0 }, // { 0x0015, 0x0018, 0 }, // // { 0x000F, 0x0013, 1 }, // 2 ct coin { 0x0010, 0x0012, 1 }, // { 0x0010, 0x0013, 1 }, // { 0x0010, 0x0014, 1 }, // // { 0x000C, 0x000D, 2 }, // 5 ct coin { 0x000C, 0x000E, 2 }, // { 0x000C, 0x000F, 2 }, // { 0x000B, 0x000E, 2 }, // { 0x000B, 0x000F, 2 }, // // { 0x000E, 0x0011, 3 }, // 10 ct coin { 0x000E, 0x0012, 3 }, // { 0x000F, 0x0011, 3 }, // { 0x000F, 0x0012, 3 }, // // { 0x0009, 0x000D, 4 }, // 20 ct coin { 0x000A, 0x000C, 4 }, // { 0x000A, 0x000D, 4 }, // { 0x000B, 0x000C, 4 }, // { 0x000B, 0x000D, 4 }, // // { 0x0006, 0x0009, 5 }, // 50 ct coin { 0x0006, 0x000A, 5 }, // { 0x0006, 0x000B, 5 }, // { 0x0007, 0x000A, 5 }, // // { 0x0008, 0x000a, 6 }, // 1 € coin { 0x0008, 0x000b, 6 }, // { 0x0008, 0x000C, 6 }, // { 0x0009, 0x000C, 6 }, // // { 0x0004, 0x0007, 7 }, // 2 € coin { 0x0004, 0x0008, 7 } // }; static const CoinInfo coininfo[ MAX_COIN ] // Information about the coin = { // value count name // { 1, 0, "1 ct " }, // { 2, 0, "2 ct " }, // { 5, 0, "5 ct " }, // { 10, 0, "10 ct" }, // { 20, 0, "20 ct" }, // { 50, 0, "50 ct" }, // { 100, 0, "1 EUR" }, // { 200, 0, "2 EUR" } // }; //------------------------------------------------------------------------------ // Defining global variables //------------------------------------------------------------------------------ int feed_forbidden = 1; // Flag for control the serving process int no_more_feeding = 0; // Flag for control feeding process int total_sum; // Total amount over all scanned coins int total_count; // Total count over all scanned coins time_t total_time; // Total duration time for scanning //------------------------------------------------------------------------------ // This function displayed a given value with the format "#0.00". //------------------------------------------------------------------------------ void ShowAmount( int value ) { int rest; // Variable for displaying digit int pos; // Variable of rest of value pos=0; // Position for refreshing next digit cputs( " 000 " ); // Inital display _0.00_ while( value > 0 ) // While value is greater than zero { // rest = value % 10; // Compute the rest for next iteration value = value / 10; // Compute the digit for displaying pos++; // Increment position for display digit cputc( '0'+rest, pos); // Update the display at actual position } // dlcd_show( LCD_3_DOT ); // Show decimal point between pos 3 and 2 } //------------------------------------------------------------------------------ // This function displayed a given value with the format "###0". //------------------------------------------------------------------------------ void ShowNumber( int value ) { int rest; // Variable for displaying digit int pos; // Varialbe of rest of value pos=0; // Position for refreshing next digit cputs( " 0 " ); // Initial display ___0_ while( value > 0 ) // While value is greater than zero { // rest = value % 10; // Compute the rest for next iteration value = value / 10; // Compute the digit for displaying pos++; // Increment position for display digit cputc( '0'+rest, pos); // Update the display at actual position } } //------------------------------------------------------------------------------ // This function displayed the given time (ms) with the format "00.00_" // The given time will redimension from ms to s and recalculated from seconds to // a decimal format for output: // // value = 100 * ( ( t/1000 ) / 60 ) + ( ( t / 1000 ) % 60 ) // //------------------------------------------------------------------------------ void ShowTime( time_t t ) { int secs; // Converted value from ms to s int min; // Minute part of converted value int sec; // Seconds part of converted value int value; // Converted decemal value for displaying int rest; // Variable for displaying digit int pos; // Variable of rest of value secs = t / TICKS_PER_SEC; // Convert ms to s min = secs / 60; // Calculate the minutes for display sec = secs % 60; // Calculate the seconds for display value = min * 100 + sec; // Calculate the displaying value pos=0; // Position for refreshing next digit cputs( "0000 " ); // Inital display _0.00_ while( value > 0 ) // While value is greater than zero { // rest = value % 10; // Compute the rest for next iteration value = value / 10; // Compute the digit for displaying pos++; // Increment position for display digit cputc( '0'+rest, pos); // Update the display at actual position } // dlcd_show( LCD_3_DOT ); // Show decimal point between pos 3 and 2 } //------------------------------------------------------------------------------ // Move the scanner to initial position (right end) and reset the rotation // sensor of scanner unit. //------------------------------------------------------------------------------ void InitTheBot() { int pos_old; // Local value for old sensor value int pos_new; // Local value for new sensor value cputs( "Init " ); // Show the beginning process are started. pos_new=ROTATION_SCANNER; // Remember actual position of scanner SCANNER_RIGHT_SLOW; // Move scanner to right with slow speed do // Wait until there is no more movement { // at the scanner unit. pos_old = pos_new; // msleep( 200 ); // pos_new = ROTATION_SCANNER; // } // while ( pos_old != pos_new ); // ds_rotation_set(&SENSOR_3,0x0000); // Reset the sensor to 0 SCANNER_STOP; // Stop motor of scanner unit } //------------------------------------------------------------------------------ // Move Scanner unit to given position. If the destination position is 0, the // scanner unit will move fast near 0 and the rest will be moved slow to 0. //------------------------------------------------------------------------------ void MoveToPosition( int pos ) { if( pos > ROTATION_SCANNER ) // If destination position is left from { // actual position: SCANNER_LEFT; // Move scanner unit to left while( pos > ROTATION_SCANNER ) // Wait until position will be reached msleep( 10 ); // SCANNER_LEFT_STOP; // Hard stop of scanner unit } // else // If destination position is right from { // actual position: SCANNER_RIGHT; // Move scanner unit to right while( pos < ROTATION_SCANNER ) // Wait until position will be reached msleep( 10 ); // SCANNER_RIGHT_STOP; // Hard stop of scanner unit if( pos = 0 ) // If destination = 0 { // yes: Move little bit closer to 0 with SCANNER_RIGHT_SLOW; // low speed until position is 0 ... while( ROTATION_SCANNER > 0 )// msleep( 10 ); // SCANNER_RIGHT_STOP; // and than hard stop of scanner unit } // } // } //------------------------------------------------------------------------------ // This Procedure shows the complete result of scanning process. On first step // it displays all values of every coin, and at last the total sum of coint, // total amount und total time. // // Information for single coin type: 1 ct ###0n #0.00€ // 2 ct ###0n #0.00€ // 5 ct ###0n #0.00€ // 10 ct ###0n #0.00€ // 20 ct ###0n #0.00€ // 50 ct ###0n #0.00€ // 1 EUR ###0n #0.00€ // 2 EUR ###0n #0.00€ // // Sum and duration of scan process: TOTAL // ###0n // #0.00€ // #0.00t //------------------------------------------------------------------------------ void ShowResult() { int coin; // Iteration value for coin //--- Show for every coin: type, count and total coin amount for( coin=0; coin < MAX_COIN; coin++ ) // do for all coins: { // cputs( coininfo[ coin ].name ); // Display the name of coin msleep( TIME_TO_DISPLAY ); // Wait a short time // ShowNumber( coininfo[ coin ].count ); // Show count of coin with format cputc_0( 'n' ); // ###0n msleep( TIME_TO_DISPLAY ); // Wait a short time // ShowAmount( coininfo[ coin ].count * // Show total coin amount with coininfo[ coin ].value ); // the format #0.00€ cputc_0( 'E' ); // msleep( TIME_TO_DISPLAY ); // Wait a short time } // cputs( "TOTAL" ); // Signal the total values msleep( TIME_TO_DISPLAY ); // Wait a short time ShowNumber( total_count ); // Display total count of all coins cputc_0( 'n' ); // with format ###0n msleep( TIME_TO_DISPLAY ); // Wait a short time ShowAmount( total_sum ); // Display total amount of all coins cputc_0( 'E' ); // with format #0.00€ msleep( TIME_TO_DISPLAY ); // Wait a short time ShowTime( total_time ); // Display total time for scanning process cputc_0( 't' ); // with format 00.00t msleep( TIME_TO_DISPLAY ); // Wait a short time } //------------------------------------------------------------------------------ // This function delivered the next coin from feeder to scanning unit. If no // coin will pass the scanner (enter the scanning unit) after MAX_WAIT_TIME, // the function will give back 0. If the coins spinned into scanning unt, the // function have the result 1. //------------------------------------------------------------------------------ int DeliverNextCoin() { time_t start_time; // Local variable for timout-check //--- Start Coin Rotation Seperator until a coin will pass light sensor cputs( "SErvE" ); // Display Serve and start start_time = get_system_up_time(); // Remember the start time FEEDER_ON; // Rotate Feeder unit (MA) //--- Wait untili coin will pass the sensor, or this procedure is waiting //--- longer than MAX_WAIT_TIME for next coin (for this case, there is no //--- more coin waiting at feeder unit) while( ( ! SCANNER_COIN_DETECTED ) && ( ( get_system_up_time()-start_time ) < MAX_WAIT_TIME ) ) msleep( 10 ); FEEDER_OFF; // Stop the feeder unit //--- If there are no more coins, the function will return 0 //--- It's return 1, if there was a coin (less than 2 secs) for deliver. return ( ( get_system_up_time()-start_time ) < MAX_WAIT_TIME ); } //------------------------------------------------------------------------------ // This procedure scannes the coin at scanner unit and add the result to total // amount, total coin and increment the count of the recognized coin. This will // be done be several steps: // 1. Show the start of the process // 2. Move scanner to right end of scanner unit. // 3. Initialize variables for scanning process // 4. Move fast left to END_OF_SCAN_AREA position. By this way detect the // right and left side of the coin and compare this two values with the // hash-table coinref. // 5. Display the result (name of coin) and add the result // 6. Move left with scanner to SCANNER_RELEASE_COIN positon and lift up the // bar to release the coin // 7. Wait until coin passed the sensor again and move back to right end //------------------------------------------------------------------------------ void ScanTheCoin( ) { //--- Internal variables int status_old; // S2 Sensor state at last iteration int status_new; // S2 Sensor state for current iteration int von; // Position of right end of coin int bis; // Position of left end of coin int found; // Flag for founding a coin at hash table int coin; // Index on coininfo array int i; // Iteration index for hash table //-- 1. -- Show the start of process cputs( "ScAn " ); // Display SCAN on RCX //-- 2. -- Move to right border of scanning unit MoveToPosition( 0 ); // Move to right position (S3=0) //-- 3. -- Initialize the local values von=-1; // Reset right border of coin bis=-1; // Reset left border of coin dlcd_hide( LCD_CIRCLE_0 ); // Clear LCD segments dlcd_hide( LCD_CIRCLE_1 ); // status_old = SCANNER_COIN_DETECTED; // Remember state of light sensor //-- 4. -- Move fast left to END_OF_SCAN_AREA position. By this way detect // the right and left side of the coin ... SCANNER_LEFT; // Move very fast left and scan ... while( ! END_OF_SCAN_AREA ) // While end of scan range not reach { // status_new = SCANNER_COIN_DETECTED; // Read actual light sensor state // if( status_old != status_new ) // Compare it with old one. If { // not same: if( status_old != 0 ) // If old not background: { // bis=ROTATION_SCANNER; // Remember right dlcd_show( LCD_CIRCLE_0 ); // Show scan process } // else // If old is coin: { // von=ROTATION_SCANNER; // Remember left dlcd_show( LCD_CIRCLE_1 ); // Show scan process } // } // status_old=status_new; // Remember state for next loop // msleep( 10 ); // Wait a little moment } SCANNER_LEFT_STOP; // Hard stop of the scanner //--- ... and search for coin at hash table. found=0; // Reset coin flag for( i=0; i Set found-flag coin=coinref[i].index; // // //--- 5. Display the result and add the result // cputs( coininfo[ coin ].name ); // show coin type // coininfo[ coin ].count++; // Store Info and total_sum+=coininfo[coin].value; // Add value to total_sum total_count++; // Increase total_count // } // if( found == 0 ) // If not found at coin array { // cputw( von ); // Show right value with format cputc_0( 'v' ); // ####v sleep( 2 ); // Wait a little // cputw( bis ); // Show left value with format cputc_0( 'b' ); // ####b sleep( 2 ); // Wait a little // cputw( bis-von ); // Show width of coin with format cputc_0('L' ); // ####L } // Wait a little //-- 7. -- Wait until coin passed the sensor again and move back to right end sleep( 1 ); // Wait 1 sec for displaying result MoveToPosition( SCANNER_RELEASE_COIN ); // Release the coin out of scanner //--- Wait, until coin passed the light sensor and escaped the scan area while( ! SCANNER_COIN_DETECTED ) // While coin doesn't passed sensor msleep( 20 ); // Wait a little moment msleep( 200 ); // Wait a additional moment //--- Show total sum over all scanned coins ShowAmount( total_sum ); // Display total sum as "#0.00€" cputc_0( 'E' ); // //--- Move back to right border of scan area and wait for next scan process MoveToPosition( 2 ); // Wait position for next coin ... } //------------------------------------------------------------------------------ // Start the convoyer belt and wait until MAX_WAIT_FIRST_COIN time for frist // coin. If the coin will pass the light sensor of feeder less than // MAX_WAIT_FIRST_COIN seconds, the routine will return 1 - at the other case, // it will return 0. This routine will only be used at the beginning to fill up // the feeder unit. After this, the background process Task_FeedWithCoins will // do the rest to fill up the feeder unit. //------------------------------------------------------------------------------ // Return value: // 0 : No coin detected after MAX_WAIT_FOR_COIN // 1 : Queue of feeder unit is filled //------------------------------------------------------------------------------ int FillTheFeeder() { time_t start_time; // Local value for timeout-check feed_forbidden = 0; // release feeder process start_time = get_system_up_time(); // get timestamp //--- Wait for next coin from conveyer belt - but only max 5 seconds. while( ( ( get_system_up_time()-start_time ) < MAX_WAIT_FIRST_COIN ) && ( ! FEEDER_COIN_DETECTED ) ) msleep( 10 ); //--- If a timeout, return 0. On the other case return 1 return ( ( get_system_up_time()-start_time ) < MAX_WAIT_FIRST_COIN ); } //------------------------------------------------------------------------------ // This process shows the value of a sensor. It depends on the value of the // variable displaying. This variable can be set by pressing the button VIEW at // RCX: // // 0 : No refresh of sensor value // 1 : Rotation sensor S1 - Feeder unit // 2 : Light sensor S2 - Detecting unit // 3 : Rotation sensor S3 - Sorting unit // // I added this background process for programing analyzes. It doesn't have a // productive function for the bot. //------------------------------------------------------------------------------ void Task_Displaying( int argc, char **argv ) { int displaying = 0; // Internal index for value while( 1 ) // Do forever { // if( PRESSED( dbutton(), BUTTON_VIEW ) ) // { // while(PRESSED(dbutton(),BUTTON_VIEW )) // Wait until button VIEW will msleep( 50 ); // be released // if( displaying < 3 ) // Increment the sensor selek- displaying++; // tor - and if it is greater else // then 3 - reset it to zero. displaying = 0; // } // switch( displaying ) // Display the value of { // slected sensor case 0 : break; // // 0 : don't refresh display case 1 : cputw( LIGHT_FEEDER ); // cputc_0( '1' ); // 1 : Refresh display with break; // value of sensor S1 and // use format ###01 case 2 : cputw( LIGHT_SCANNER ); // cputc_0( '2' ); // 2 : Refresh display with break; // value of sensor S2 and // use format ###02 case 3 : cputw( ROTATION_SCANNER ); // cputc_0( '3' ); // 3 : Refresh display with break; // value of sensor S3 and } // use format ###03 msleep( 50 ); // Wait a little moment for } // next refresh } //------------------------------------------------------------------------------ // This background task displayed the status of S1 and S2. If a coin will pass // sensor S1 (light sensor at feeder unit), the lower right quarter of the LCD // circle will visible. The same funktion with the lower left quarter is imple- // mented for the sensor S2 (light sensor at scanner unit). This task is also // only for information and not importand for the work of the CoinCountB bot. //------------------------------------------------------------------------------ void Task_DetectionLight( int argc, char **argv ) { while( 1 ) // Do forever { // if( SCANNER_COIN_DETECTED ) // If a coin pass light sensor of { // scanner unit, show the lower dlcd_show( LCD_CIRCLE_2 ); // right quarter at LCD display and dsound_play( Sound0 ); // play a little beep. } // else // If not, hide this quarter. dlcd_hide( LCD_CIRCLE_2 ); // // if( FEEDER_COIN_DETECTED ) // If a coin pass light sensor of dlcd_show( LCD_CIRCLE_3 ); // feeder unit, show the lower else // left quarter at LCD display dlcd_hide( LCD_CIRCLE_3 ); // If not, hide this quarter. // msleep( 50 ); // Wait a little moment for next } // refresh } //------------------------------------------------------------------------------ // This background task is importand! It brings the coins from conveyor belt to // the feeding unit. If the light sensor of feeding unit (S1) doesn't recognize // a coin, the task start the conveyor belt (MB) until the feeder queue is // filled (coin at light sensor S1). If the feeder queue filled, the motor for // conveyor belt (MB) stopped. // Additional the task runs in timeout, if the time for next coin on light sen- // sor S1 are more then MAX_WAIT_FOR_COIN. If this happend, the global flag // no_more_feeding will be set and signal the main task, that there are no more // coins available. //------------------------------------------------------------------------------ void Task_FeedWithCoins( int argc, char **argv ) { time_t start_time; // Local variable for timeout-check while( 1 ) // Do forever { // if( ! feed_forbidden ) // If not feed_forbidden { // if( ! FEEDER_COIN_DETECTED ) // If no coin at sensor S1 { // CONVEYOR_BELT_ON; // Start conveyor belt start_time=get_system_up_time();// Remind the start timestamp //--- While no coin at sensor and no timeout ... while( ( ! FEEDER_COIN_DETECTED ) && ( ! no_more_feeding ) ) { //--- Check for timeout - more than MAX_WAIT_FOR_COIN time is done if( ( get_system_up_time()-start_time ) > MAX_WAIT_FOR_COIN ) no_more_feeding=1; // set flag, if timeout is happened // msleep( 10 ); // Wait a little for next check } // // CONVEYOR_BELT_OFF; // Stop conveyor belt } // } // msleep( 50 ); // Wait a little for next check } } //------------------------------------------------------------------------------ // This is the main background process. It controls the complete scanning pro- // cess and displayed the result at end in a endless loop: // 1. Initialize global variables // 2. Fill the queue of feeder unit // 3. While coins are available do: // 3.1. Get next coin from feeder unit into scanning unit // 3.2. Scan the coin - get the coin type, display result and release it // 4. Calculate the total time for scanning process of all coins // 5. Display the result within a endless loop //------------------------------------------------------------------------------ void Task_MainControl( int argc, char **argv ) { time_t start_time; // Local variable for start time int more_coins; // Local flag for control //-- 1. -- Initialize global and local variables start_time = get_system_up_time(); // Get timestamp for start total_sum = 0; // Reset total_sum of coins total_count = 0; // Reset total_count of coins more_coins = 1; // Set flag "more_coins" for start //-- 2. -- Fill the queue of feeder unit FillTheFeeder(); // Wait until first coin are waiting //-- 3. While coins are available ... while( more_coins ) // While more coins available { // //-- 3.1. -- Get next coin // // if( DeliverNextCoin() ) // If next coin was delivered { // sleep( 1 ); // wait until coin stands still //-- 3.2. -- Scan the coin and release it after displaying the result ScanTheCoin(); // Start scan process of coin } // else // If there are no more coins ... more_coins = 0; // reset the flag "more_coins" // msleep( 10 ); // Give a chance to other processes } // //-- 4. -- Calculate the total time for scanning process of all coins total_time = get_system_up_time() - start_time; // calculate total time //-- 5. -- Display the result at end within a endless loop while( 1 ) // Show the complete result within ShowResult(); // a endless loop } //------------------------------------------------------------------------------ // Main program // // The main program prepare the hardware and initilize the CoinSorter1, started // the background processes and wait for termination by pressing the RUN button // at RCX. The complete control of coin detecting is done by background process // Task_MainControl. After pressing the RUN butten, the background processes // will be stopped and the hardware reseted. // // 1. Wait for releasing the RUN button // 2. Define sensors // 3. Initialize the CoinCounter1 bot // 4. Start background processes // 5. Wait for termination of process by user // 6. Stop background processes // 7. Stop all motors // 8. Reset the sensors // 9. Signal end of program //------------------------------------------------------------------------------ int main( ) { tid_t tid_Displaying; // Local variables for background tid_t tid_DetectionLight; // processes tid_t tid_FeedWithCoins; // tid_t tid_MainControl; // //-- 1. -- Wait for releasing the RUN button while( PRESSED( dbutton(), BUTTON_RUN ) ) msleep( 20 ); //-- 2. -- Define sensor ds_active( &SENSOR_1 ); // Light Sensor of seperation unit ds_active( &SENSOR_2 ); // Light Sensor of detection unit ds_active( &SENSOR_3 ); // Rotation Sensor of detection unit ds_rotation_set( &SENSOR_3, 0x0000 ); ds_rotation_on( &SENSOR_3 ); //-- 3. -- Initialize the CoinCounter1 bot InitTheBot(); //-- 4. -- Start all background processes tid_Displaying = execi( &Task_Displaying, 0, NULL, 0, DEFAULT_STACK_SIZE ); tid_DetectionLight = execi( &Task_DetectionLight, 0, NULL, 0, DEFAULT_STACK_SIZE ); tid_FeedWithCoins = execi( &Task_FeedWithCoins, 0, NULL, 0, DEFAULT_STACK_SIZE ); tid_MainControl = execi( &Task_MainControl, 0, NULL, 0, DEFAULT_STACK_SIZE ); //-- 5. -- Wait until user will terminate the program by pressing RUN button while( ! PRESSED( dbutton(), BUTTON_RUN ) ) msleep( 50 ); //-- 6, -- Kill background processes kill( tid_MainControl ); kill( tid_FeedWithCoins ); kill( tid_DetectionLight ); kill( tid_Displaying ); //-- 7. -- Stop all motors CONVEYOR_BELT_OFF; FEEDER_OFF; SCANNER_STOP; //-- 8. -- Reset all sensors ds_passive( &SENSOR_1 ); ds_passive( &SENSOR_2 ); ds_passive( &SENSOR_3 ); //-- 9. -- Signal end of program cputs( "End " ); return 0; } //------------------------------------------------------------------------------ // CoinCountB.c - End of program //------------------------------------------------------------------------------