Here is a simple code that reads a PWM signal and calculates its frequency and duty cycle in real time. The lack of an oscilloscope motivated this code.
The star of the show is the built-in 'pulseIn()' function, which gives the length of a low or high pulse. With these two measurements the calculation of duty cycle and frequency of the PWM signal is straightforward.
I have two different versions, simple and slightly longer.
The slightly longer code takes a user-specified time delay over which the maximum length is taken to help prevent truncation of a signal. For example, if an input pulse of 10 ms has already been running for 2 ms and the pulseIn function is called, it may return 8 ms. I am actually not sure if this is the way pulseIn works, but I tried both. With the default Arduino PWM frequency of approximately 490 Hz (http://arduino.cc/en/Reference/analogWrite), the slightly longer code returns 490 +/- 3 Hz, while the simple code returns 500 +/- 3 Hz. I tested this over low and high duty cycles. So it appears the slightly longer code has slightly better accuracy.
Simple code:
//Reads a PWM signal's duty cycle and frequency.
#define READ_PIN 13
#define PWM_OUTPUT 10
static double duty;
static double freq;
static long highTime = 0;
static long lowTime = 0;
static long tempPulse;
void setup(){
pinMode(READ_PIN,INPUT);
Serial.begin(9600);
analogWrite(PWM_OUTPUT,230);
}
void loop(){
readPWM(READ_PIN);
Serial.println(freq);
Serial.println(duty);
}
//Takes in reading pins and outputs pwm frequency and duty cycle.
When reading strings through Arduino Serial, I usually make a string variable and concatenate onto it as each Serial.read() character comes in.
Suppose Serial communication occurs one string at a time. If you collect each string with a while(Serial.available()) loop, a problem arises. The first three characters, if the string is longer than three characters, is truncated. Why?
I fixed this problem by adding a small delay (~5 ms, could be less, I did not play with it and it depends on the amount of code between the delay and character reception) after every three characters. It appears Serial communication is done in packets of three, with a small delay in between, making Serial.available() false every three characters for a brief period of time.
It is easy to hook up and use a character display to an Arduino. Turns out, a specific driver that comes with LCD displays that is very common is the HD44780 driver and there is an Arduino library specifically for it: LiquidCrystal.
It is very easy to use in software and in hardware. The following picture is from the documentation for my screen that I bought on eBay (JHD-204A), showing the pin configuration and power characteristics.
The official Arduino documentation on LiquidCrystal is all you need and it can be found at: http://www.arduino.cc/en/Tutorial/LiquidCrystal. Actually no other parts than connecting wires are required. The potentiometer mentioned in the above reference is just for contrast adjustment.
I personally prefer wire wrapping to soldering when I can, mainly because I am not good at soldering and I do not like toxic fumes. Here I had to solder the header pins onto the LCD display pins, but after that wire wrapping all the way. It was fun. Wire wrapping wire and header pins are an awesome combination.
One inevitably runs into errors when installing the driver for the Arduino Uno on my Windows 7 PC. I thought it was just an error on my computer specifically but apparently it is the norm for now. The solution is found on the official Arduino website here. They acknowledge that the error occurs no matter what, "despite [Window's] best efforts".
Here we look at a full-range servo turret controlled wirelessly by Arduino via Xbee modules. The title says "fps" because if you were to have the point of view of the pencil tip, the joystick would control like an fps video game.
It works by moving the turret whenever the joystick is moved outside the neutral center position, and stays at whatever position its at when the joystick is moved back to the center position. Just like an fps video game.
You may have noticed, one joystick is superfluous in this demo. That will be used when (or if) I create an "fps bot", which would have a live wireless camera, omni wheels, and other things to allow for an fps control of a physical robot that has all of the movement freedom of a typical fps video game.
This project utilized Xbee modules with the FTDI-ready adapter that can be found at www.adafruit.com, Arduino Duemilanove, HS-311 Standard servos, and these adafruit.com joysticks.
Here's an Arduino Reference, if you need it. For the Xbees, plenty of resources online can help you configure and set it up. Good luck!
Below are two codes, one for the controller and one for the reciever. If you guys need help, comment on my corresponding Youtube video and I will try to get to it, as I am on Youtube quite often.
Controller code:
//CONTROLLER CODE //Feel free to use this code however you like, but please credit lordvon and this site! //'ud' and 'lr' are the pot signals for the up/down and left/right pots, respectively.
//(Joysticks and their pot values are not perfect, so some things have to be empirically //determined. The serial read function is a great tool for collecting the values.) //range of ud: 29-1014 (middle: around 479-540; avg:~510, center:+/-35) //range of lr: 0-960 (middle: around 419-471; avg:445, center:+/-30) //minimum range extreme (from avg) magnitude: 445 //maximum tolerance value: 35
//Print values as 'topic:value', where 'topic' denotes either 'ud' or 'lr', //and 'value' is the associated pot value. //Reciever is prompted to record by ':', and ended by ','.
//"" gives characters, '' gives characters in integer form.
Here we describe how to set up a full-range 3-servo turret controlled by a Nintendo DS touchscreen and Arduino Duemilanove with an ATMega328 microcontroller. The magnitude of the distance from the center of the touchscreen to the touched position will control the angle of the servo on top for elevation, while the azimuth, or rotation of the ground plane, will be controlled by basically polar coordinates on the DS touchscreen.
It's just a demo; I did this to become familiar with Arduino microcontrollers. You can mount a bb gun controlled by a simple switch. Making it wireless may be one of my next projects.
One of the things that make the Arduino really easy to use is the libraries. These are basically sets of functions that achieve a certain category of tasks. In this project we use the "Servo" library. Information on this library can be found here.
Below is the code. The ranges of movement corresponding to the ranges of touch can be easily adjusted by changing the constants defined at the beginning, so you can make the turret easier to use.
Circuit details: --See code comments for connections to the touchscreen (X1,Y2,X2,Y1,Xin,Yin). --Connect the servos (HT-311) to an appropriate power source (red to positive, black to negative). --Group the signal wires (yellow) of the azimuth (ground-plane) servos together and connect them to digital pin 11. --Connect the elevation servo signal wire to digital pin 12. --Be sure to connect the ground of the arduino to the ground of the servo power supply. I do not know why this is necessary, haha, and it took me a while to figure out. --That's it! Here's an Arduino Reference, if you need it.
//Feel free to use this code however you like, but please credit lordvon and this site! //Code was adapted from that found on (http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1243499684/0). #include <Servo.h>
Servo azimuth; Servo elevation;
// Empirically determined; Voltage between an output high and output low pin. #define Vref 4.46 #define highpulse 2400 #define lowpulse 600 #define quarter (highpulse-lowpulse)/4 #define s1high lowpulse+quarter/2 #define s2high s1high+quarter #define s3high s2high+quarter #define s4high s3high+quarter #define sdivide .7071 #define maxmag 420
//When looking at DS screen with connector bottom left, // the connections are from left to right: //TOP, X1 //LEFT, Y2 //BOTTOM, X2 //RIGHT, Y1
// Digital pin connections (used to drive power) #define X1 2 // TOP to Digital output 5 #define Y2 3 // LEFT to digital output 2 #define X2 4 // BOTTOM to digital output 3 #define Y1 5 // RIGHT to digital output 4
// Analog inputs #define Xin 3 // From X1 #define Yin 4 // From Y1
// set initial touched position int touchX; int touchY; int xpos; int ypos; float cosine; float sine; float mag; int apulse; int epulse;
boolean touched() { boolean touch = false; // Horizontal routine Y1:Y2::Vcc:Gnd pinMode(Y2, OUTPUT); digitalWrite(Y2, LOW); pinMode(Y1, OUTPUT); digitalWrite(Y1, HIGH); // X1,X2 high impedance (input mode) pinMode(X1, INPUT); pinMode(X2, INPUT); // wait a bit, then read from X1 delay(10); touchX = analogRead(Xin); // Vertical routine X1:X2::Vcc:Gnd pinMode(X2, OUTPUT); digitalWrite(X2, LOW); pinMode(X1, OUTPUT); digitalWrite(X1, HIGH); // Y1,Y2 high impedance (input mode) pinMode(Y1, INPUT); pinMode(Y2, INPUT); // wait a bit, then read from Y1 delay(10); touchY = analogRead(Yin);
// Only read touch if coords are below 1000 and above 0 // (stops errors with certain screens) if(touchX < 1023 and touchX > 0 and touchY < 1023 and touchY > 0) { touch = true; }