Can read, but cannot write serial ports on Ubuntu 16.04 - serial-port

I have a strange problem with trying to write data to a serial port.
I am running Ubuntu 16.04 on a NUC7i7DNBE, and am trying to make a serial connection to an Arduino UNO. The Serial API that I am using is found here: http://docs.ros.org/kinetic/api/serial/html/classserial_1_1Serial.html
I have written a simple program which opens the serial port "ttyACM0" to communicate with the arduino. I have tested this code on another computer running Ubuntu 16.04, and everything worked fine, the only permissions I had to set where adding the user to the dialout group.
On the NUC, however, I have added the user to the dialout group. This allowed the program to read from the Arduino, but it still does not write to the Arduino. The Arduino IDE will write to the Arduino just fine, but my program will not.
I am assuming that I am having trouble with serial write permissions in Ubuntu.
Steps I have taken:
I have added the user to the dialout group
I have added a rule in /etc/udev/rules.d/ which states:
SUBSYSTEMS=="tty", GROUP="dialout", MODE="0666"
Afterward, I sent the commands:
sudo chown root:root /etc/udev/rules.d/50-AVCusb.rules
sudo chmod 0644 /etc/udev/rules.d/50-AVCusb.rules
udevadm control --reload-rules
I followed some information found on stack exchange to get to this point:
https://unix.stackexchange.com/questions/111593/allow-non-root-user-to-read-write-dev-files
I have tried using an FTDI device to write to the Arduino port. The FTDI device uses the ttyUSB0 port rather than the ttyACM0 port. The result was the same; can read, but can't write.
I have also run my external hard-drive on the NUC to see if there was any kind of hardware issue. When I ran the program from my external hard drive, I had no problem reading from and writing to the Arduino.
I have not dealt much with Ubuntu permissions or ports in general, please help me find and upload any other information that you may need in order to help me solve this problem.
Code on NUC:
#include <ros/ros.h>
#include <serial/serial.h>
using namespace serial;
Serial ser;
static const uint8_t MOTOR_ID = 0;
void writeMotor(uint8_t byte)
{
size_t size = 4;
uint8_t buffer[size];
buffer[0] = 'G'; //PID
buffer[1] = 'O';
buffer[2] = MOTOR_ID; //address
buffer[3] = byte; //data byte
ser.write(buffer, size);
}
int main() {
ros::init(argc, argv, "servo_esc_driver");
std::string port = "/dev/ttyACM0";
Timeout timeout = Timeout(0, 0, 0, 0, 0);
bytesize_t bytesize = eightbits;
parity_t parity = parity_none;
stopbits_t stopbits = stopbits_one;
flowcontrol_t flowcontrol = flowcontrol_none;
try{
ser.setPort(port);
ser.setBaudrate(115200);
ser.setTimeout(timeout);
ser.setBytesize(bytesize);
ser.setParity(parity);
ser.setStopbits(stopbits);
ser.setFlowcontrol(flowcontrol);
ser.open();
}
catch (SerialException e) {
ROS_FATAL_NAMED("Failed to connect to the Arduino UNO, %s.", e.what());
ros::shutdown();
return 0;
}
uint8_t byte = 90;
writeMotor(byte);
}
Full Code on Arduino
#include <Servo.h>
const byte N = 2;
//Servo esc;
//Servo servo;
Servo servo[N];
//int escPos = 90;
//int servoPos = 90;
int pos[N];
static const byte ESC_PIN = 7;
static const byte SERVO_PIN = 8;
static const byte RPM_FEEDBACK_PIN = 0; //interrpt 0, pin 2
static const byte SERVO_FEEDBACK_PIN = A0;
//const float MUL = 0.7058823529; //180/255
unsigned long lastTime_servoFeedback = 0;
static const byte MOTOR_ID = 0; //ID for differentiating data received and sent over serial connections
static const byte SERVO_ID = 1;
//added for motor data timeout safety feature
static const unsigned long MOTOR_DATA_TIMEOUT = 200; //4 x 50 ms (50 ms time period expected)
static unsigned long lastTimeMotorData = 0;
static const byte NEUTRAL = 90;
unsigned long last_rpm_pulse_update_ms = 0; //used for detecting a stopped car, and rejecting old data when writing to the serial port
unsigned long last_rpm_pulse_time_us = 0;//keeps track of rpms by comparing to system timer
static const long REV_PERIOD_MAX_US = 100000; //in us
unsigned long rev_period = REV_PERIOD_MAX_US; //100 ms is considered too long to be in motion
boolean forward = true;
/*Scratch that, I want these parameters set in ROS:
static const float wheel_radius = 0.05 // meters
static const float revs_to_mps_MUL = //assuming 2.85 gear ratio for brushless motor differential: https://forums.traxxas.com/showthread.php?9080733-Diff-gear-ratios
*/
//boolean rpm_period_updated = false; //rpms must be updated every 100 ms, otherwise the car has stopped, and velocity data should show 0 m/s
void rpm_feedback()
{
//Serial.println("in rpm_feedback");
last_rpm_pulse_update_ms = millis(); //notice the 'ms' here we want to use millisecond for checking whether or not data is valid. millis() can count up to 50 days while micros() only counts up to 70 minutes, thus millis() is used here.
unsigned long time_now = micros(); //use time now for accurate time calculations
unsigned long rev_period_temp = time_now - last_rpm_pulse_time_us; //get spur-gear revolution period
if(rev_period_temp > 0) rev_period = rev_period_temp; //revs are within
else rev_period = REV_PERIOD_MAX_US;
last_rpm_pulse_time_us = time_now; //using 'time_now' ensures that the time taken to get to this point in code does not interfere with rev_period accuracy - - - micros(); //reset time
if(pos[MOTOR_ID] < 90) //determine the direction that the vehicle is traveling in
{
forward = false;
}else forward = true;
//rpm_period_updated = true; not needed, only last_rpm_pulse_time_ms is needed for checking
}
void setup() {
// put your setup code here, to run once:
pinMode(RPM_FEEDBACK_PIN, INPUT_PULLUP);
attachInterrupt(RPM_FEEDBACK_PIN, rpm_feedback,FALLING); //arduino reference recommends using digitalPinToInterrupt(RPM_FEEDBACK_PIN) but the command is not recognized here
analogReference(EXTERNAL); //Using external reference for servo position
for(int i = 0; i < N; i++) //initialize
{
pos[i] = 90;
servo[i].attach(ESC_PIN + i);
}
Serial.begin(115200);
}
void loop() {
// put your main code here, to run repeatedly:
if(Serial.available() >= 1)
{
if(Serial.read() == 'G')
{
unsigned long t = millis();
while((Serial.available() < 3) && ((millis() - t) < 10)); //wait for the rest of the package, or timeout
if(Serial.available() >= 3)
{
char buf[3];
Serial.readBytes(buf, 3);
if((buf[0] == 'O') && (buf[1] >= 0) && (buf[1] < 2))
{
pos[buf[1]] = byte(buf[2]);
if(buf[1] == MOTOR_ID) lastTimeMotorData = millis(); //time stamp of last motor data retrieval
//Serial.print("buf[2]: ");
//Serial.println(byte(buf[2]), DEC);
//Serial.print("pos: ");
//Serial.println(pos[buf[1]]);
}
}
}
}
if((millis() - lastTimeMotorData) > MOTOR_DATA_TIMEOUT) pos[MOTOR_ID] = NEUTRAL; //stop the motor if data is not being received
for(int i = 0; i < N; i++)
{
servo[i].write(pos[i]);
}
if((millis() - lastTime_servoFeedback) >= 50) // 20Hz 20) //50Hz matches current ROS driver settings
{
lastTime_servoFeedback = millis();
int servo_feedback = analogRead(SERVO_FEEDBACK_PIN);
Serial.write('G'); //PID
Serial.write('O');
Serial.write(SERVO_ID);
//Serial.print(servo_feedback);
Serial.write(lowByte(servo_feedback));
Serial.write(highByte(servo_feedback));
//Serial.println(servo_feedback);
float rev_frequency;
if((last_rpm_pulse_update_ms + 100) < millis()) rev_frequency = 0; //use millis() since it can count up to 50 days, and will not have a chance of a hiccup after 70 minutes of using micros()
//instead, correct period when slowing down, also stop when the maximum threshold is reached
//if((micros() - last_rpm_pulse_time_us) >= REV_PERIOD_MAX_US) rev_frequency = 0; //car is stopped in this case. I decided not to try correcting the period as mentioned above
else rev_frequency = (float) 1/rev_period*1000000;
byte *rev_freq_bytes_to_transmit = (byte *) &rev_frequency;
if(forward == false) rev_frequency = -rev_frequency; //a negative frequency is used for reverse
Serial.write('G'); //PID
Serial.write('O');
Serial.write(MOTOR_ID); //used for addressing
Serial.write(rev_freq_bytes_to_transmit, 4);
}
}
Some good information may be:
snuc#usuavc:~$ udevadm info -a -n /dev/ttyACM0
Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.
looking at device '/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.0/tty/ttyACM0':
KERNEL=="ttyACM0"
SUBSYSTEM=="tty"
DRIVER==""
looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.0':
KERNELS=="1-4:1.0"
SUBSYSTEMS=="usb"
DRIVERS=="cdc_acm"
ATTRS{authorized}=="1"
ATTRS{bAlternateSetting}==" 0"
ATTRS{bInterfaceClass}=="02"
ATTRS{bInterfaceNumber}=="00"
ATTRS{bInterfaceProtocol}=="01"
ATTRS{bInterfaceSubClass}=="02"
ATTRS{bNumEndpoints}=="01"
ATTRS{bmCapabilities}=="6"
ATTRS{supports_autosuspend}=="1"
looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-4':
KERNELS=="1-4"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{authorized}=="1"
ATTRS{avoid_reset_quirk}=="0"
ATTRS{bConfigurationValue}=="1"
ATTRS{bDeviceClass}=="02"
ATTRS{bDeviceProtocol}=="00"
ATTRS{bDeviceSubClass}=="00"
ATTRS{bMaxPacketSize0}=="8"
ATTRS{bMaxPower}=="100mA"
ATTRS{bNumConfigurations}=="1"
ATTRS{bNumInterfaces}==" 2"
ATTRS{bcdDevice}=="0001"
ATTRS{bmAttributes}=="c0"
ATTRS{busnum}=="1"
ATTRS{configuration}==""
ATTRS{devnum}=="4"
ATTRS{devpath}=="4"
ATTRS{idProduct}=="0043"
ATTRS{idVendor}=="2341"
ATTRS{ltm_capable}=="no"
ATTRS{manufacturer}=="Arduino (www.arduino.cc)"
ATTRS{maxchild}=="0"
ATTRS{quirks}=="0x0"
ATTRS{removable}=="removable"
ATTRS{serial}=="55330313635351207081"
ATTRS{speed}=="12"
ATTRS{urbnum}=="6990"
ATTRS{version}==" 1.10"
looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1':
KERNELS=="usb1"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{authorized}=="1"
ATTRS{authorized_default}=="1"
ATTRS{avoid_reset_quirk}=="0"
ATTRS{bConfigurationValue}=="1"
ATTRS{bDeviceClass}=="09"
ATTRS{bDeviceProtocol}=="01"
ATTRS{bDeviceSubClass}=="00"
ATTRS{bMaxPacketSize0}=="64"
ATTRS{bMaxPower}=="0mA"
ATTRS{bNumConfigurations}=="1"
ATTRS{bNumInterfaces}==" 1"
ATTRS{bcdDevice}=="0415"
ATTRS{bmAttributes}=="e0"
ATTRS{busnum}=="1"
ATTRS{configuration}==""
ATTRS{devnum}=="1"
ATTRS{devpath}=="0"
ATTRS{idProduct}=="0002"
ATTRS{idVendor}=="1d6b"
ATTRS{interface_authorized_default}=="1"
ATTRS{ltm_capable}=="no"
ATTRS{manufacturer}=="Linux 4.15.0-32-generic xhci-hcd"
ATTRS{maxchild}=="12"
ATTRS{product}=="xHCI Host Controller"
ATTRS{quirks}=="0x0"
ATTRS{removable}=="unknown"
ATTRS{serial}=="0000:00:14.0"
ATTRS{speed}=="480"
ATTRS{urbnum}=="76"
ATTRS{version}==" 2.00"
looking at parent device '/devices/pci0000:00/0000:00:14.0':
KERNELS=="0000:00:14.0"
SUBSYSTEMS=="pci"
DRIVERS=="xhci_hcd"
ATTRS{broken_parity_status}=="0"
ATTRS{class}=="0x0c0330"
ATTRS{consistent_dma_mask_bits}=="64"
ATTRS{d3cold_allowed}=="1"
ATTRS{dbc}=="disabled"
ATTRS{device}=="0x9d2f"
ATTRS{dma_mask_bits}=="64"
ATTRS{driver_override}=="(null)"
ATTRS{enable}=="1"
ATTRS{irq}=="122"
ATTRS{local_cpulist}=="0-7"
ATTRS{local_cpus}=="ff"
ATTRS{msi_bus}=="1"
ATTRS{numa_node}=="-1"
ATTRS{revision}=="0x21"
ATTRS{subsystem_device}=="0x2070"
ATTRS{subsystem_vendor}=="0x8086"
ATTRS{vendor}=="0x8086"
looking at parent device '/devices/pci0000:00':
KERNELS=="pci0000:00"
SUBSYSTEMS==""
DRIVERS==""

