I know how to solder and build hardware, and I know how to program software. I do not know the current most appropriate readily available, low-cost, low-power reliable components to build clickers and clackers, defined as follows. A clicker is a handheld box with 8 buttons and 1 of 32 codes. The box contains a microprocessor, a radio transmitter, and an easily replaceable battery power supply. When a button is pressed the clicker radio transmitter emits 1 byte of data identifying the button with 3 bits and the clicker with 5 bits. Transmitter range need be no more than 200 feet. A clacker is a device in a small box containing a radio receiver and a microprocessor that is powered by and corresponds via USB with an application program running under Windows XP (or later Microsoft OS). The application program user interface includes a start button and a stop button. The program maintains in RAM a 32 row by 8 column bit array and is normally in an idle loop waiting for the start button to be pressed. When the start button is pressed the array is set to all 0's and the program enters a loop ready to receive data bytes from up to 32 clickers. If a byte arrives then a 1 is entered in the correct row and column of the clicker code and clicker button. When the stop button of the user interface is pressed then the array is recorded as a (sequentially numbered) CSV file on hard disk in a previously designated folder. Then the program re-enters its idle loop waiting for the start button to be pressed. My question is, what are the most appropriate readily available, low-cost, low-power, and reliable radio transmitter, radio receiver, microcontroller and USB modules or chips for building clickers and clackers? E. D. Cooper, XTALV1@NETROPOLIS.NET
what are the most appropriate readily available, low-cost, low-power, and reliable radio transmitter, radio receiver, microcontroller and USB modules or chips for building clickers and clackers
That's like saying what is the most reliable way to build a car. If the answer was as simple as a forum answer then electronic engineers would be out of a job (which I am at the moment).
I would say your biggest problem is getting only one clicker to transmit at a time, the classic collision avoiding problem. This is normally solved with some sort of two way protocol. Also 200ft is a long way in the small radio data field especially if there are things in the way.
This sounds like a commercial project, is it?
Grumpy_Mike wrote:
That's like saying what is the most reliable way to build a car.
It was supposed to be like, I know there are many alternative technologies, here is the ideal towards which I aim, without expecting to truly achieve it, but I would welcome adherents of different viewpoints on different products to suggest their preferences.
I would say your biggest problem is getting only one clicker to transmit at a time, the classic collision avoiding problem.
I am a teacher and would have one clacker, and each student would have one clicker. The application program running my clacker would display the total table of results each time a click is received, including the identifier of the clicker. If the student with that clicker does not see their result posted on the projection of the table of results in front of the classroom, then they would press their button again. That is how the feedback loop is closed.
This sounds like a commercial project, is it?
I suppose it could be, and in truth, that dark thought festers in the back of my mind. But I would be just tickled pink to have a clacker-clicker system for my one classroom.
Richard Crowley wrote:
Here is a tutorial comparing various wireless TX/RX products which are popular for use with Arduino
This is precisely the sort of reply I hoped to get by posting my query to this forum. Thank you!
This subject came up several months ago. As I recall, someone posted a link to an existing commercial system, but it was too expensive for the original poster's limited budget (I think he was volunteering to help out a teacher friend/relative).
then they would press their button again. That is how the feedback loop is closed.
That's a very important design decision: closing the loop that way will save quite a bit of cost, because it keeps the RF communication one-way. However, you need to look carefully at the rate of collisions, and whether it will lead to frustrated kids beating the (bleep) out of your "clickers". Especially if there's a competitive aspect (intended or not) to their use: it's inevitable that some of the kids who come up with the answers first will find themselves needing to retry due to collisions.
Another, easily-overlooked, factor that came up in the previous discussion was designing the "clickers" so it's easy to recharge them. Preferably without an easily-removed battery that would tempt idle hands and curious minds. Look to walkie-talkies and cordless phones that use "charging cradles" for examples.
The iClicker products (www.iclicker.com) are quite affordable at a low per-student cost, and comes with software which (together with the USB base) implement the "clacker" function. On the distributor's website (www.sunburst.com) $1200 gets you the base+software and 24 clickers. IMHO you'd never roll your own and outfit 24 students, for that price.
It would be interesting to try, though
Collisions and retransmits are handled automatically, and the handheld units use batteries which last for months. The software meets the requirements stated in this thread.
I'm not affiliated with iClicker in any way, but have adapted their software for a non-classroom application.
MLuckham wrote:
It would be interesting to try, though
On a previous teaching job I used the iClicker system quite successfully. There is no way my current employer nor I could afford the sticker price of the iClicker system. So, yes, the whole point of my inquiry on this forum is to make a determination about whether I can roll my own.
I am uncertain about the need to be concerned with collisions. If the one byte per student could be transmitted in, say, 1 millisecond, then a second byte must be within 3 milliseconds to collide with a first byte. If the time that the teacher waits for 32 bytes is, say, 10 seconds, then 3 divided by 10,000 is the probability that two bytes collide. Multiply by 32 students taken 2 at a time comes to 3*496/10,000, or a probability of about 15%. So, at most a few students might have to click more than once. I look forward to your letters, as Craig Ferguson would say.
After people finish trashing my analysis then I would like to get back to the original question, specifically about whether, say, radio control chips for model airplanes and the like might be inexpensive and not require government approval, which appears to be a possible obstacle for some of the RF transmitter chips in the US.
I am also unclear about whether the USB capability -- which evidently comes with the arduino for development -- could be used for the clacker functionality without much work.
If the time that the teacher waits for 32 bytes is, say, 10 seconds, then 3 divided by 10,000 is the probability that two bytes collide.
That assumes the distribution of the responses is random. But that's only true if you're a bad teacher ;D
If the students have learned well, their responses are going to be clustered around the "average recall and thinking time". So the probability of collision is actually higher.
You can reduce the number by using multiple frequencies. Cheap consumer RF remotes are available on multiple bands, and may be tunable to different segments of those bands. Then you'd only have a few transmitters competing on each frequency.
Some of them probably do multiple transmissions to improve reliability, though. That would increased the number of collisions. Be sure to read the spec sheets carefully.
Why not try a fairly inexpensive test? Get 3 Prominis or RBBs from Modern Devices, a few dollars cheaper but different footprint) , a 434Mhz receiver and two 434MHz transmitters that Sparkfun carries.
MO-RX3400, WRL-08950 RX
MO-SAWR, WRL-08946 TX
Wire up two simple transmitters with a push button each and output 1 byte of data, different for each (0 & 1 for example), and the transmitter with simple code to display the data received.
Use the VirtualWire code on all 3. The transmitters can be run off 3 AA batteries to start (and change to 3.7VLI Ion battery with charger chip later on form 5V source).
The Remotes could be this simple - with just one button (vs my 16). The remote is in powerdown sleep mode all the time, the button press wakes it with interrupt and sends out preprogrammed code (or read a jumper field and send the value there so that all remotes can be programmed identically), then goes back to sleep. LED13 flashes for visual check that battery is charged enough to transmit.
The empty socket in my picture is for the Li Ion battery charger chip (battery is under the board) that I haven't tried out yet (trying to get my 8 digit multiplexed display to work with MAX7221 as the driver, just updated the wiring & code last night, not home today).
Box can be whatever size you need to mount the few parts, the button, and a power jack for charging. These little Really Useful Boxes (online, got mine at Staples) are easy to work with.
The receiver would be similar - the promini, the receiver module, DC power from wallwart, serial output to PC screen for display, or 24 LEDs (one for each remote), etc.
The Remote could be simplified from my 16 button code:
// transmitter_mine_updated_Simon_Bell_DiodeOr.pde
// have to double Serial.Begin value with 8MHz ProMini
// have to double VirtualWire Bits/sec in Setup with 8MHz ProMini
// ALL SERIAL PRINTS COMMENTED OUT
// started with the code from this example
// http://www.arduino.cc/playground/Learning/arduinoSleepCode
// with sleep function called -> 0.357mA! should be 175 days on 1500mAH batteries
// down from 8.95 mA in normal idle mode -> just 7 days
// with bursts of ~14-15mA when a keypress is transmitted
// Processor: Arduino Mini-Pro running on PC USB power
// (ran on 3 AA batteries fed into VCC line prior to this Interrut attempt)
// Keypad: Velleman 4x4 Matrix
// RF Link Transmitter - Sparkfun MO-SAWR-A, 434MHz, WRL-08946
// Simple example of how to use VirtualWire to transmit messages
// Implements a simplex (one-way) transmitter with RF module.
// See VirtualWire.h for detailed API docs
// Author: Mike McCauley (mikem@open.com.au)
// Copyright (C) 2008 Mike McCauley
// $Id: transmitter.pde,v 1.3 2009/03/30 00:07:24 mikem Exp $
// uses default pin 12 for transmit data
// uses default pin 11 for receive data
// added Keypad example from playground
// modified to send character in a buffer to the receiver from 4x4 matrix
// Velleman 4 x 4 matrix keypad
// keypad 1 (Col1) to D10
// keypad 2 (Col2) to D9
// keypad 3 (Col3) to D8
// keypad 4 (Col4) to D7
// keypad 5 (Row1) to D6
// keypad 6 (Row2) to D5
// keypad 7 (Row3) to D4
// keypad 8 (Row4) to D3
// Rows have Internal Pullups
// Row 1, 2, 3, 4 Diode AND'D to D2 (INT0) to pull it low on a keypress
// Interrupt on D2 "wakePin" LOW - Input with Internal pullup
// D0, D1, D14, D15, D16, D17, D18, D19 set as inputs with internal pullups enabled
// end of notes
// ***********************************************************************
// bring in the library(s)
#include <VirtualWire.h> // Wireless transmitter/receiver library
#include <Keypad.h> // Matrix Keypad library
#include <avr/sleep.h> // powerdown library
#include <avr/interrupt.h> // interrupts library
// ***********************************************************************
// define unused pins
int dpin0 = 0; // apparently redefined by Serial as Serial Monitor works
int dpin1 = 1; // apparently redefined by Serial as Serial Monitor works
int pin2 = 2; // Int0 interrupt pin
int dpin14 = 14;
int dpin15 = 15;
int dpin16 = 16;
int dpin17 = 17;
int dpin18 = 18;
int dpin19 = 19;
// ***********************************************************************
// define the used pins
#define ledPin 13 // activity indicator, use for brief flash when transmit
// don't need to define pin12, handled by VirtualWire as default data_out pin to the transmitter
int sleep_count = 0; // flag/counter to tell us to go sleep
// ***********************************************************************
// create an array to store data to be sent out
char msg[1];
// set up the Keypad
const byte ROWS = 4; // Four rows
const byte COLS = 4; // Four columns
// Define the Keymap
char keys[ROWS][COLS] =
{
{ '1','2','3','A' } , // row 1
{ '4','5','6','B' } , // row 2
{ '7','8','9','C' } , // row 3
{ '*','0','#','D' } , // row 4
};
// Connect keypad ROW1, ROW2, ROW3 and ROW4 to these Arduino pins.
byte rowPins[ROWS] = { 6, 5, 4, 3 }; // Keypad uses internal pullups? No externals supplied
// these pins have separate external Diodes, anodes connected to Pin2 (Int0)
// Column pins are set low just before shut down,
// and Pin2 is pulled high internally.
// Pressing a Row button connects to a Low Columna and pulls the appropriate Row Diode Low for a Pin2 Low interrupt.
// Column pins are then set back high for the keypad library button determination.
// Connect keypad COL1, COL2, COL3, COL4 to these Arduino pins.
byte colPins[COLS] = { 10, 9, 8, 7 };
// Create the Keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
//***************************************************
// * Name: pin2Interrupt, "ISR" to run when interrupted in Sleep Mode
void pin2Interrupt()
{
/* This brings us back from sleep. */
}
//***************************************************
// * Name: enterSleep
void enterSleep()
{
/* Setup pin2 as an interrupt and attach handler. */
attachInterrupt(0, pin2Interrupt, LOW);
delay(50); // need this?
/* the sleep modes
SLEEP_MODE_IDLE - the least power savings
SLEEP_MODE_ADC
SLEEP_MODE_PWR_SAVE
SLEEP_MODE_STANDBY
SLEEP_MODE_PWR_DOWN - the most power savings
*/
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // setting up for sleep ...
sleep_enable(); // setting up for sleep ...
sleep_mode(); // now goes to Sleep and waits for the interrupt
/* The program will continue from here after the interrupt. */
detachInterrupt(0); //disable interrupts while we get ready to read the keypad
/* First thing to do is disable sleep. */
sleep_disable();
// set all the keypad columns back high so can read keypad presses again
digitalWrite(7, HIGH);
digitalWrite(8, HIGH);
digitalWrite(9, HIGH);
digitalWrite(10, HIGH);
// then go to the void Loop()
}
// ***********************************************************************
// set up the pins as Inputs, Outputs, etc.
void setup()
{
/* Setup the pin directions, write inputs High to turn on internal pullups */
pinMode(pin2, INPUT); // our sleep interrupt pin
digitalWrite(pin2, HIGH);
// define all the unused pins as inputs with internal pullups for lower power state
pinMode(dpin0, INPUT); // apparently redefined by Serial as Serial Monitor works (receiving anyway)
digitalWrite(dpin0, HIGH); // apparently redefined by Serial as Serial Monitor works
pinMode(dpin1, INPUT); // apparently redefined by Serial as Serial Monitor works
digitalWrite(dpin1, HIGH); // apparently redefined by Serial as Serial Monitor works
pinMode(dpin14, INPUT);
digitalWrite(dpin14, HIGH);
pinMode(dpin15, INPUT);
digitalWrite(dpin15, HIGH);
pinMode(dpin16, INPUT);
digitalWrite(dpin16, HIGH);
pinMode(dpin17, INPUT);
digitalWrite(dpin17, HIGH);
pinMode(dpin18, INPUT);
digitalWrite(dpin18, HIGH);
pinMode(dpin19, INPUT);
digitalWrite(dpin19, HIGH);
// default pin for data to be transmitted out
// pinMode(dpin12, OUTPUT); // taken care of by VirtualWire
// // VirtualWire takes care of 11 also.
digitalWrite(ledPin, LOW); // pin 13, turn off the LED
// Serial.begin(9600); // need for debug monitoring only with FTDI connected via USB to PC
// Serial.println("TX setup"); // for debug only
// ***********************************************************************
// Initialise the IO and ISR for VirtualWire
vw_setup(4000); // Bits per sec - had to double from 2000 with 8MHz 3.3V Pro-Mini
} // end of void Setup()
see next message for void loop
void loop
// ***********************************************************************
// Main loop for reading the keypad and sending the button pushed out
// (with a unique address to be added eventually by reading 0-F from currently unused pins)
void loop()
{
if (sleep_count>1000){ // check if we should go to sleep because of "time" --> Try shorter versions of this
sleep_count=0; // turn it off for when we wake up
// Serial.println("Sleep"); // for debug only
// set the columns low before sleeping, otherwise Keypad leaves them high and Rows have nothing to pull low.
digitalWrite(7, LOW);
digitalWrite(8, LOW);
digitalWrite(9, LOW);
digitalWrite(10, LOW);
delay(100); // need this?
enterSleep(); // call Sleep function to put us out
// THE PROGRAM CONTINUEs FROM HERE after waking up in enterSleep()
} // end of checking to go to sleep
// go read the keypad
char key = keypad.getKey(); // reading the keypad
if(key) // same as if(key != NO_KEY)- did something change?
{
msg[0]=key; // load the array with the key character
// msg[1]=NULL; // Rx side seems to work without this
digitalWrite(ledPin, true); // Flash a light to show transmitting
vw_send((uint8_t *)msg, strlen(msg)); // send the character out
// Serial.println(key); // for debugging only
vw_wait_tx(); // Wait until the whole message is gone
delay (50); // need some delay or seem to miss key presses
digitalWrite(ledPin, false); // turn off the flash of LED
sleep_count = 0; // reset count up to sleep if transmitted a key press
} // end of if(key) & transmitting a character
sleep_count = sleep_count+1; // start counting to go to sleep
} // end of void loop