I have a solution for an arduino uno R3 and rotary encoder that will count each time you rotate the encoder clockwise and decrement when rotated counterclockwise. All other solutions to this problem were very convoluted and unsatisfactory so i solved it myself. Below you can see the code listing, you should be able to copy and paste into a new sketch file and upload without any problems.
Thanks,
Cameron Belt
//rotary encoder
int pin1 = 2;//a
int pin2 = 3;//b
int reset = 11;
int previousA;
int previousB;
int counter = 20;
void setup()
{
Serial.begin(9600);
pinMode(pin1,INPUT);
pinMode(pin2,INPUT);
pinMode(reset,INPUT);
digitalWrite(pin1,HIGH);
digitalWrite(pin2,HIGH);
attachInterrupt(0,encoderRead,CHANGE);
attachInterrupt(1,encoderRead,CHANGE);
}
void loop()
{
if(digitalRead(reset) == LOW)
counter = 20;
}
void encoderRead()
{
int a = digitalRead(pin1);
int b = digitalRead(pin2);
//Serial.print(digitalRead(pin1));
//Serial.print(digitalRead(pin2));
//Serial.println();
if(previousA == HIGH && previousB == HIGH)
{
if(a == LOW && b == HIGH)
{
counter += 1;
Serial.println(counter);
}
else if(a == HIGH && b == LOW)
{
counter -= 1;
Serial.println(counter);
}
}
previousA = digitalRead(pin1);
previousB = digitalRead(pin2);
}
Connect the rotary encoders outside pins (when looking at the side with three pins) to inputs 2 and 3 on the arduino and if you have a push button on your encoder connect one pin of the switch to pin 11 on the arduino with a pull up resistor (10k should be sufficient) from that pin to Vdd and the other pin of the encoder switch to ground. Connect the middle pin of the encoder on the side with three pins to ground.
Once uploaded to the arduino open the serial monitor and turn the rotary encoder.
Related
I am working on an artistic project that includes an ADXL345 sensor (accelerometer), Arduino Uno R3 Board, Arduino IDE 2.0.3 and Processing 4.1.2.
I want Processing to display images randomly and continuously every time the values of the sensor that are received from the serial communication with the Arduino sketch, go x>5, x<-5, y.5, y.-5, z>1, z<-1.
UPDATE:
A friend helped me with some lines of code and now the image being displayed when I move the sensor.
CHALLENGE:
What I want to be able to do now is run the processing sketch ONCE and let the windows containing the images pop up, close down, open new windows and display new random images from my folder. For this process to repeat on itself so I don't have to run the sketch manually every time.
These are the codes that I am using in Arudino and Processing.
ARDUINO
void setup() {
// initialize serial communication at 9600 baud rate
Serial.begin(9600);
}
void loop() {
// send x, y, and z values over serial
int x = analogRead(A0);
int y = analogRead(A1);
int z = digitalRead(2);
Serial.print(x);
Serial.print(",");
Serial.print(y);
Serial.print(",");
Serial.println(z);
delay(1000);
}
& PROCESSING
import processing.serial.*;
Serial mySerial;
PImage fragment;
int rand;
void setup() {
size(1000, 500);
rand = int(random(0,133));
takerandomimage("C:/Users/user/Documents/Processing/Trial_300123/frag_" + nf(rand, 3) + ".jpg");
String portName = Serial.list()[0];
mySerial = new Serial(this, portName, 9600);
println("Serial port connected: " + portName);
loop();
}
void takerandomimage(String fn) {
fragment = loadImage(fn);
println(fragment);
}
void draw() {
background(255); //clears the screen
if (fragment.width>0 && fragment.height > 0){ //check if image has been loaded
String data = mySerial.readStringUntil('\n');
if (data != null && data != "\n" && data != " " && data != "\r" && data != "\t") {
println("Data received: " + data);
String[] values = data.split(" ",0);
int counter = 0;
int x = 0;
int y = 0;
int z = 0;
for(String w :values){
System.out.println(w);
if (counter == 1)
x = int(w);
if ( counter == 4)
y = int(w);
if ( counter == 7)
z = int(w);
counter++;
}
println(x);
println(y);
println(z);
if (x < 0 || y > 0 || z > 0) {
takerandomimage("C:/Users/user/Documents/Processing/Trial_300123/frag_" + nf(rand, 3) + ".jpg");
image(fragment, 0,0);
delay(1000);
}
}
}
}
Thank you!!
So many things are right with your code (and question)(+1):
your question mentions version of the Arduino/Processing used, Arduino board, sensor and also includes minimal code focused on the issue
checking if data is not null
checking if the split array is right length, etc.
You are so close !
There is one issue throwing off parsing:
your Processing code assumes you have the x, y, z values one line: String data = mySerial.readStringUntil('\n');
your Arduino code is printling mulitple lines instead of one(e.g. Serial.println(x); instead of Serial.print(x))
to double check, you would see x, y, z values (as well as the two "," symbols) in Serial Monitor on separate lines each (instead of all on one line)
I suspect the intention was to use println() only on the last line:
void setup() {
// initialize serial communication at 9600 baud rate
Serial.begin(9600);
}
void loop() {
// send x, y, and z values over serial
int x = analogRead(A0);
int y = analogRead(A1);
int z = digitalRead(2);
Serial.print(x);
Serial.print(",");
Serial.print(y);
Serial.print(",");
Serial.println(z);
delay(1000);
}
(The above should print 3 values separated by "," on a single line. Double check if z should be a digitalRead(2) (returning 1 or 0) reading on pin 2 on your Arduino or analogRead(A2) (returning 0 to 1023) reading analog pin A2.)
Update
Another idea is move the accelerometer conditions in the Arduino code and simply output a single byte/character ('i' for example) when you want to trigger loading a random image in Processing.
Here's a rough / untested example:
void setup() {
// initialize serial communication at 9600 baud rate
Serial.begin(9600);
}
void loop() {
// send x, y, and z values over serial
int x = analogRead(A0);
int y = analogRead(A1);
int z = digitalRead(2);
// if the right motion is picked up, send 'i' to Processing to load a random image
if (x > 5 || y > 5 || z > 0) {
Serial.print('i');
}
delay(1000);
}
Note that with the 1000 ms (1s) delay means you can't trigger an image change faster than that. Adjust the delay as needed.
Additionally you say you want to trigger the change when accelerometer values meet these conditions:
x>5, x<-5, y.5, y.-5, z>1, z<-1.
If so, you might want to change:
if (x > 5 || y > 5 || z > 0)
to
if (abs(x) > 5 || abs(y) > 5 || abs(z) > 0)
(where abs() returns the absolute value (e.g. 5 remains 5, but -5 becomes 5))
Hopefully the values you selected make sense for the motion you're trying to capture with the accelerometer (otherwise the Serial Plot tool in Arduino can be helpful).
If you move the condition to Arduino it simplifies the Processing code as you don't need to wait for a full string to parse into an array: you can read just one character.
import processing.serial.*;
Serial mySerial;
PImage fragment;
void setup() {
size(1000, 500);
loadRandomImage();
String portName = Serial.list()[0];
mySerial = new Serial(this, portName, 9600);
}
void loadRandomImage() {
int rand = int(random(0,133));
String filename = "frag_" + nf(rand, 3) + ".jpg"
fragment = loadImage(fn);
}
void draw() {
// if there is a serial data
if(mySerial.available > 0){
// read one byte/char (mask (&) because byte range is -127 to 127 in java, but 0 to 255 in c++)
char data = mySerial.read() & 255;
// optional: print serial to debug
println("received from Arduino", data);
// if the expect char (i) was received, load random image
if(data == 'i'){
loadRandomImage();
}
}
background(255); //clears the screen
if (fragment.width>0){ //check if image has been loaded
image(fragment, 0, 0);
}
}
Notice a few other minor changes:
I've renamed takerandomimage to loadRandomImage() and changed it so each time the function gets called it generates the random number and loads the random image
whenever the 'i' character is received from Ardiuno a new random is loaded
whatever random image has been set gets displayed continuously (decoupling image display from reading serial data). Before you only loaded and displayed an image if the right serial data came through).
I am attempting to connect the Arducam HM01B0 sensor to the nRF52840-DK embedded board using bare metal programming. The sensor has pins for a four-bit serial interface, and to use it, the user has to solder the pins. However, I am trying to make the HM01B0 work with the one-bit interface and capture an image.
I am able to read and write to the sensor registers over I2C. The datasheet presents the following timings characteristics to capture an image over a serial line.
I have connected the logic analyzer and I am able to see the corresponding waveform that is the data is being streamed over D0 line.
For 1 bit interface,the image sensor has a frame rate of 30 FPS and the frequency of PCLK is 36 Mhz. I know that GPIO pins would not be able to read the input signals in this
frequency range but I don't know how else to read a serial line. One option is making the image sensor as SPIM master and nrf52840 as SPIM slave. The image sensor provides the clock over PCLK which can be configured as SPI clock and the line D0 can be configured as MOSI line. However to read valid data bits/bytes over the serial line, VSYNC and HSYNC should also be read and made sure that their value is according to the serial video interface timings diagram. So I tried to read the serial line D0 by configuring it as a GPIO pin and I read 0x00 always.
How can I configure the image sensor and capture an image?
This is the code I have written,
// array to hold a complete frame
uint8_t frameBuffer[324][324];
#define PIN_VSYNC (28)
#define PIN_HSYNC (29)
#define PIN_PCLK (30)
#define PIN_D0 (31)
// initialise the pins of sensor
void hm0360_init()
{
// GPIO I/P
nrf_gpio_cfg_input(PIN_VSYNC, NRF_GPIO_PIN_PULLUP);
nrf_gpio_cfg_input(PIN_HSYNC, NRF_GPIO_PIN_PULLUP);
nrf_gpio_cfg_input(PIN_PCLK, NRF_GPIO_PIN_PULLUP);
// GPIO O/P
nrf_gpio_cfg_input(PIN_D0,NRF_GPIO_PIN_PULLUP);
for(int i = 0; i < 324 ; i++){
for(int j = 0; j < 324 ; j++){
frameBuffer[i][j] = 0;
}
}
}
void hm01b0_read_frame_bits()
{
int VSYNC_count = -1, HREF_count = 0;
int incomingBits;
unsigned char byte = 0;
int byteArrayIndex = 0;
int bitCount = 0;
while(nrf_gpio_pin_read(PIN_VSYNC) == LOW) { }
while(nrf_gpio_pin_read(PIN_VSYNC) == HIGH)
{
while(nrf_gpio_pin_read(PIN_HSYNC) == false && nrf_gpio_pin_read(PIN_VSYNC) == HIGH) { }
VSYNC_count++;
HREF_count = 0;
//Read a row
while(nrf_gpio_pin_read(PIN_HSYNC) == true)
{
while(nrf_gpio_pin_read(PIN_PCLK) == false) { }
// read 0 always
incomingBits = nrf_gpio_pin_read(PIN_D0);
byte = (byte << 1) | incomingBits;
bitCount++;
if (bitCount == 8) {
frameBuffer[VSYNC_count][HREF_count++] = byte;
bitCount = 0;
byte = 0;
}
if (VSYNC_count == 324) {
break;
}
while(nrf_gpio_pin_read(PIN_PCLK) == true) { }
}
}
}
I’m trying to send an sms with the location when the ultrasonic sensor measures a certain distance but when I add the gpsSerial(9600) line in the void setup, the ultrasonic sensor readings become inconsistent such as it reads 24 cm then skips to 18 cm then back to 24 cm. i would really appreciate it if anyone familiar with arduino or has faced this problem before would help me out. here is my code:
#include <TinyGPS.h>
#include <SoftwareSerial.h>
#include "NewPing.h"
#define TRIGGER_PIN 7
#define ECHO_PIN 8
#define MAX_DISTANCE 100
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);
float duration, distance;
SoftwareSerial gsmSerial(2, 3);
SoftwareSerial gpsSerial(5, 4);
TinyGPS gps; //Creates a new instance of the TinyGPS object
bool newData = false;
void setup()
{
Serial.begin(9600);
gsmSerial.begin(9600);
gpsSerial.begin(9600);
}
void loop()
{
// Send ping, get distance in cm
distance = sonar.ping_cm();
if (distance < 4 )
{
//sendSMS();
Serial.println("Bin is full!!, SMS SENT!!");
Serial.println(distance);
delay(1200);
}
else
{
Serial.println(distance);
delay(2000);
}
delay(2000);
}
void sendSMS(){
// For one second we parse GPS data and report some key values
for (unsigned long start = millis(); millis() - start < 1000;)
{
while (gpsSerial.available())
{
char c = gpsSerial.read();
//Serial.print(c);
if (gps.encode(c))
newData = true;
}
}
if (newData) //If newData is true
{
float flat, flon;
unsigned long age;
gps.f_get_position(&flat, &flon, &age);
gsmSerial.print("AT+CMGF=1\r");
delay(400);
gsmSerial.println("AT + CMGS = \"+26xxxxxxxx\"");// recipient's mobile
number
delay(300);
gsmSerial.print("BIN IS FULL!, PLEASE COLLECT # https://www.google.com
/maps/?q=");
gsmSerial.print(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat, 6);
gsmSerial.print(",");
gsmSerial.print(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6);
delay(200);
gsmSerial.println((char)26); // End AT command with a ^Z, ASCII code
26
delay(2000);
gsmSerial.println();
}
}
I've tried to reproduce your problem on Arduino Uno with HC SR04, but with no success – my measurements were stable (more than 100 same measurements in a row). I have even set the sensor to 24 cm distance from the measured obstacle. I used a code derived from what you have provided:
#include <SoftwareSerial.h>
#include "NewPing.h"
#define TRIGGER_PIN 7
#define ECHO_PIN 8
#define MAX_DISTANCE 100
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);
float duration, distance;
SoftwareSerial gsmSerial(2, 3);
SoftwareSerial gpsSerial(5, 4);
void setup() {
Serial.begin(9600);
gsmSerial.begin(9600);
gpsSerial.begin(9600);
}
void loop() {
// Send ping, get distance in cm
distance = sonar.ping_cm();
if (distance < 4 ) {
Serial.println("Bin is full!!, SMS SENT!!");
Serial.println(distance);
}
else {
Serial.println(distance);
}
delay(2000);
}
My conclusion is your code is fine and the problem is HW related. Check the wiring and if possible, try to use another HC-SR04 sensor.
BTW1: During testing, I was sending data to gpsSerial (rx) just to be sure, it is not caused by the GPS module sending some periodic data.
BTW2: How do you power the GPS and GSM module? Are you using Arduino to power these? If yes, this also can be the source of your problems since these modules could drain large peak currents and Arduino as source is not powerful enough ...
I need to be able to send an integer from cocoa to an arduino.
It is easy to send characters, i.e. single digit integers, but I can't seem to find a way of sending two and three digit integers.
The purpose of this is to control the brightness of an LED continuously from 0 to 255.
So far, I can either turn it on and off using the following code:
int ledPin = 9; // LED connected to digital pin 9
int incomingByte = 0; // for incoming serial data
void setup() {
// initialize the digital pin as an output:
pinMode(ledPin, OUTPUT);
Serial.begin(9600);
}
void loop()
{
if (Serial.available() > 0) {
// read the incoming byte:
incomingByte = Serial.read();
if(incomingByte == 105){ //105 corresponds to i and is programmed in cocoa to turn the LED on
digitalWrite(ledPin, HIGH);
}
else if(incomingByte == 111){ //111 corresponds to o and is programmed in cocoa to turn the LED on
digitalWrite(ledPin, LOW);
}
}
}
However, I can't work out how to set values between 0 and 255. Instead of 'digitalWrite', I would use 'AnalogWrite', however, I don't know how to send the incomingByte to be a value between 0 and 255.
This is the cocoa code:
#import "MainController.h"
#implementation MainController
-(IBAction)ledOn:(id)sender{
popen("echo i > /dev/cu.usbmodem1411", "r");
}
-(IBAction)ledOff:(id)sender{
popen("echo o > /dev/cu.usbmodem1411", "r");
}
#end
Thanks.
You can treat the integers with more than one digits as cstring in your arduino code then convert them to integer via atoi().
The following code will capture the bytes from the serial buffer as cstring:
char buffer[MAX_BUFFER_SIZE]; // global c character array variable
boolean inputReady()
{
byte index = 0;
byte avail = Serial.available();
if(avail > 0)
{
while(index < avail)
{
byte val;
do
{
val = Serial.read();
}
while (val == -1); // if value is no longer -1, bytes are captured
buffer[index] = val;
index++;
}
buffer[index] = 0; //terminate the character array
return true;
}
return false;
}
Note: I prefer cstrings than the String class built in the arduino IDE since it uses more memory, but be careful using cstrings as they are prone to memory leaks if not managed well.
This is how your loop() block should look like:
void loop()
{
if(inputReady())
{
int pwmValue = atoi(buffer); // convert ascii buffer to integer.
if(pwmValue >= 0 && pwmValue <= 255) // filter values from 0-255
analogWrite(ledPin, pwmValue);
else
digitalWrite(ledPin, LOW); // turn off if pwmValue is more than 255
}
delay(100);
}
You can then send pwm values as string from your cocoa code via popen().
#import "MainController.h"
#implementation MainController
-(IBAction)ledPWMValue:(id)sender{
popen("echo 254 > /dev/cu.usbmodem1411", "r");
}
#end
I've tested this on my Arduino Uno and will probably work on other variants. I hope this helps you in your project and best of luck!
I am stuck on my project at the final part which is controlling a servo by reading xml feed and depending on the values it should turn several degrees. I am using a weather xml feed by yahoo which shows different wind speed attributes as speed, direction and etc. What i am doing is Im using only wind direction and speed in order to visualize it with LED's and and arrow for the direction. Everything works fine with the LED's , but when it comes to the servo I'm not quite sure what to do. It works alright with the Arduino sweeping example, but I use Firmata and i guess the code for it is a bit different. First I used standard Firmata to control the LED's but it wasn't good with the servo, so now Im using 2 arduino's one with Standard Firmata for the LEDs and one with Servo Firmata for the servo, noth assigned on different COM ports. Unfortunately when I try to program the servo it only gets faster or slower without being able to control the angle of it and when to stop. In arduino it works with their example, but in Firmata it seems that I can't adapt it so it does similar in Processing with Firmata. I've been stuck on this for 2 days already pls any help would be appreciated since I have to finish it by Monday
here is the code :
import processing.serial.*;
import cc.arduino.*;
Arduino arduino, arduino2;
final String URL = "http://weather.yahooapis.com/forecastrss?w=27764362";
final String WORD = "yweather:wind";
final String TOKEN = "\\W+";
int ledPin = 13;
int ledPin1 = 12;
int ledPin2 = 8;
int pos=0;
void setup() {
arduino = new Arduino(this, Arduino.list()[0], 57600);
arduino2 = new Arduino(this, Arduino.list()[1], 57600);
arduino.pinMode(ledPin, Arduino.OUTPUT);
arduino.pinMode(ledPin1, Arduino.OUTPUT);
arduino.pinMode(ledPin2, Arduino.OUTPUT);
arduino2.pinMode (9, Arduino.OUTPUT);
final String[] xml = loadStrings(URL);
int idx = 0;
for (; idx != xml.length; ++idx)
if ( xml[idx].contains(WORD) ) break;
if (idx == xml.length) {
println("Not found");
exit();
}
println("Index: " + idx);
println(xml[idx]);
final int[] info = int( xml[idx].split(TOKEN) );
final int dir = info[6];
final int spd = info[8];
println("Speed: " + spd);
println("Direction: " + dir);
if (spd < 5 ) {
arduino.digitalWrite(ledPin, Arduino.LOW);
arduino.digitalWrite(ledPin1, Arduino.LOW);
arduino.digitalWrite(ledPin2, Arduino.LOW);
}
if (spd >= 5 && spd <10) {
arduino.digitalWrite(ledPin, Arduino.HIGH);
arduino.digitalWrite(ledPin1, Arduino.LOW);
arduino.digitalWrite(ledPin2, Arduino.LOW);
}
if (spd >= 10 && spd <= 15) {
arduino.digitalWrite(ledPin, Arduino.HIGH);
arduino.digitalWrite(ledPin1, Arduino.HIGH);
arduino.digitalWrite(ledPin2, Arduino.LOW);
}
if (spd > 16) {
arduino.digitalWrite(ledPin, Arduino.HIGH);
arduino.digitalWrite(ledPin1, Arduino.HIGH);
arduino.digitalWrite(ledPin2, Arduino.HIGH);
}
println("3");
if (dir >= 10 && dir <= 25) {
println("4");
arduino2.analogWrite(9, 90);
delay(1500);
}
else if (dir > 340 && dir <= 360) {
println("Low speed");
arduino2.analogWrite(9, 80); //in this case 80 is controlling the speed, although I wanted to control the angle
delay(1500);
arduino2.analogWrite(9, 120); // same here
delay(1500);
println("5");
}
}
All those prinLn(1-5) are obviously just code checkers to see if there is something wrong with it, but i guess there isnt, its just that i cant control the angle or any other particular control over it other than it's speed, but it doesn't stop spinning till I unplug the usb most cases :)
I guess i need to insert somewher this part of the arduino example to make it move properly :
void loop()
{
for(pos = 0; pos < 180; pos += 1) // goes from 0 degrees to 180 degrees
{ // in steps of 1 degree
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
But not quite sure since i tried, but I might not have programmed it properly .
Thanks!
setup() is only called once at initialization of the sketch. loop() is repeatedly called during the runtime. therefore, most of your code needs to be in the loop.
i do recommend starting off with some simple sketches to get things running step by step.
ladyada has some good tutorials up, i.e. for serial communication at http://www.ladyada.net/learn/arduino/lesson4.html
the firmata repository holds some good examples at https://github.com/firmata/arduino/tree/master/examples
in addition, the arduino forum reveals some discussion on searching for "firmata" at http://forum.arduino.cc/