I decided that the problem was with the ROS version of serial. I decided to try some native linux library, termios, and had success writing to the port!
I found this example code:
https://en.wikibooks.org/wiki/Serial_Programming/Serial_Linux
The problem lies in the ros serial installation somehow.

Don't know if you still want to solve this with serial/serial.h, but I think that your problem might be in the timeout settings.
I'm telling you this, 'cause I had the exact same problem, I could read the incoming data, but couldn't write.
The /dev/ttyUSB0 permission was ok, but not the timeout.
I found the following config on internet, gave a try and work. Now I can read and write.
try{
ser.setPort("/dev/ttyUSB0");
ser.setBaudrate(9600);
serial::Timeout to = serial::Timeout::simpleTimeout(10);
ser.setTimeout(to);
ser.open();
return true;
}
catch (SerialException e) {
return 0;

Related

'class SoftSerial' has no member named 'readString' ! Arduino DigiSpark attiny85 SoftSerial.h SoftwareSerial.h NeoPixel

i'm using Arduino IDE 1.8.12, it's setup to use digispark libs (i think), don't remember exactly what i did, watched a video online some many moths ago.
i have an issue with my sketch, when i try to compile it it gives me this error:
error: 'class SoftSerial' has no member named 'readString'
dataIn = bluetooth.readString();
^
exit status 1
'class SoftSerial' has no member named 'readString'
I am not that surprised because the original code was written for an Arduino and it used SoftwareSerial.h instead of SoftSerial.h but for some strange reason i can't load or get to work with softwareserial now, i have the libs in arduino folder but i don't know if it's even possible to load them and work with them since i've set the IDE to work with digispark.
The other solution would be to find a way to do "readString" in a way that SoftSerial recognises, i'm not sure if that is possible either.
PLEASE HELP!
#include <Adafruit_NeoPixel.h> // NeoPixel Lib
#include <SoftSerial.h> // Serial Lib
#define LED_PIN 1
#define LED_COUNT 30
SoftSerial bluetooth(3, 4); // RX TX
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
int brightness = 100; //
int redColor = 0;
int greenColor = 0;
int blueColor = 0;
String dataIn = ""; //
unsigned long timer1 = 0;
void setup()
{
Serial.begin(9600);
bluetooth.begin (9600);
strip.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
strip.show(); // Turn OFF all pixels ASAP
strip.setBrightness(brightness); // Set BRIGHTNESS to about 1/5 (max = 255)
}
void loop(){
if (bluetooth.available() > 0);{
dataIn = bluetooth.readString();
delay(20);
// Serial.println(dataIn);
if (dataIn.startsWith("1")){
delay(10);
String R = dataIn.substring(dataIn.indexOf("R") + 1, dataIn.indexOf("G"));
redColor = R.toInt();
Serial.println(R);
String G = dataIn.substring(dataIn.indexOf("G") + 1, dataIn.indexOf("B"));
greenColor = G.toInt();
Serial.println(G);
String B = dataIn.substring(dataIn.indexOf("B") +1, dataIn.indexOf("E"));
blueColor = B.toInt();
Serial.println(B);
}
else if (dataIn.startsWith("2")){
String stringBrightness = dataIn.substring(dataIn.indexOf("2") + 1, dataIn.length());
brightness = stringBrightness.toInt();
strip.setBrightness(brightness);
Serial.println(brightness);
}
for (int i = 0; i < LED_COUNT; i++){
strip.setPixelColor(i, strip.Color(greenColor, redColor, blueColor));
}
}
strip.show();
delay(20);
}
Simply implement the same functionality in your sketch using read().
readString blocks for a set amount of time. It freezes your sketch waiting on the transmission to complete for 1 second. This isn't great for most sketches. Most of the time it would be better to implement a non-blocking read. There are also big issues with using the String class on smaller microcontrollers like the UNO and especially the tiny85 in the digiSpark. It would be best on that platform to stick to c-style strings. But here's how to mimic readString if that's really what you want to do.
String myReadString() {
unsigned long startTime = millis();
char c = 0;
String message = "";
while (c!= '\n' && (millis() - startTime <= 1000)){
if(bluetooth.available()){
c = bluetooth.read();
message += c;
}
}
return message;
And then use it like this:
if (bluetooth.available() > 0);{
dataIn = myReadString();
Again, this isn't a particularly good thing to do because all of that string concatenation will shoot holes in the tiny amount of memory you have on the 85. That's probably why they didn't implement it in the libraries for it. If I were you I'd spend some time learning how to work with serial data. Google "Robin2 serial input basics" for one good place to read from the Arduino forum. But if you really insist on String class then there's a function that will do what readString does.

Serial.write causing void loop program to stop (Digital Pins stop responding)

I have an issue trying to send some serial data through tx and rx to another arduino through a HC05 bluetooth module.
The overall project is developing a hybrid go kart and using the arduino as a simple ECU unit with a PID speed control over the PWM output controlling a DC motor. I have been working the project in steps and have go as far as setting up a footpedal with the arduino and controlling the electronic speed controller (ESC) directly. I have added a simple PID function to this along with a simple hall sensor to detect the speed and does require tuning but works great so far. Now the problem comes when I try to send data across over serial ports.
I have had the bluetooth modules connected with to separate arduinos and have successfully managed to send over data from one arduino with a pot input to another with a 3.5 inch TFT screen. When I try to integrate the master side of the project to the PID controlled DC motor the system freezes. I have since then removed the PID control and gone back to direct control and it still fails, i have tried commenting out the interrupt sequence for the encoder and put a static value for RPM and still freezes. the sending sequence works if I don't attempt to use any digital outputs. I am really confused. The code I have gone down to to try and debug this can be found below. This is not the full code and has been chopped to pieces to try and eliminate this fault. however in this code below, if I comment out the sendData function the system works and the motor spins with relative speed to the pedal input. as soon as I try to send the data the system runs for a seconds then freezes. the data is still being sent and the static readings are showing just the digital output seizes to work.
#include <TimerOne.h>
int previous = 0;
int Tavg = 0; // the average
int Tout = 0;
int throttle = A0;
const int numReadings = 10;
int readings[numReadings]; // the readings from the analog input
int readIndex = 0; // the index of the current reading
int total = 0; // the running total
int ESCPin = 5;
unsigned int counter=0;
int RPM;
long Time = 0;
long ReadInt = 0;
void docount() // counts from the speed sensor
{
counter++; // increase +1 the counter value
}
void timerIsr()
{
Timer1.detachInterrupt(); //stop the timer
Serial.print("Motor Speed: ");
RPM = (counter*75 ); // RPM= counterx10*60/8 (x10 for second, 8 counts in encoder, 60 minutes === 75x counter)
Serial.print(RPM);
Serial.println(" Rotation per min"); Serial.print(Tout);Serial.print("= "); Serial.print(Tout*0.01961);Serial.println("V");
counter=0; // reset counter to zero
Timer1.attachInterrupt( timerIsr ); //enable the timer
}
void ReadEnc (){
Timer1.initialize(100000); // set timer for 0.1sec
attachInterrupt(0, docount, RISING); // increase counter when speed sensor pin goes High
Timer1.attachInterrupt( timerIsr ); // enable the timer
}
void sendData(){
if (Serial.available()>0) {
if (Serial.read() == 0){
//Serial.println(sendChars);
int RPMout = RPM;
Serial.write("<");
//delay(2);
//Serial.write(sendChars);
Serial.write("Data is,");
//delay(2);
Serial.write( itoa (RPMout, 4,10));
//delay(2);
Serial.write(", 30, 48.35");
//delay(2);
Serial.write(">");
//delay(10);
Serial.println("");
}
}
}
void setup()
{
Serial.begin(9600);
pinMode(2, INPUT_PULLUP); // internal pullup input pin 2
pinMode(ESCPin, OUTPUT);
for (int thisReading = 0; thisReading < numReadings; thisReading++) {
readings[thisReading] = 0; }
Time = millis();
ReadInt = -100;
}
void ReadSensor (){
// get the sensor value
total = total - readings[readIndex];
// read from the sensor:
readings[readIndex] = analogRead(throttle);
//Serial.println(readings[readIndex]);
// add the reading to the total:
total = total + readings[readIndex];
// advance to the next position in the array:
readIndex = readIndex + 1;
// if we're at the end of the array...
if (readIndex >= numReadings) {
// ...wrap around to the beginning:
readIndex = 0;
}
// calculate the average:
Tavg = total / numReadings;
}
void loop(){
ReadSensor();
ReadEnc();
RPM = 1800;
Tout = map(Tavg, 180, 860, 0, 200);
if (Tout>0){
analogWrite(ESCPin, Tout);
}
if (Time > ReadInt + 5000) {
sendData (); // when this is commented it works fine, tried moving it everywhere
ReadInt = Time;
}
Time = millis();
}
If anyone has any ideas please let me know, and I know I probably haven't explained my problem well so if their is any questions or more details needed please ask.
Second parameter of itoa should be a pointer to output bufffer. but you do not need itoa. use Serial.print(RPM);. For string the print and write functions are the same, but for number print has a version for int

Arduino SD card fails to write when used with another SPI device

I have an ADXL355 accelerometer attached to an Adafruit Feather Adalogger. I can configure and read the sensor. I can also write binary values to the SD card. The problem occurs when I try to read from the sensor and then write that data to the SD card. The only thing I can think of is I'm somehow messing up the SPI communication but I can't see where. I looked through pins_arduino.h for my board and the SD Card (pin 4) is on a different register than pin 10 so I don't see how I'm breaking things.
My operations proceed like this. Global sensor creation, Serial.begin, SD.begin, SPI.begin, Test sensor connection, Create file for output on SD card, Initialize sensor, Read sensor FIFO, Write to file, repeat last 2 forever.
The file is created but remains at 0 file size, ie nothing is actually written to the card.
The sensor can operate at 4 kHz which was hard to achieve using the digitalWrite functions so I switched to using the port registers on the Feather. I do it like this:
#include <SM_ADXL355_SPI_fast.h>
#include <SPI.h>
#include <SD.h>
#define cardSelect 4
ADXL355_SPIF adxl355(&DDRB, &PORTB, _BV(6)); // values taken from pins_arduino.h, tested and working on pin 10
void setup() {
Serial.begin(57600);
while(!Serial){
// wait for Serial
}
SD.begin(cardSelect);
SPI.begin();
while(!adxl355.TestConnection()){
delay(1000);
}
adxl355.OpenFile("TestSPI.bin");
adxl355.Initialize(1, 10, 0); // set range to 2g's, frequency to 4 Hz and filter to off
}
void loop() {
while(true){ // avoid Arduino overhead of their loop function
adxl355.ReadFIFO();
adxl355.WriteFIFOToFile();
}
}
Here is the ADXL constructor
ADXL355_SPIF::ADXL355_SPIF(volatile uint8_t * outReg, volatile uint8_t * outPort, uint8_t bitValue) : sensorOutReg(outReg), sensorPort(outPort), sensorBitValue(bitValue){
*sensorOutReg |= sensorBitValue;
*sensorPort |= sensorBitValue;
sensorWriteCount = 0;
}
TestConnection tests that the DeviceID reads 0xAD. Initialize sets the G range, sample rate in Hz and filter. I have tested these with serial output and they work properly.
OpenFile looks like this:
bool ADXL355_SPIF::OpenFile(const String& fileName){
sensorFile = SD.open(fileName, FILE_WRITE);
if (!sensorFile){
Serial.print("Could not create file: ");
Serial.println(fileName);
return false;
}
return true;
}
After running this a file does get created on the SD card called "TESTSPI.BIN" with 0 file size.
ReadFIFO reads the numbers of entries in FIFO, stored as fifoCount and then populates a buffer (sensorFIFO[32][3]) with the values from the FIFO. I've printed this buffer to Serial to show that it's working. Here is that function
void ADXL355_SPIF::ReadFIFO(){
ReadRegister(ADXL355_RA_FIFO_ENTRIES, 1);
fifoCount = buffer[0];
ReadFIFOInternal();
return;
}
void ADXL355_SPIF::ReadFIFOInternal(){
SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));
*sensorPort &= ~sensorBitValue;
uint8_t spiCommand = ADXL355_RA_FIFO_DATA << 1 | ADXL355_READ;
SPI.transfer(spiCommand);
int i = 0;
unsigned long tempV;
unsigned long value;
while(i < fifoCount){
for (int ptr = 0; ptr < 3; ++ptr){
buffer[0] = SPI.transfer(0x0);
value = buffer[0];
value <<= 12;
tempV = SPI.transfer(0x0);
tempV <<= 4;
value |= tempV;
tempV = SPI.transfer(0x0);
tempV >>=4;
value |= tempV;
if (buffer[0] & 0x80) {
value |= 0xFFF00000;
}
long lValue = static_cast<long>(value);
sensorFIFO[i][ptr] = scaleFactor * lValue;
}
i += 3;
}
SPI.endTransaction();
*sensorPort |= sensorBitValue;
return;
}
Here is WriteFIFOToFile:
void ADXL355_SPIF::WriteFIFOToFile(){
if (fifoCount > 0){
sensorFile.write(reinterpret_cast<const char *>(&sensorFIFO), 4 * fifoCount);
}
sensorWriteCount += fifoCount;
if (sensorWriteCount >= 100){
sensorFile.flush();
sensorWriteCount = 0;
}
}
After allowing this to run for a while the file size is always 0. I tried a simple binary write function just to test the card. It looks like this and it worked.
#include <SD.h>
#define cardSelectPin 4
const float pi=3.14159;
File oFile;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
while(!Serial){
// wait for serial
}
SD.begin(cardSelectPin);
oFile = SD.open("Test.bin", FILE_WRITE);
Serial.println(sizeof(int));
Serial.println(sizeof(float));
float testFloat[32][3];
for (int i = 0; i < 32; ++i){
for (int j = 0; j < 3; ++j){
testFloat[i][j] = pi * (i + 1) + j;
}
}
oFile.write(reinterpret_cast<const char *>(&testFloat), sizeof(float) * 96);
oFile.close();
Serial.println("Finished writing file.");
}
void loop() {
// put your main code here, to run repeatedly:
}
The problem was that flush was not being called correctly. I had created a buffer to hold data from the FIFO and it would flush the card when it would get full enough such that a subsequent read would overflow. At that time it would call flush. This is what was intended with the variable sensorWriteCount. This variable was of type uint8_t when it should have been a uint16_t.
Changing to the correct type fixed the problem. I would have deleted this question because it boils down to a typo, but once an answer has been posted the system doesn't allow that.
The only difference between the not-working sketch and the working one is the closing of the sd card. The sd card MUST be closed, I had the same problem you have and I assume that the file gets its boundaries written in its filesystem at file close call.
To solve your issue, use a push button. When you push it, it will close the file and stop reading/processing sensors. You can also use this button to start reading and recording sensors data on sd card again (toggle).

