Hi!
So, we're trying to create a rover with multiple ultrasonics sensors (all HC-SR04), sensors like the BMP-280 and BNO-085, servo board (PCA9685), and OLED display (SSD1306).
Because we want to be continuously monitoring the environment as we move (including obstacles), we want to use the NewPing code with interrupts as shown in the example code "NewPing15SensorsTimer".
I understand that I2C also needs interrupts which is probably why the OLED display isn't able to show data from the ultrasonics.
I've tried moving "display.display()" to:
- the main loop,
- to the end of the oneSensorCycle() function as recommended by the author (@TimEckel) , and
- to the echotest (based on my understanding that a new interrupt hasn't been started yet and the prior one was closed).
The result is the same: the program works fine and writes to serial no problems, but if I uncomment display.display() anywhere, then the program hangs.
I would like to display the ultrasonics' distance data on the OLED.
(And I'm worried that we won't be able to use the other sensors over I2C).
So what should we do? Code below:
// ---------------------------------------------------------------------------
// I2C addresses for breadboard:
// 0x3C - OLED Display
// 0x76 - BMP-280
// 0x70 and 0x76 - servo board
// ? - BNO085
//
//
// ---------------------------------------------------------------------------
// Before attempting to use this sketch, please read the "Help with 15 Sensors Example Sketch":
// https://bitbucket.org/teckel12/arduino-new-ping/wiki/Help%20with%2015%20Sensors%20Example%20Sketch
//
// This example code was used to successfully communicate with 15 ultrasonic sensors. You can adjust
// the number of sensors in your project by changing SONAR_NUM and the number of NewPing objects in the
// "sonar" array. You also need to change the pins for each sensor for the NewPing objects. Each sensor
// is pinged at 33ms intervals. So, one cycle of all sensors takes 495ms (33 * 15 = 495ms). The results
// are sent to the "oneSensorCycle" function which currently just displays the distance data. Your project
// would normally process the sensor results in this function (for example, decide if a robot needs to
// turn and call the turn function). Keep in mind this example is event-driven. Your complete sketch needs
// to be written so there's no "delay" commands and the loop() cycles at faster than a 33ms rate. If other
// processes take longer than 33ms, you'll need to increase PING_INTERVAL so it doesn't get behind.
// ---------------------------------------------------------------------------
#include <NewPing.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#define SONAR_NUM 3 // Number of sensors.
#define MAX_DISTANCE 200 // Maximum distance (in cm) to ping.
#define PING_INTERVAL 33 // Milliseconds between sensor pings (29ms is about the min to avoid cross-sensor echo).
unsigned long pingTimer[SONAR_NUM]; // Holds the times when the next ping should happen for each sensor.
unsigned int cm[SONAR_NUM]; // Where the ping distances are stored.
uint8_t currentSensor = 0; // Keeps track of which sensor is active.
char *sonarLabel[] = {"Left", "Right", "Rear"};
NewPing sonar[SONAR_NUM] = { // Sensor object array.
NewPing(10, 9, MAX_DISTANCE), // Front left. Each sensor's trigger pin, echo pin, and max distance to ping.
NewPing(12, 11, MAX_DISTANCE), // Front right
NewPing(15, 16, MAX_DISTANCE) // Back
};
void setup() {
Serial.begin(115200);
pingTimer[0] = millis() + 75; // First ping starts at 75ms, gives time for the Arduino to chill before starting.
for (uint8_t i = 1; i < SONAR_NUM; i++) // Set the starting time for each sensor.
pingTimer[i] = pingTimer[i - 1] + PING_INTERVAL;
//display.clearDisplay();
Serial.print("Display cleared");
}
void loop() {
for (uint8_t i = 0; i < SONAR_NUM; i++) { // Loop through all the sensors.
if (millis() >= pingTimer[i]) { // Is it this sensor's time to ping?
pingTimer[i] += PING_INTERVAL * SONAR_NUM; // Set next time this sensor will be pinged.
if (i == 0 && currentSensor == SONAR_NUM - 1) oneSensorCycle(); // Sensor ping cycle complete, do something with the results.
sonar[currentSensor].timer_stop(); // Make sure previous timer is canceled before starting a new ping (insurance).
currentSensor = i; // Sensor being accessed.
cm[currentSensor] = 0; // Make distance zero in case there's no ping echo for this sensor.
sonar[currentSensor].ping_timer(echoCheck); // Do the ping (processing continues, interrupt will call echoCheck to look for echo).
}
}
// Other code that *DOESN'T* analyze ping results can go here.
// display.clearDisplay();
// display.print(cm[i]);
// display.print(" ");
// display.display();
}
void echoCheck() { // If ping received, set the sensor distance to array.
if (sonar[currentSensor].check_timer())
cm[currentSensor] = sonar[currentSensor].ping_result / US_ROUNDTRIP_CM;
//display.display();
}
void oneSensorCycle() { // Sensor ping cycle complete, do something with the results.
// The following code would be replaced with your code that does something with the ping results.
for (uint8_t i = 0; i < SONAR_NUM; i++) {
// Serial.print(i);
// Serial.print(" ");
Serial.print(sonarLabel[i]);
Serial.print(" = ");
Serial.print(cm[i]);
Serial.print("cm \t");
// display.print(cm[i]);
// display.print(" ");
}
Serial.println();
// display.display();
}
/*void oledUltrasonics() { // write ultrasound data to OLED screen
display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(0,0); // Start at top-left corner
display.print(cm[0]);
display.print(" ");
display.print(cm[1]);
display.print(" ");
display.println(cm[2]);
display.display();
} */