Micro-controller : SainSmart Mega 2560
Motor Shield: Osepp Motor Shield V1.0
I am trying to implement Radio Frequency communication on my wheeled robot however when the motors are running the radio frequency code will not receive messages.
The motor shield uses pins 4,7,8,12
I have setup the radio frequency to occur on pins 22,23 ,5
I see this reference to
Why does VirtualWire conflicts with PWM signal in Arduino/ATmega328 pin D10?
but am not sure if this applies to my situation.
How do I get Radio Frequency receiver/transmitter to work while motor shield in use?
code demonstrating the situation:
#include <RH_ASK.h>
#include <SPI.h> // Not actually used but needed to compile
RH_ASK driver(2000, 22, 23, 5,true); // ESP8266: do not use pin 11
/// *************************
// MOTOR SETUP
/// *************************
// Arduino pins for the shift register
#define MOTORLATCH 12
#define MOTORCLK 4
#define MOTORENABLE 7
#define MOTORDATA 8
// 8-bit bus after the 74HC595 shift register
// (not Arduino pins)
// These are used to set the direction of the bridge driver.
#define MOTOR1_A 2
#define MOTOR1_B 3
#define MOTOR2_A 1
#define MOTOR2_B 4
#define MOTOR3_A 5
#define MOTOR3_B 7
#define MOTOR4_A 0
#define MOTOR4_B 6
// Arduino pins for the PWM signals.
#define MOTOR1_PWM 11
#define MOTOR2_PWM 3
#define MOTOR3_PWM 6
#define MOTOR4_PWM 5
#define SERVO1_PWM 10
#define SERVO2_PWM 9
// Codes for the motor function.
#define FORWARD 1
#define BACKWARD 2
#define BRAKE 3
#define RELEASE 4
void setup()
{
Serial.begin(9600); // Debugging only
if (!driver.init())
Serial.println("init failed");
//comment out code below to allow receiver to read radio frequency communication
//BEGIN
motor(1, FORWARD, 255);
motor(2, FORWARD, 255);
motor(4, FORWARD, 255);
motor(3, FORWARD, 255);
//END
}
void loop()
{
uint8_t buf[RH_ASK_MAX_MESSAGE_LEN];
uint8_t buflen = sizeof(buf);
if (driver.recv(buf, &buflen)) // Non-blocking
{
int i=0;
// Message with a good checksum received, dump it.
driver.printBuffer("Got:", buf, buflen);
buf[5]= '\0';
Serial.println((char*)buf);
}
}
void motor(int nMotor, int command, int speed)
{
int motorA, motorB;
if (nMotor >= 1 && nMotor <= 4)
{
switch (nMotor)
{
case 1:
motorA = MOTOR1_A;
motorB = MOTOR1_B;
break;
case 2:
motorA = MOTOR2_A;
motorB = MOTOR2_B;
break;
case 3:
motorA = MOTOR3_A;
motorB = MOTOR3_B;
break;
case 4:
motorA = MOTOR4_A;
motorB = MOTOR4_B;
break;
default:
break;
}
switch (command)
{
case FORWARD:
motor_output (motorA, HIGH, speed);
motor_output (motorB, LOW, -1); // -1: no PWM set
break;
case BACKWARD:
motor_output (motorA, LOW, speed);
motor_output (motorB, HIGH, -1); // -1: no PWM set
break;;
case RELEASE:
motor_output (motorA, LOW, 0); // 0: output floating.
motor_output (motorB, LOW, -1); // -1: no PWM set
break;
default:
break;
}
}
}
void motor_output (int output, int high_low, int speed)
{
int motorPWM;
switch (output)
{
case MOTOR1_A:
case MOTOR1_B:
motorPWM = MOTOR1_PWM;
break;
case MOTOR2_A:
case MOTOR2_B:
motorPWM = MOTOR2_PWM;
break;
case MOTOR3_A:
case MOTOR3_B:
motorPWM = MOTOR3_PWM;
break;
case MOTOR4_A:
case MOTOR4_B:
motorPWM = MOTOR4_PWM;
break;
default:
speed = -3333;
break;
}
if (speed != -3333)
{
shiftWrite(output, high_low);
if (speed >= 0 && speed <= 255)
{
analogWrite(motorPWM, speed);
}
}
}
void shiftWrite(int output, int high_low)
{
static int latch_copy;
static int shift_register_initialized = false;
if (!shift_register_initialized)
{
// Set pins for shift register to output
pinMode(MOTORLATCH, OUTPUT);
pinMode(MOTORENABLE, OUTPUT);
pinMode(MOTORDATA, OUTPUT);
pinMode(MOTORCLK, OUTPUT);
// Set pins for shift register to default value (low);
digitalWrite(MOTORDATA, LOW);
digitalWrite(MOTORLATCH, LOW);
digitalWrite(MOTORCLK, LOW);
// Enable the shift register, set Enable pin Low.
digitalWrite(MOTORENABLE, LOW);
// start with all outputs (of the shift register) low
latch_copy = 0;
shift_register_initialized = true;
}
bitWrite(latch_copy, output, high_low);
shiftOut(MOTORDATA, MOTORCLK, MSBFIRST, latch_copy);
delayMicroseconds(5); // For safety, not really needed.
digitalWrite(MOTORLATCH, HIGH);
delayMicroseconds(5); // For safety, not really needed.
digitalWrite(MOTORLATCH, LOW);
}
It looks like the reference you give could be the problem. To try that fix just find the RH_ASK.cpp file and uncomment line 16 like this
// RH_ASK on Arduino uses Timer 1 to generate interrupts 8 times per bit interval
// Define RH_ASK_ARDUINO_USE_TIMER2 if you want to use Timer 2 instead of Timer 1 on Arduino
// You may need this to work around other libraries that insist on using timer 1
#define RH_ASK_ARDUINO_USE_TIMER2
Your motor is using pin 5:
#define MOTOR4_PWM 5
Try using a different third pin for your radio (make sure to match your software and hardware to the same new pin). Glancing at the specsheet, one option would be pin 24. Your motor code reserves every pin from 0 through 12. So, try...
RH_ASK driver(2000, 22, 23, 24,true); // ESP8266: do not use pin 11
Or change your motor pins using similar logic.
Related
I'm currently working on a project with some friends about lidar measuraments based on ARDUINO and GARMIN Lidar v3HP and we are getting some reading that are questionable from the sensors. They seem to work but the measurements are not correct.
We have issues with the data and also with the address, we setup the sensors with two different addresses 0x42 and 0x43, but one of the sensors keeps on the default address.
#include <Arduino.h>
#include <Wire.h>
#include <stdint.h>
#include <LIDARLite_v3HP.h>
#include <I2CFunctions.h>
#define POWER_ENABLE_S1 12
#define POWER_ENABLE_S2 11
#define DEFAULT_ADDRESS 98
#define FAST_I2C
#define NUMERO_LIDARS 2
LIDARLite_v3HP Sensor1;
LIDARLite_v3HP Sensor2;
int detectedAddreses[NUMERO_LIDARS];
int currentAdd;
int deviceCount = 0;
int i = 0;
void scanI2C()
{
int nDevices = 0;
while (i < NUMERO_LIDARS)
{
for (byte addr = 1; addr < 127; ++addr)
{
Wire.beginTransmission(addr);
byte error = Wire.endTransmission();
if (error == 0)
{
Serial.print("Se encontro un dispositivo en ");
Serial.print(addr);
Serial.println(" !");
++nDevices;
detectedAddreses[i] = addr;
if (addr == DEFAULT_ADDRESS)
{
configSensors(i, 66 + deviceCount, addr);
detectedAddreses[i] = addr;
i++;
}else{
detectedAddreses[i] = addr;
i++;
}
}
else if (error == 4)
{
Serial.print("Error desconocido en ");
Serial.println(addr);
}
}
if (nDevices == 0)
{
Serial.println("No se encontraron dispositivos\n");
}
else
{
Serial.println("Terminado\n");
}
}
}
void configSensors(int sensor, uint8_t new_address, uint8_t old_address)
{
switch (sensor)
{
case 0:
Sensor1.setI2Caddr(new_address, 0, old_address);
digitalWrite(POWER_ENABLE_S1, LOW);
//detectedAddreses[sensor] = new_address;
deviceCount++;
Sensor1.configure(0,new_address);
break;
case 1:
Sensor2.setI2Caddr(new_address, 0, old_address);
digitalWrite(POWER_ENABLE_S2, LOW);
//detectedAddreses[sensor] = new_address;
deviceCount++;
Sensor2.configure(0,new_address);
i = 999;
break;
case 2:
break;
}
}
void setup()
{
Serial.begin(115200);
#ifdef FAST_I2C
#if ARDUINO >= 157
Wire.setClock(400000UL); // Set I2C frequency to 400kHz (for Arduino Due)
#else
TWBR = ((F_CPU / 400000UL) - 16) / 2; // Set I2C frequency to 400kHz
#endif
#endif
pinMode(POWER_ENABLE_S1, OUTPUT);
pinMode(POWER_ENABLE_S2, OUTPUT);
digitalWrite(POWER_ENABLE_S1, HIGH);
digitalWrite(POWER_ENABLE_S2, HIGH);
Wire.begin();
scanI2C();
digitalWrite(POWER_ENABLE_S1,HIGH);
digitalWrite(POWER_ENABLE_S2,HIGH);
Sensor1.configure(3,detectedAddreses[0]);
Sensor2.configure(3,detectedAddreses[1]);
}
void measure(){
float s1;
float s2;
Sensor1.waitForBusy();
Sensor1.takeRange();
Sensor1.waitForBusy();
s1 = Sensor1.readDistance(detectedAddreses[0]);
Sensor2.waitForBusy();
Sensor2.takeRange();
Sensor2.waitForBusy();
s2 = Sensor2.readDistance(detectedAddreses[1]);
Serial.println("Sensor 1: " + String(s1) + "; Sensor 2: " + String(s2));
}
void loop()
{
/*Serial.println(detectedAddreses[0]);
Serial.println(detectedAddreses[1]);*/
measure();
}
Based on your top comment, there may be an issue with configuring both lidars at the same time.
From factory default, they will both respond to the default I2C address 0x62. So, when you try to reconfigure one at a time, they will both respond [and there may be a race condition] and will both get programmed to the new I2C address.
If [and this is a big if] the lidar can save the configuration to non-volatile storage on the unit, you can connect one at a time [physically/manually] and give them different addresses. The unit saves the address. And, next time, will only respond to the "new" address.
Then, after both units have been reconfigured, you can then connect both simultaneously and they will respond individually [as desired].
I looked at the .pdf and the wiring diagram. You may be able to connect the lidar's power pin [or enable pin] to an Arduino GPIO port pin (instead of +5V). Then, you can control the power up of each unit individually. Then, you can reconfigure both as above. That is, assert power to one, reconfigure it, power it down [with the saved config]. Do this for the other unit. Then, you can power up both units [at this point, they are responding to different I2C addresses].
Don't know if Garmin starts up the lasers immediately or whether you have to give it a "start" command. Being able to control power individually may be a good thing if there is no separate start command.
I'm not familiar with Garmin's lidars, but I've written S/W to control Velodyne lidars and we had to apply power in a staggered manner because the power surge when they both started up would "brown out" the system. With Garmin, YMMV.
If all else fails, you may have to put each unit on a separate/different physical I2C bus [because you can't reconfigure them separately].
Here's the working code,
The sensors are hocked up in the same I2C bus, power enable pins to each sensor and ground conected to arduino. Power to the sensors is supplied by a 11.1V battery with a power regulator to 5V
#include <Arduino.h>
#include <Wire.h>
#include <stdint.h>
#include <LIDARLite_v3HP.h>
#include <I2CFunctions.h>
#define POWER_ENABLE_S1 12
#define POWER_ENABLE_S2 11
#define DEFAULT_ADDRESS 98
#define FAST_I2C
#define NUMERO_LIDARS 2
LIDARLite_v3HP Sensor1;
LIDARLite_v3HP Sensor2;
int detectedAddreses[NUMERO_LIDARS];
int currentAdd;
int deviceCount = 0;
int i = 0;
void scanI2C()
{
int nDevices = 0;
while (i < NUMERO_LIDARS)
{
for (byte addr = 1; addr < 127; ++addr)
{
Wire.beginTransmission(addr);
byte error = Wire.endTransmission();
if (error == 0)
{
Serial.print("Se encontro un dispositivo en ");
Serial.print(addr);
Serial.println(" !");
++nDevices;
detectedAddreses[i] = addr;
if (addr == DEFAULT_ADDRESS)
{
configSensors(i, 66 + deviceCount, addr);
detectedAddreses[i] = addr;
i++;
}else{
detectedAddreses[i] = addr;
i++;
}
}
else if (error == 4)
{
Serial.print("Error desconocido en ");
Serial.println(addr);
}
}
if (nDevices == 0)
{
Serial.println("No se encontraron dispositivos\n");
}
else
{
Serial.println("Terminado\n");
}
}
}
void configSensors(int sensor, uint8_t new_address, uint8_t old_address)
{
switch (sensor)
{
case 0:
Sensor1.setI2Caddr(new_address, 0, old_address);
digitalWrite(POWER_ENABLE_S1, LOW);
//detectedAddreses[sensor] = new_address;
deviceCount++;
Sensor1.configure(0,new_address);
break;
case 1:
Sensor2.setI2Caddr(new_address, 0, old_address);
digitalWrite(POWER_ENABLE_S2, LOW);
//detectedAddreses[sensor] = new_address;
deviceCount++;
Sensor2.configure(0,new_address);
i = 999;
break;
case 2:
break;
}
}
void setup()
{
Serial.begin(115200);
#ifdef FAST_I2C
#if ARDUINO >= 157
Wire.setClock(400000UL); // Set I2C frequency to 400kHz (for Arduino Due)
#else
TWBR = ((F_CPU / 400000UL) - 16) / 2; // Set I2C frequency to 400kHz
#endif
#endif
pinMode(POWER_ENABLE_S1, OUTPUT);
pinMode(POWER_ENABLE_S2, OUTPUT);
digitalWrite(POWER_ENABLE_S1, HIGH);
digitalWrite(POWER_ENABLE_S2, HIGH);
Wire.begin();
scanI2C();
digitalWrite(POWER_ENABLE_S1,HIGH);
digitalWrite(POWER_ENABLE_S2,HIGH);
Sensor1.configure(3,detectedAddreses[0]);
Sensor2.configure(3,detectedAddreses[1]);
}
void measure(){
float s1;
float s2;
digitalWrite(POWER_ENABLE_S1,HIGH);
digitalWrite(POWER_ENABLE_S2,LOW);
delay(25);
Sensor1.waitForBusy();
Sensor1.takeRange();
Sensor1.waitForBusy();
s1 = Sensor1.readDistance(detectedAddreses[0]);
digitalWrite(POWER_ENABLE_S1,LOW);
digitalWrite(POWER_ENABLE_S2,HIGH);
delay(25);
Sensor2.waitForBusy();
Sensor2.takeRange();
Sensor2.waitForBusy();
s2 = Sensor2.readDistance(detectedAddreses[1]);
Serial.println("Sensor 1: " + String(s1) + "; Sensor 2: " + String(s2));
}
void loop()
{
/*Serial.println(detectedAddreses[0]);
Serial.println(detectedAddreses[1]);*/
measure();
}
I am trying to make fall detection using MPU6050, SIM900a, and Arduino Nano. after uploading the code to Arduino, the serial monitor show me this:
serial monitor output
this is the code that I have tried,
#include <SoftwareSerial.h> // Library for using software serial communication
//______________________sms part_____________________________________________
SoftwareSerial SIM900(7, 8); // rx, tx
char c = ' '; // variable to store the data from the sms module
//_______________________MPU part_______________________________________________________
#include <Wire.h>
const int MPU_addr=0x68; // I2C address of the MPU-6050
int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;
float ax=0, ay=0, az=0, gx=0, gy=0, gz=0;
//int data[STORE_SIZE][5]; //array for saving past data
//byte currentIndex=0; //stores current data array index (0-255)
boolean fall = false; //stores if a fall has occurred
boolean trigger1=false; //stores if first trigger (lower threshold) has occurred
boolean trigger2=false; //stores if second trigger (upper threshold) has occurred
boolean trigger3=false; //stores if third trigger (orientation change) has occurred
byte trigger1count=0; //stores the counts past since trigger 1 was set true
byte trigger2count=0; //stores the counts past since trigger 2 was set true
byte trigger3count=0; //stores the counts past since trigger 3 was set true
int angleChange=0;
void setup(){
randomSeed(analogRead(0));
Serial.begin(9600);// baudrate for serial monitor
while (!Serial) {
; // wait for serial port to connect. Needed for Native USB only
}
SIM900.begin(9600); // baudrate for GSM shield
Serial.println(" Logging time completed!");
delay(1000); // wait for 5 seconds
Wire.begin();
Wire.beginTransmission(MPU_addr);
Wire.write(0x6B); // PWR_MGMT_1 register
Wire.write(0); // set to zero (wakes up the MPU-6050)
Wire.endTransmission(true);
}
void loop(){
//______________________________________MPU_________________________________________
mpu_read();
//2050, 77, 1947 are values for calibration of accelerometer
// values may be different for you
ax = (AcX-2050)/16384.00;
ay = (AcY-77)/16384.00;
az = (AcZ-1947)/16384.00;
//270, 351, 136 for gyroscope
gx = (GyX+270)/131.07;
gy = (GyY-351)/131.07;
gz = (GyZ+136)/131.07;
// calculating Amplitute vactor for 3 axis
float Raw_AM = pow(pow(ax,2)+pow(ay,2)+pow(az,2),0.5);
int AM = Raw_AM * 10; // as values are within 0 to 1, I multiplied
// it by for using if else conditions
Serial.println(AM);
//Serial.println(PM);
//delay(500);
if (trigger3==true){
trigger3count++;
//Serial.println(trigger3count);
if (trigger3count>=10){
angleChange = pow(pow(gx,2)+pow(gy,2)+pow(gz,2),0.5);
//delay(10);
Serial.println(angleChange);
if ((angleChange>=0) && (angleChange<=10)){ //if orientation changes remains between 0-10 degrees
fall=true; trigger3=false; trigger3count=0;
Serial.println(angleChange);
}
else{ //user regained normal orientation
trigger3=false; trigger3count=0;
Serial.println("TRIGGER 3 DEACTIVATED");
}
}
}
if (fall==true){ //in event of a fall detection
Serial.println("FALL DETECTED");
MakeCall;
delay(100000);
fall=false;
// exit(1);
}
if (trigger2count>=6){ //allow 0.5s for orientation change
trigger2=false; trigger2count=0;
Serial.println("TRIGGER 2 DECACTIVATED");
}
if (trigger1count>=6){ //allow 0.5s for AM to break upper threshold
trigger1=false; trigger1count=0;
Serial.println("TRIGGER 1 DECACTIVATED");
}
if (trigger2==true){
trigger2count++;
//angleChange=acos(((double)x*(double)bx+(double)y*(double)by+(double)z*(double)bz)/(double)AM/(double)BM);
angleChange = pow(pow(gx,2)+pow(gy,2)+pow(gz,2),0.5); Serial.println(angleChange);
if (angleChange>=30 && angleChange<=400){ //if orientation changes by between 80-100 degrees
trigger3=true; trigger2=false; trigger2count=0;
Serial.println(angleChange);
Serial.println("TRIGGER 3 ACTIVATED");
}
}
if (trigger1==true){
trigger1count++;
if (AM>=12){ //if AM breaks upper threshold (3g)
trigger2=true;
Serial.println("TRIGGER 2 ACTIVATED");
trigger1=false; trigger1count=0;
}
}
if (AM<=2 && trigger2==false){ //if AM breaks lower threshold (0.4g)
trigger1=true;
Serial.println("TRIGGER 1 ACTIVATED");
}
//It appears that delay is needed in order not to clog the port
delay(100);
}
//______________________________MPU raeding________________________
void mpu_read(){
Wire.beginTransmission(MPU_addr);
Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H)
Wire.endTransmission(false);
Wire.requestFrom(MPU_addr,14,true); // request a total of 14 registers
AcX=Wire.read()<<8|Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
AcY=Wire.read()<<8|Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
AcZ=Wire.read()<<8|Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
Tmp=Wire.read()<<8|Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
GyX=Wire.read()<<8|Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
GyY=Wire.read()<<8|Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
GyZ=Wire.read()<<8|Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
}
//______________________________________GSM module calling function________________
void MakeCall()
{
SIM900.println("ATD+*********;"); // ATDxxxxxxxxxx; -- watch out here for semicolon at the end!!
Serial.println("Calling "); // print response over serial port
delay(20000); //wait
}
the configuration of MPU050
VCC --- 5V in arduino
GND ----GND
SCL ----A5
SDA----A4
INT ----- D2
The serial monitor should show some numbers first but instead of showing numbers trigger 1 activated and disactivate automatically and I didn't even touch it . No matter how much I throw the MPU6050, trigger 2 and 3 are not activated. all the three trigger must be activated to make the sim900a module make a call.
what could be the reason ? could be the code or the hardware connection.
here is a picture of the MPU position in case it could be the problem.
MPU6050 position
edit:
i have tried this code but all the values show zero values
#include <MPU6050.h>
/*
MPU6050 Triple Axis Gyroscope & Accelerometer. Simple Gyroscope Example.
Read more: http://www.jarzebski.pl/arduino/czujniki-i-sensory/3-osiowy-zyroskop-i-akcelerometr-mpu6050.html
GIT: https://github.com/jarzebski/Arduino-MPU6050
Web: http://www.jarzebski.pl
(c) 2014 by Korneliusz Jarzebski
*/
#include <Wire.h>
MPU6050 mpu;
void setup()
{
Serial.begin(115200);
// Initialize MPU6050
Serial.println("Initialize MPU6050");
while(!mpu.begin(MPU6050_SCALE_2000DPS, MPU6050_RANGE_2G))
{
Serial.println("Could not find a valid MPU6050 sensor, check wiring!");
delay(500);
}
// If you want, you can set gyroscope offsets
// mpu.setGyroOffsetX(155);
// mpu.setGyroOffsetY(15);
// mpu.setGyroOffsetZ(15);
// Calibrate gyroscope. The calibration must be at rest.
// If you don't want calibrate, comment this line.
mpu.calibrateGyro();
// Set threshold sensivty. Default 3.
// If you don't want use threshold, comment this line or set 0.
mpu.setThreshold(3);
// Check settings
checkSettings();
}
void checkSettings()
{
Serial.println();
Serial.print(" * Sleep Mode: ");
Serial.println(mpu.getSleepEnabled() ? "Enabled" : "Disabled");
Serial.print(" * Clock Source: ");
switch(mpu.getClockSource())
{
case MPU6050_CLOCK_KEEP_RESET: Serial.println("Stops the clock and keeps the timing generator in reset"); break;
case MPU6050_CLOCK_EXTERNAL_19MHZ: Serial.println("PLL with external 19.2MHz reference"); break;
case MPU6050_CLOCK_EXTERNAL_32KHZ: Serial.println("PLL with external 32.768kHz reference"); break;
case MPU6050_CLOCK_PLL_ZGYRO: Serial.println("PLL with Z axis gyroscope reference"); break;
case MPU6050_CLOCK_PLL_YGYRO: Serial.println("PLL with Y axis gyroscope reference"); break;
case MPU6050_CLOCK_PLL_XGYRO: Serial.println("PLL with X axis gyroscope reference"); break;
case MPU6050_CLOCK_INTERNAL_8MHZ: Serial.println("Internal 8MHz oscillator"); break;
}
Serial.print(" * Gyroscope: ");
switch(mpu.getScale())
{
case MPU6050_SCALE_2000DPS: Serial.println("2000 dps"); break;
case MPU6050_SCALE_1000DPS: Serial.println("1000 dps"); break;
case MPU6050_SCALE_500DPS: Serial.println("500 dps"); break;
case MPU6050_SCALE_250DPS: Serial.println("250 dps"); break;
}
Serial.print(" * Gyroscope offsets: ");
Serial.print(mpu.getGyroOffsetX());
Serial.print(" / ");
Serial.print(mpu.getGyroOffsetY());
Serial.print(" / ");
Serial.println(mpu.getGyroOffsetZ());
Serial.println();
}
void loop()
{
Vector rawGyro = mpu.readRawGyro();
Vector normGyro = mpu.readNormalizeGyro();
Serial.print(" Xraw = ");
Serial.print(rawGyro.XAxis);
Serial.print(" Yraw = ");
Serial.print(rawGyro.YAxis);
Serial.print(" Zraw = ");
Serial.println(rawGyro.ZAxis);
Serial.print(" Xnorm = ");
Serial.print(normGyro.XAxis);
Serial.print(" Ynorm = ");
Serial.print(normGyro.YAxis);
Serial.print(" Znorm = ");
Serial.println(normGyro.ZAxis);
delay(10);
}
what could be the reason?
I have problem with results (on serial monitor) of rotary encoder.
I am using Arduino UNO and RotaryEncoder library.
When I am running example code serial monitor show proper values when rotating with any speed.
I want to use encoder to change volume in Df-player.
Problem starts when I want to use this code together with more complicated one - Mp3 player.
It actually works only when I am rotating encoder very very slowly
#include <SPI.h>
#include <MFRC522.h>
#include <Arduino.h>
#include <SoftwareSerial.h>
#include <DFRobotDFPlayerMini.h>
#include <RotaryEncoder.h>
#define RST_PIN 9 // Configurable, see typical pin layout above
#define SS_PIN 10 // Configurable, see typical pin layout above
#define PIN_IN1 2
#define PIN_IN2 3
#define ROTARYSTEPS 1
#define ROTARYMIN 0
#define ROTARYMAX 30
const int playPauseButton = 4;
const int shuffleButton = 5;
boolean isPlaying = false;
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance
SoftwareSerial mySoftwareSerial(5, 6); // RX, TX
DFRobotDFPlayerMini myDFPlayer;
void printDetail(uint8_t type, int value);
// Setup a RotaryEncoder with 2 steps per latch for the 2 signal input pins:
RotaryEncoder encoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::TWO03);
// Last known rotary position.
int lastPos = -1;
//*****************************************************************************************//
void setup() {
Serial.begin(9600); // Initialize serial communications with the PC, COMMENT OUT IF IT FAILS TO PLAY WHEN DISCONNECTED FROM PC
mySoftwareSerial.begin(9600);
SPI.begin(); // Init SPI bus
mfrc522.PCD_Init(); // Init MFRC522 card
while (! Serial);
encoder.setPosition(5 / ROTARYSTEPS); // start with the value of 5.
pinMode(playPauseButton, INPUT_PULLUP);
pinMode(shuffleButton, INPUT_PULLUP);
Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));
if (!myDFPlayer.begin(mySoftwareSerial)) { //Use softwareSerial to communicate with mp3.
Serial.println(F("Unable to begin:"));
Serial.println(F("1.Please recheck the connection!"));
Serial.println(F("2.Please insert the SD card!"));
}
Serial.println(F("DFPlayer Mini online. Place card on reader to play a spesific song"));
//myDFPlayer.volume(15); //Set volume value. From 0 to 30
//volumeLevel = map(analogRead(volumePot), 0, 1023, 0, 30); //scale the pot value and volume level
myDFPlayer.volume(5);
//prevVolume = volumeLevel;
//----Set different EQ----
myDFPlayer.EQ(DFPLAYER_EQ_NORMAL);
// myDFPlayer.EQ(DFPLAYER_EQ_POP);
// myDFPlayer.EQ(DFPLAYER_EQ_ROCK);
// myDFPlayer.EQ(DFPLAYER_EQ_JAZZ);
// myDFPlayer.EQ(DFPLAYER_EQ_CLASSIC);
// myDFPlayer.EQ(DFPLAYER_EQ_BASS);
}
//*****************************************************************************************//
void loop() {
encoder.tick();
// get the current physical position and calc the logical position
int newPos = encoder.getPosition() * ROTARYSTEPS;
if (newPos < ROTARYMIN) {
encoder.setPosition(ROTARYMIN / ROTARYSTEPS);
newPos = ROTARYMIN;
} else if (newPos > ROTARYMAX) {
encoder.setPosition(ROTARYMAX / ROTARYSTEPS);
newPos = ROTARYMAX;
} // if
if (lastPos != newPos) {
Serial.println(newPos);
myDFPlayer.volume(newPos);
lastPos = newPos;
} // if
// Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory.
MFRC522::MIFARE_Key key;
for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF;
//some variables we need
byte block;
byte len;
MFRC522::StatusCode status;
if (digitalRead(playPauseButton) == LOW) {
if (isPlaying) {
myDFPlayer.pause();
isPlaying = false;
Serial.println("Paused..");
}
else {
isPlaying = true;
myDFPlayer.start();
Serial.println("Playing..");
}
delay(500);
}
if (digitalRead(shuffleButton) == LOW) {
myDFPlayer.randomAll();
Serial.println("Shuffle Play");
isPlaying = true;
delay(1000);
}
//-------------------------------------------
// Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
if ( mfrc522.PICC_IsNewCardPresent()) {
// Select one of the cards
if ( ! mfrc522.PICC_ReadCardSerial()) {
return;
}
Serial.println(F("**Card Detected:**"));
//-------------------------------------------
mfrc522.PICC_DumpDetailsToSerial(&(mfrc522.uid)); //dump some details about the card
//mfrc522.PICC_DumpToSerial(&(mfrc522.uid)); //uncomment this to see all blocks in hex
//-------------------------------------------
Serial.print(F("Number: "));
//---------------------------------------- GET NUMBER AND PLAY THE SONG
byte buffer2[18];
block = 1;
len = 18;
status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 1, &key, &(mfrc522.uid)); //line 834
if (status != MFRC522::STATUS_OK) {
Serial.print(F("Authentication failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return;
}
status = mfrc522.MIFARE_Read(block, buffer2, &len);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("Reading failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return;
}
//PRINT NUMBER
String number = "";
for (uint8_t i = 0; i < 16; i++)
{
number += (char)buffer2[i];
}
number.trim();
Serial.print(number);
//PLAY SONG
myDFPlayer.play(number.toInt());
isPlaying = true;
//----------------------------------------
Serial.println(F("\n**End Reading**\n"));
delay(1000); //change value if you want to read cards faster
mfrc522.PICC_HaltA();
mfrc522.PCD_StopCrypto1();
}
}
Any ideas what is wrong?
You have a delay(1000) in your main loop, and since your RotaryEncoder object seems to need a tick() function, i am assuming that it is not interrupt driven. This means that it will check only once per second if it has moved to the next step.
If a rotary encoder is stepped twice, and the middle step is missed by the MCU, the latter has no way of knowing which way round the encoder has turned.
So in this case you can only turn it one step per second.
What you need is, either:
a free running main loop, which goes round at least 100 times per second. (less nice)
a rotary encoder driver that is interrupt driven. (very nice)
I don't know if such a library exists, because i tend not to use arduino libs, but it is a very good exercise to write your own using GPIO interrupts.
I'm working on a project that collects data from an Arduino Pro Mini and sends it using SPI to a raspberry Pi for storage.
The Pro Mini will be reading analog input and calculating voltage (once I finish), and passing values to the Pi when prompted using an ISR.
I'm using C/C++ for both platforms to keep it uniform. The slave code is snipped together using Arduino IDE and the master code is based off a BCM2835 SPI library example for the Pi.
Arduino code is meant to calculate a float value and pre-process the float value into an array of 4 bytes/chars (I'm shooting for binary because I think it is the best way to go).
Once prompted by the Pi, each byte is sent and will be recompiled into a float.
Here is what I have now:
Slave
/*************************************************************
ARDUINO BREAKER READ/SPI PRE-PROC/TRANSMIT CASES
****************************************************************/
/***************************************************************
Global Variables
***************************************************************/
byte command = 0; //command from PI
byte bytes[4]; //
int sensorVoltage, sensorCurrent; //eventual live reading vars
float Voltage, Current, RealCurrent, RealVoltage, Power;
/***************************************************************
Set Up
-designate arudino as slave
-turn on interrupts
***************************************************************/
void setup (void)
{
//debugging with serial monitor
Serial.begin(9600);
// Set up arduino as slave
pinMode(MOSI, INPUT);
pinMode(SCK, INPUT);
pinMode(SS, INPUT);
pinMode(MISO, OUTPUT);
// turn on SPI in slave mode
SPCR |= _BV(SPE);
// turn on interrupts
SPCR |= _BV(SPIE);
} // end of setup
/*************************************************************
Interrupt Service Routine
************************************************************/
// SPI interrupt routine
ISR (SPI_STC_vect)
{
delay(500); //for errors
// Create union of shared memory space
union
{
float f_var;
unsigned char bytes[4];
} u;
// Overwrite bytes of union with float variable
u.f_var = RealVoltage;
// Assign bytes to input array
memcpy(bytes, u.bytes, 4);
byte c = SPDR;
command = c;
switch (command)
{
// null command zeroes register
case 0:
SPDR = 0;
break;
// case a - d reserved for voltage
case 'a':
SPDR = bytes[3];
break;
// incoming byte, return byte result
case 'b':
SPDR = bytes[2];
break;
// incoming byte, return byte result
case 'c':
SPDR = bytes[1];
break;
// incoming byte, return byte result
case 'd':
SPDR = bytes[0];
break;
/** // case e -h reserved for current
case 'e':
SPDR = amps.b[0];
break;
// incoming byte, return byte result
case 'f':
SPDR = amps.b[1];
break;
// incoming byte, return byte result
case 'g':
SPDR = amps.b[2];
break;
// incoming byte, return byte result
case 'h':
SPDR = amps.b[3];
break;
// case i - l reserved for wattage
case 'i':
SPDR = watts.b[0];
break;
// incoming byte, return byte result
case 'j':
SPDR = watts.b[1];
break;
// incoming byte, return byte result
case 'k':
SPDR = watts.b[2];
break;
// incoming byte, return byte result
case 'l':
SPDR = watts.b[3];
break;**/
} // end of switch
} // end of interrupt service routine (ISR) SPI_STC_vect
/***************************************************************
Loop until slave is enabled by Pi.
****************************************************************/
void loop (void)
{
/*************************************************************
Read and Calculate
****************************************************************/
/**
sensorVoltage = analogRead(A2);
sensorCurrent = analogRead(A3);
Voltage = sensorVoltage*(5.0/1023.0);
Current = sensorCurrent*(5.0/1023.0);
RealCurrent = Current/0.204545;
RealVoltage = (Voltage/0.022005);
Power = RealVoltage*RealCurrent;
**/
RealVoltage = 1.234;
/*************************************************************
Loop Check for SS activation
****************************************************************/
// if SPI not active, clear current command, else preproc floats and pass to SPI
if (digitalRead (SS) == HIGH){
command = 0;
}
/*************************************************************
Debug with serial monitor
****************************************************************/
/*
Serial.print("Byte 3: ");
Serial.println(bytes[3],BIN);
delay(500);
Serial.print("Byte 2: ");
Serial.println(bytes[2],BIN);
delay(500);
Serial.print("Byte 1: ");
Serial.println(bytes[1],BIN);
delay(500);
Serial.print("Byte 0: ");
Serial.println(bytes[0],BIN);
delay(1000);
Serial.println();*/
}
Master
#include <bcm2835.h>
#include <stdio.h>
void setup()
{
bcm2835_spi_begin();
bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_LSBFIRST); // The default
bcm2835_spi_setDataMode(BCM2835_SPI_MODE0); // The default
bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_65536); // The default
bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, LOW); // the default
}
char getByte(const char command){
char read_data = bcm2835_spi_transfer(command);
delay(100);
return read_data;
}
int main(int argc, char **argv)
{
//If you call this, it will not actually access the GPIO
//Use for testing
//bcm2835_set_debug(1);
if (!bcm2835_init())
return 1;
setup();
//Start communication
bcm2835_spi_chipSelect(BCM2835_SPI_CS0);// Enable 0
//voltage 1-4
char read_data = getByte('a');
printf("byte is %02d\n", read_data);
read_data = getByte('b');
printf("byte is %02d\n", read_data);
read_data = getByte('c');
printf("byte is %02d\n", read_data);
read_data = getByte('d');
printf("byte is %02d\n", read_data);
/** voltage = volts.f;
printf("%.6f", voltage);
printf("\n");
**/
delay(1000);
bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, HIGH);
bcm2835_spi_chipSelect(BCM2835_SPI_CS0);// Disable 0
bcm2835_spi_end();
bcm2835_close();
return 0;
}
I'm using a fixed value to debug the code. Sometimes the output from SPI on the Pi is accurate, but otherwise it changes and outputs partially accurate and/or random bytes.
The issue I have been unable to work out is stability on the side of the Pi, so I am looking for help evaluating whether my code is causing inaccuracies or if it's my hardware.
At a guess I would say that this is a timing issue between the sender and receiver. Try looking at the bits of the data that you are receiving and see if they are shifted forward or backward. This will possibly indicate that the pi is waiting too long to begin receiving, or not waiting long enough for all of the data. I think the issues are probably around the delays:
delay(500); //for errors
on the Arduino, and
delay(1000);
on the receiver. Why are you using these? 500ms is a long time to keep the pi waiting for a response to the SPI data.
Just a note, there is also now an SPI kernel driver (spidev) for the pi - this is a much more industry standard approach, and is potentially a more robust method.
There's a good example of this on the raspberry pi github site: https://github.com/raspberrypi/linux/blob/rpi-4.4.y/Documentation/spi/spidev_test.c
Here is my code. It compiles and runs on my Arduino MEGA 2560.
#include "Arduino.h"//Standard Arduino Library
#include "Print.h" //Print to serial library, Serial.Println would not work by default for some reason.
#define led_pin 13 //Set var led_pin to equal 13, meaning pin 13
#define pinstate digitalRead(read_pin)
#define read_pin 50 // " 50, "50
int loopstore; //Def as global var so it won't be reset on next loop iteration
void setup() //Setup function, used to set pins and vars before running main Arduino Program
{
Serial.begin(9600); //Start serial comms, set baud rate
Serial.println("\nHello User.\n\nArduio has set baud rate and started serial communication.\n\nThank You, Sketch will run momentarily.\n\n");
pinMode(led_pin,OUTPUT); //Set led_pin to digital output mode;
pinMode(read_pin,INPUT); //", " read mode
}
void loop() //Actual program
{
loopstart = 1;
do
{
++loopstore;
} while (loopstart == 0);
Serial.println("This program has ran this many times:\n");
Serial.println(loopstore);
digitalWrite(led_pin,HIGH); //Set pin high
delay(1000); //Wait
if (pinstate == 1) //If else statement for outputting pin state to console
{
Serial.println("\nPin is in a HIGH state\n\n"); // Output to console
}
else
{
Serial.println("Pin is in a LOW state\n\n"); // Output to console
}
delay(1500); //Wait
digitalWrite(led_pin,LOW); //Set pin to Low State
delay(1000); //Wait
if (pinstate == 1) //If else funct for outputting pin state to console
{
Serial.println("Pin is in a HIGH state\n\n"); // Output to console
}
else
{
Serial.println("Pin is in a LOW state\n\n"); // Output to console
}
delay(1000); //Wait
digitalWrite(led_pin,HIGH); //Set pin high
delay(1500); //Wait
if (pinstate == 1) //If else funct for outputting pin state to console
{
Serial.println("Pin is in a HIGH state\n\n"); // Output to console
}
else
{
Serial.println("Pin is in a LOW state\n\n"); // Output to console
}
delay(1000); //Wait
digitalWrite(led_pin,LOW); //Set pin to Low State
delay(1500); //Wait
if (pinstate == 1) //If else funct for outputting pin state to console
{
Serial.println("Pin is in a HIGH state\n\n"); // Output to console
}
else
{
Serial.println("Pin is in a LOW state\n\n"); // Output to console
}
delay(1000); //Wait
digitalWrite(led_pin,HIGH); //Set pin high
delay(500); //Wait
if (pinstate == 1) //If else funct for outputting pin state to console
{
Serial.println("Pin is in a HIGH state\n\n"); // Output to console
}
else
{
Serial.println("Pin is in a LOW state\n\n"); // Output to console
}
delay(1000); //Wait
digitalWrite(led_pin,LOW); //Set pin to Low State
delay(500); //Wait
if (pinstate == 1) //If else funct for outputting pin state to console
{
Serial.println("Pin is in a HIGH state\n\n"); // Output to console
}
else
{
Serial.println("Pin is in a LOW state\n\n"); // Output to console
}
}
I'm just learning to work with Arduino and I made a quick and dirty program that simply sets the pin state of the LED pin on the Arduino (13) and then reads it with pin 50. It's a pointless program but I'm trying to learn/practice.
For extra practice I also made a counter for the amount of times the loop() function runs.
The "Do While" statement I made increments the counter. Then I print the result to serial afterwards. See that if loopstart == 0, the "Do While" statement runs again. This is impossible because it never gets set to 0. I wanted a sort of "passthrough" counter, but is this the best way?
I am almost positive there has to be a way to do what I did above more efficiently, but being new to Arduino (and programming in general), I have no idea how I would be able to simplify this.
Anybody have any suggestions or perhaps a place where they could point me to?
I've tried looking online for examples of a counter in C++, but I couldn't find anything that was outside of a "For" loop.
Thank you for your time and helping a kid learn!
Edit: Did not know about CodeReview. Thanks!
Maybe something like that can best suit you.
If I understand correctly your program basically toggle 3 times the led and then check for the pin state with a delay before and after (which is variable).
If you want me to detail some more parts, ask me I will edit my post ;)
#include "Arduino.h"//Standard Arduino Library
#include "Print.h" //Print to serial library, Serial.Println would not work by default for some reason.
// Some debugging macros
#define DEBUG 1
#define slog(a) { if (DEBUG) Serial.println(a); }; // No debug directive will be in compiled file if DEBUG is set to 0
// Let's define our port mapping
#define LED_PIN _BV(7) //bit 7 on PORTB on 2560 correspond to digital pin 13 (check http://arduino.cc/en/Hacking/PinMapping2560)
#define READ_PIN _BV(3)
// Some quick access for led pin / read pin manipulation
// Let's use bitwise operation on PORTB, digitalRead => 28 cycle, direct read with PORTB => 1 cycle (28x faster!)
// I prefer defining setters as functions, easier to read, but you are not force to (it is exactly the same once compiled)
//#define LED_ON() { PORTB |= LED_PIN; } // Put LED_PIN bit to 1 on PORTB
//#define LED_OFF() { PORTB &= ~LED_PIN; } // Put LED_PIN bit to 0 on PORTB
#define LED_TOGGLE() { PORTB ^= LED_PIN; } // Put LED_PIN bit to 0 if it was 1 or to 1 if it was 0
#define READ_STATE PORTB & READ_PIN // Read LED_PIN bit on PORTB
int loopcount = 0; //Def as global var so it won't be reset on next loop iteration
// Let's create an array which will define all the delays before and after serial calls
// ex: {1000, 1500} => 1000ms before serial output, 1500ms after serial output
int wrapDelays[][2] = { {1000, 1500}, {1000, 1000}, {1500, 1000}, {1500, 1000}, {500, 1000}, {500, 0} };
void setup() //Setup function, used to set pins and vars before running main Arduino Program
{
if (DEBUG) Serial.begin(9600); //Start serial comms, set baud rate
slog("\nHello User.\n\nArduio has set baud rate and started serial communication.\n\nThank You, Sketch will run momentarily.\n\n");
// Output/Input for PORTB (in DDRB register)
DDRB |= LED_PIN; // Set LED_PIN to digital output mode (put LED_PIN bit to 1)
DDRB &= ~READ_PIN; // Ensure READ_PIN is in input mode (put READ_PIN bit to 0)
}
// ToggleLed, write read pin state on serial, and wait `delayBefore`ms before and `delayAfter`ms after
void toggleLedBetweenDelays(int delayBefore, int delayAfter){
LED_TOGGLE();
if (delayBefore > 0) delay(delayBefore);
if (READ_STATE) {//If else funct for outputting pin state to console
slog("Pin is in a HIGH state\n\n"); // Output to console
}
else
slog("Pin is in a LOW state\n\n"); // Output to console
if (delayAfter > 0) delay(delayAfter);
}
void loopCounter(){
loopcount++; // increase count of loops
slog("This program has ran this many times:\n");
slog(loopcount);
}
void loop() //Actual program
{
for (int i = 0, l = sizeof(wrapDelays) / sizeof(wrapDelays[0]); i < l; ++i)
{
toggleLedBetweenDelays(wrapDelays[i][0], wrapDelays[i][1]);
}
loopCounter();
}
Note: Don't forget that it's not because the code you write is smaller that the final compiled binary will also be smaller/optimized.