Can't send data through ESP8266

I working on project about seat occupancy in which I have used an Arduino, a piezoelectric sensor and an ESP8266. My problem is that I am not able to send data to my PC where an UDP server is running, written in Python.
My real problem is, that I am able to send data, when I use Arduino IDE's serial monitor. It sends and receives data perfectly, but code is not running and I am not able to point out my mistake.
Arduino code:
const int seat_no = 2;
const char *ssid = "";
const char *passwd = "";
const char *ip = "192.168.43.250";
const int port = 55056;
const int threshold = 100;
String op;
int i, a, data_size;
void setup() {
Serial.begin(9600);
Serial1.begin(115200);
Serial.println("Starting ESP8266");
Serial1.write("AT+CWJAP=\"");
Serial1.write(ssid);
Serial1.write("\",\"");
Serial1.write(passwd);
Serial1.write("\"\r\n");
Serial1.write("AT+CWMODE=1\r\n");
Serial1.write("AT+CIPMUX=0\r\n");
Serial1.write("AT+CIPSTART=\"UDP\",\"");
Serial1.write(ip);
Serial1.write("\",");
Serial1.write(port);
Serial1.write("\r\n");
}
void loop() {
op = "{\"seat_status\":[";
for (i = 0; i < seat_no; i++) {
a = analogRead(i);
if (a > threshold) {
op += "\"0\"";
Serial.println("0");
}
else {
op += "\"1\"";
Serial.println("1");
}
if (i < seat_no - 1)
op += ",";
}
op += "]}";
data_size = op.length();
Serial1.write("AT+CIPSEND=");
Serial1.write(data_size+2);
Serial1.write("\r\n");
delay(1000);
for (i = 0; i < data_size; i++)
Serial.write(op[i]);
Serial.println();
for (i = 0; i < data_size; i++)
Serial1.write(op[i]);
Serial1.write("\r\n");
delay(5000);
}
I think my Python code is correct as I am able to receive data from other sources as well (through Android app UDP sender) so help me to rectify this problem.
Circuit Diagram
The problem is with the use of Serial1.write. It's a lower level function. All it does is send bytes and doesn't convert numbers to their string representation.
When you are writing your port and length of your data to the serial, the write function is just sending a byte with that value and not a string.
If you would replace Serial1 with Serial and send the commands back to PC, you would see the mistake.
To actually solve your problem, you should replace all of your Serial1.write with Serial1.print.

