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/
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 wanted to make a servomotor oscilate between 0-90 degrees when i push a button, but when i push another one, it stops oscillating and then remains in its latest position.
i started with this:
#include <Servo.h>
Servo myservo;
int pos = 0;
const int button1 = 5;
const int button2 = 6;
int lastpos = pos;
void setup() {
myservo.attach(3);
pinMode(button1, INPUT);
pinMode(button2, INPUT);
}
void loop() {
if(digitalRead(button1) == HIGH)
{for(pos = 0; pos <= 90; pos += 1)
{myservo.write(pos);
for(pos = 90; pos >= 0; pos -= 1)
{myservo.write(pos);
delay(36);
} } if(digitalRead(button2) == HIGH){ myservo.write(lastpos);}}}
To start, take a look at how to format code inside a question. It makes it a lot easier to read and help you out. See below for how I formatted for the site, but also readability.
Servo myservo;
int pos = 0;
const int button1 = 5;
const int button2 = 6;
int lastpos = pos;
void setup() {
myservo.attach(3);
pinMode(button1, INPUT);
pinMode(button2, INPUT);
}
void loop() {
if(digitalRead(button1) == HIGH) {
for(pos = 0; pos <= 90; pos += 1) {
myservo.write(pos);
for(pos = 90; pos >= 0; pos -= 1) {
myservo.write(pos);
delay(36);
}
}
if(digitalRead(button2) == HIGH) {
myservo.write(lastpos);
}
}
}
There are several issues with your code based on your description of what you are trying to achieve. First, let's start with the button presses. You are ready the button state, but your code will only detect the button if it is pressed at the exact moment you are doing the digital read. Here's a good resource for reading up on how to properly implement buttons on Arduino: https://www.logiqbit.com/perfect-arduino-button-presses
The second objective is to have the servo sweep back and forth, but stop when you press a button. Your for loops won't let that happen. As currently written, you will always do a sweep to one end and back and then check the next button.
You should update the position of the servo once each time through the loop so you can check on the status of the buttons. In pseudo-code, what I suggest you do is:
void loop() {
//Check button statuses
if(button1), start sweep
if(button2), stop sweep
//Update sweep position
if(ascending && pos < 90) {
//You should be increasing in angle and you haven't reached 90 yet
ascending = TRUE;
pos += 1
myservo.write(pos);
delay(36); //Or whatever delay you need for the servo
} else if(pos > 0) {
//You already reached 90 and are coming back down to 0
ascending = FALSE;
pos -= 1;
delay(36);
}
I am using a PIC24 to read data using 3 analog inputs but am only getting 1 to show the right result. I looked everywhere on the internet and am still not able to get the code to work.
I am trying to read 3 analog input signals and am only able to read in AN0.
I am using an accelerometer to obtain the data and show it on the LCD screen for now. I was able to implement 3 different ways to take the data and display it but only an0 works and an1 is not the right value.
void InitADC(int amask) {
AD1PCFG = 0xFFF8; // select AN0, AN1, AN2 as analog inputs
AD1CON1 = 0x00E0; // auto convert # end of sampling, Integer Data out.
// see Text pg. 179 & Sec. 17 on AD1CON1.
//AD1CON2bits.CSCNA = 1;
AD1CON3 = 0x1F01; // Tad = 2xTcy = 125ns. 31*Tad for conversion time.
//AD1CSSL = 0xFFF7; // Scan 3 channels
AD1CON1bits.ADON = 1; // Turn on the ADC
} // InitADC
main() {
InitADC(0xFFF8); // initialize the ADC and analog inputs
char x_string [12];
char y_string [12];
char z_string [12];
//TRISB = 1; // all PORTB pins as outputs
TRISBbits.TRISB0 = 1;
TRISBbits.TRISB1 = 1;
TRISBbits.TRISB2 = 1;
InitPMP(); // Initialize the Parallel Master Port
InitLCD(); // Initialize the LCD
float x_val;
float y_val;
float z_val;
float x_axis, y_axis, z_axis;
while (1) // main loop
{
x_axis= SelectPort(0);
x_val= ((((x_axis * 3.3)/ 1024)-1.58)/0.380);
sprintf(x_string, "X: %0.2f ", x_val);
ms_delay(2.5);
y_axis= SelectPort(1);
y_val= ((((y_axis * 3.3)/ 1024)-1.58)/0.380);
sprintf(y_string, "Y: %0.2f ", y_val);
ms_delay(2.5);
z_axis= SelectPort(2);
z_val= ((((z_axis * 3.3)/ 1024)-1.58)/0.380);
sprintf(z_string, "Z: %0.2f ", z_val);
ms_delay(2.5);
}
Here is the code where the data is read:
int SelectPort(int ch)
{
//int *result;
AD1CON1bits.ADON = 0; // Turn off the ADC to reconfigure
//result = &ADC1BUF0;
switch(ch) // set values based on the channel to use
{
case 0: // select AN0 as analog input
//AD1CHSbits.CH0SA=0;
//result = ADC1BUF0;
AD1PCFG = 0xFFFE;
break;
case 1:
//AD1CHSbits.CH0SA=1;
//result = ADC1BUF1;
AD1PCFG = 0xFFFD; // select AN1 as analog input
break;
case 2:
//AD1CHSbits.CH0SA=2;
AD1PCFG = 0xFFFB; // select AN2 as analog input
break;
// there's only so many options here, so there's not really a default case
}
AD1CON1bits.ADON = 1; // Turn on the ADC
AD1CHS = ch; // 1. select analog input channel
AD1CON1bits.SAMP = 1; // 2. Start sampling.
while (!AD1CON1bits.DONE); //5. wait for conversion to complete
AD1CON1bits.DONE = 0; // 6. clear flag. We are responsible see text.
return ADC1BUF0; // 7. read the conversion results
}
I am new to PIC24 and need help to figure out why I am not able to get multiple ADC channels to read the data.
You should always give some time for the ADC input voltage to settle after changing its input port. Also, make sure the impedance of your inputs signals are less than 10K.
Separating the ADC channel switching and reading its value will help, and give you an opportunity to add a delay.
I could not find AD1PCFG in the PIC24 datasheet. AD1PCFG is a PIC32 register... PIC24 uses ANSx and TRSx to set pins as analog inputs. Analog inputs should be set once, during the boot sequence. Feeding an analog signal to a digital input CMOS pin will result in increased power draw, and can even lead to hardware failure!
// Set the pins as analog inputs once and for all in your setup code.
void InitADC()
{
// select RB0/AN0, RB1/AN1, RB2/AN2 as analog inputs
TRISB |= 0x07;
ANSB |= 0x07;
// ...
}
void ADC_SelectInput(int ch)
{
AD1CHS = ch & 0x0F
}
int ADC_Read()
{
AD1CON1bits.SAMP = 1;
while (!AD1CON1bits.DONE)
;
AD1CON1bits.DONE = 0;
return ADC1BUF0;
}
Your loop then becomes:
// ...
int adc_in;
while (1)
{
ADC_SelectInput(0);
ms_delay(3); // settling delay, you could also do something
// else in the meantime instead of waiting.
// NOTE: the argument to ms_delay() is an integer
// so waiting at least 2.5 ms makes it 3.
// when computing floats, use float constants, not double.
x_val = (((ADC_Read() * 3.3f) / 1024) - 1.58f) / 0.380f;
sprintf(x_string, "X: %0.2f ", x_val);
ADC_SelectInput(1);
ms_delay(3);
y_val = (((ADC_Read() * 3.3f) / 1024) - 1.58f) / 0.380f;
sprintf(y_string, "Y: %0.2f ", y_val);
ADC_SelectInput(2);
ms_delay(3);
z_val = (((ADC_Read() * 3.3f) / 1024) - 1.58f) / 0.380f;
sprintf(z_string, "Z: %0.2f ", z_val);
}
I'm currently trying to set up a fermentation specific gravity monitor, using a tilt sensor. The process can take several weeks, and must be contained in a sterile container, so must be battery powerered. I'm using a slightly modified ESP8266-01, which enters sleep mode then wakes once an hour to take a measurement, transmit the data, and return to sleep mode. I'm using an MPU6050 for the tilt sensor. Firstly, I can't seem to put the mpu into sleep mode when the esp is off, it always seems to take around 4mA, and secondly, I only need one axis, is it possible to disable everything else to limit power consumption further? I can't seem to find anything in the manual to disable axis, only to calibrate them. my code is below
experimenting with the registers below seem to make no difference, adding them, taking them out altogether, still takes around 4mA. Tried setting to 1 to put the mpu to sleep at the end of the cycle but makes no difference.
Wire.write(0x6B);
Wire.write(0);
I'm very new to this and im struggling to interpret the manual when it refers to bit6 in addr 6b, how do i set bit 6?
If i could restict the mpu to only 1 axis, no acceleration, and to deep sleep inbetween measurements I should be able to get the power consumption around 0.5mA which gives me agood battery life using a single 18650. Any advice would be greatly appreciated!
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include "MPU6050.h"
#include "I2Cdev.h"
#include "Wire.h"
// Update these with values suitable for your network.
const char* ssid = "****";
const char* password = "******";
IPAddress server(192, 168, 1, 90);
WiFiClient espClient5;
PubSubClient client(espClient5);
long lastMsg = 0;
char msg[50];
const uint8_t scl = 5; //D1
const uint8_t sda = 4; //D2
int val;
int prevVal = 0;
String pubString;
char gravity[50];
MPU6050 mpu;
const int sleepTimeS = 10; //only 10 seconds for testing purposes, set to
1hr when operational
int counter=0;
int16_t ax, ay, az;
int16_t gx, gy, gz;
void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
randomSeed(micros());
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void callback(char* topic, byte* payload, unsigned int length) { //not
required in this application
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "test";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str())) {
Serial.println("connected");
// Once connected, publish an announcement...
client.publish("AliveRegister", "FermentMon");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
#define ONE_WIRE_BUS 2 // D4 on physical board
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);
float prevTemp = 0;
void setup() {
counter = 0;
Serial.begin(9600);
Wire.begin(0,2);
Wire.write(0x6B); //PWR_MGMT_1 register
Wire.write(0); // set to zero wakes teh 6050
Wire.endTransmission(true);
delay(100);
setup_wifi();
client.setServer(server, 1883);
client.setCallback(callback);
if (!client.connected()) {
reconnect();
}
Serial.println("Initialize MPU");
mpu.initialize();
Serial.println(mpu.testConnection() ? "Connected" : "Connection failed");
float temp;
DS18B20.requestTemperatures();
temp = DS18B20.getTempCByIndex(0); // first temperature sensor
char buff[100];
dtostrf(temp, 0, 2, buff);
temp = temp + 0.5;
int tRound = int(temp);
client.publish("Fermenter/temperature", buff);
Serial.print("Fermenter Temperature: ");
Serial.println(temp);
prevTemp = tRound;
mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
val = map(ax, -17000, 17000, 0, 180);
pubString = String(val);
pubString.toCharArray(gravity, pubString.length() + 1);
client.publish("Fermenter/angle", gravity);
Serial.print("Gravity angle: ");
Serial.println(val);
delay(500);
// counter = counter+1;
Serial.println("sleep mode");
Wire.write(0x6B); //PWR_MGMT_1 register
Wire.write(1); // set to zero wakes teh 6050
// sleep
ESP.deepSleep(sleepTimeS * 1000000);
delay(2000);
}
void loop() {
client.loop();
}
I'm very new to this and im struggling to interpret the manual when it refers to bit6 in addr 6b, how do i set bit 6?
Setting a bit is simple.
Use the follow functions to avoid any brain storming.
// Write register bit
void writeRegisterBit(uint8_t reg, uint8_t pos, bool state)
{
uint8_t value;
value = readRegister8(reg);
if (state)
{
value |= (1 << pos);
}
else
{
value &= ~(1 << pos);
}
writeRegister8(reg, value);
}
// Write 8-bit to register
void writeRegister8(uint8_t reg, uint8_t value)
{
Wire.beginTransmission(MPU_addr);
#if ARDUINO >= 100
Wire.write(reg);
Wire.write(value);
#else
Wire.send(reg);
Wire.send(value);
#endif
Wire.endTransmission();
}
Example Usage: writeRegisterBit(MPU6050_REG_INT_PIN_CFG, 5, 1); //Register 37;Interrupt Latch Enable
For your application:
void acclSetSleepEnabled(bool state)
{
writeRegisterBit(MPU6050_REG_PWR_MGMT_1, 6, state);
}
If i could restict the mpu to only 1 axis, no acceleration, and to deep sleep inbetween measurements I should be able to get the power consumption around 0.5mA which gives me agood battery life using a single 18650
To enter low power accelerometer mode use the following function:
void lowPowerAccel(uint8_t frequency) {
uint8_t value;
value = readRegister8(MPU6050_REG_PWR_MGMT_2);
value &= 0b00111000;
value |= (frequency << 6) | 0b111;
writeRegister8(MPU6050_REG_PWR_MGMT_2, value);
value = readRegister8(MPU6050_REG_PWR_MGMT_1);
value &= 0b10010111;
value |= 0b00111000;
writeRegister8(MPU6050_REG_PWR_MGMT_1, value);
}
This lowPowerAccel function also puts the gyro to standy mode. The function needs a wake up frequency parameter.
This is defined as follows:
/*
* LP_WAKE_CTRL | Wake-up Frequency
* -------------+------------------
* 0 | 1.25 Hz
* 1 | 2.5 Hz
* 2 | 5 Hz
* 3 | 10 H
*/
#define LP_WAKE_CTRL_1_25 0x00
#define LP_WAKE_CTRL_2_5 0x01
#define LP_WAKE_CTRL_5 0x02
#define LP_WAKE_CTRL_10 0x03
I hope, I could answer some of your questions.
Good luck! :)
Are you using a breakout board for the MPU6050? e.g. GY-521. Often they use linear regulators and leds which will consume additional power. It may be necessary to remove these and run the IMU from a direct power source.
Each register in the MPU6050 is 8 bits wide. When setting an individual bit to a desired value you can either use bitwise manipulation (not practical here as we aren't directly interacting with the registers) or directly set all of the bits in the register to the register's new state e.g. 0b00100000 ~ 0x20. Instead of writing a 1 to 0x6B when attempting to put the MPU6050 to sleep you should be writing 0x20.
https://www.invensense.com/wp-content/uploads/2015/02/MPU-6000-Register-Map1.pdf
Referencing page 40-42, if you want to take things a step further you can disable the temperature sensor, accelerometers, and redundant gyroscope axes to save power while the device is active.
So I made this kind of a temperature/humidity sensor and decided to add a fire sensor feature. So it all works fine, right? No, I also decided I want a buzzer to that. Tested it, works well, so I thrown it into my project.
Started it up [project], lit up a lighter, works fine, LEDs blink, a text is shown, buzzer plays an alarm. But then, after the fire was out, the buzzer continued to play one of two tones, even though there was no fire. Here's the code, to make it all clear:
#include <LiquidCrystal.h>
#include <dht.h>
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
dht DHT;
#define FLAME 13
#define DHT11_PIN 8
#define ALARM A5
const int a9 = 9, a10 = 10, a11 = 11, a12 = 12;
byte z[8] = {
B00100,
B00000,
B11111,
B00001,
B00010,
B00100,
B11111,
B00000,
};
byte st[8] = {
0b00110,
0b01001,
0b01001,
0b00110,
0b00000,
0b00000,
0b00000,
0b00000,
};
void setup(){
lcd.begin(16, 2);
lcd.createChar(0, st);
lcd.createChar(1, z);
Serial.begin(9600);
pinMode((a9, a10, a11, a12), OUTPUT);
pinMode(FLAME, INPUT);
pinMode(ALARM, OUTPUT);
}
void loop() {
// Flame sensor code for Robojax.com
int fire = digitalRead(FLAME);// read FLAME sensor
if(fire == HIGH)
{
analogWrite(a9, 255);
analogWrite(a10, 255);
lcd.setCursor(5, 0);
lcd.print("Po");
lcd.print(char(1));
lcd.print("ar!");
tone(ALARM, 4300);
delay(150);
analogWrite(a9, 0);
analogWrite(a10, 0);
lcd.clear();
tone(ALARM, 3500);
delay(150);
} else {
lcd.createChar(0, st);
int chk = DHT.read11(DHT11_PIN);
lcd.home();
lcd.print("Temp.: ");
lcd.print(DHT.temperature);
if(DHT.temperature >= 20.00 && DHT.temperature < 25) {
analogWrite(a11, 255);
delay(750);
analogWrite(a11, 0);
delay(750);
} else if(DHT.temperature >= 25 && DHT.temperature < 30) {
analogWrite(a10, 255);
delay(250);
analogWrite(a10, 0);
delay(250);
} else if(DHT.temperature >= 30) {
analogWrite(a9, 255);
}
lcd.print(char(0));
lcd.print("C");
lcd.setCursor(0, 1);
lcd.print("Wilg.: ");
lcd.print(DHT.humidity);
if(DHT.humidity >= 45.00 && DHT.humidity < 60.00) {
digitalWrite(a12, HIGH);
delay(250);
digitalWrite(a12, LOW);
delay(250);
} else if(DHT.humidity >= 60.00) {
digitalWrite(a12, HIGH);
}
lcd.print(" %");
delay(750);
}
delay(200);
}
So, what I mean is that even though fire is changed from HIGH to LOW and other part of the code is executed, the buzzer continues to play.
What am I doing wrong?
Check the documentation for tone:
A duration can be specified, otherwise the wave continues until a call
to noTone().
So, you probably need to reset your tone on every loop beginning before checking the values of the sensors (or explicitly invoke notone on the LOW branch), or use the 3-arg version of tone.
I have no idea how tone and delay might interact, though.
I'd probably make the actual tone sounding routine its own task. The idea is that you would start the alarm task and then reset it when appropriate. But for now make sure your state is reset at the beginning of every loop, or each branch resets anything it has to explicitly, if tasks sound too advanced.
Make sure you learn the basic "print" debugging in the Arduino world. Simple write logging to the serial port where it can be read on the IDE is invaluable.
Finally: use functions! If you put everything in loop your programs will get unreadable as they grow. For example, if you have some state you want to reset every time (e.g., running tasks like tones, values, flags) then create an init() function that loop calls first so any given loop has good starting state.
Limitations of the Piezo Buzzer
Here are some things to consider when using the piezo buzzer:
You can’t use tone() while also using analogWrite() on pins 3 or 11