Two xbees ( Router At) connected to Xbee(coordinator)

I have been working on a project which involves xbees. My set-up is simply one Xbee ( coordinator Api mode ) connected to an Arduino as a master unit. This master unit recieves data from multiple Xbees ( slaves ) that are only powered up by a battery and reading data from there ADC pin17. ADC values are transmitted to the master xbee to display it on the serial terminal. The slaves Xbee are configured as ( Router AT mode ). I've bee doing this between two xbees only : 1 master and 1 slave. I have a code that reads the mac address of the sending Xbee and then displays the sent ADC value which is transmitted. All of that was ok until I added another slave, I really need help since I can't associate each mac address with the right ADC value. Neither my code is capable of reading from both alternatively; at some point it stops reading from a one. If any advice on how to recognize data coming from multiple xbees on the same network, I will be grateful.
Here's my code :
#include <XBee.h>
#include <SoftwareSerial.h>
SoftwareSerial myserial(5,6);
float distance;
uint8_t myaddress[10];
XBee xbee = XBee();
uint8_t shCmd[] = {'S','H'};
uint8_t slCmd[] = {'S','L'};
AtCommandRequest atRequestSH = AtCommandRequest(shCmd);
AtCommandRequest atRequestSL = AtCommandRequest(slCmd);
AtCommandResponse atResponse = AtCommandResponse();
void getMyAddress(){
xbee.send(atRequestSL);
if(xbee.readPacket(5000)){
xbee.getResponse().getAtCommandResponse(atResponse);
if (atResponse.isOk()){
for(int i = 0; i < atResponse.getValueLength(); i++){
myaddress[i] = atResponse.getValue()[i];
}
}
}
delay(100);
}
void setup(){
Serial.begin(1200);
myserial.begin(1200);
xbee.begin(myserial);
}
void loop() {
getMyAddress();
for(int i=0; i < 10; i++) {
Serial.print(myaddress[i], HEX);
Serial.print(" ");
}
Serial.print("\n");
if (myserial.available() >= 21) { //
if (myserial.read() == 0x7E) {
for (int i = 1; i<19; i++) { // Skip ahead to the analog data
byte discardByte = myserial.read();
}
int analogMSB = myserial.read(); // Read the first analog byte data
int analogLSB = myserial.read(); // Read the second byte
int analogReading = analogLSB + (analogMSB * 256);
distance = ((analogReading *1.0) / 1023.0)* 3.3;
Serial.println(distance);
}
}
}
In the code where you're skipping data to get to the analog value, you'll find the MAC address of the device sending the data.
if (myserial.read() == 0x7E) {
for (int i = 1; i<19; i++) { // Skip ahead to the analog data
byte discardByte = myserial.read();
}
You should be taking a closer look at that data before processing it -- ensure that it's an I/O sample by looking at the frame type, check the frame length, check the checksum at the end of the frame, etc. The library you're using appears to have functions for processing AT commands and responses, perhaps it also has functions for the I/O Sample frame type.
This Digi support page explains I/O sampling and documents the various fields in the IO Data Sample Received frame (type 0x92).

Resources