Raspberry Pi control arduino atmega2560
-
Hello, I thought I would share a project I have been working on for work. I'm using a raspberry pi to send commands to an arduino atmega 2560 which either turns on/off relays or takes an analog reading.
The raspberry pi software is written in C++ using QT Creator. It starts through user input then sends single to turn on X relay and sends command to read an analog channel at set increments. When designated time is finished it send command to turn on x relay then kills the timer.
The arduino software is very basic. simple case statement and either reads or turns on/off relay based on command.
DISCLAIMER: Both pieces of code are poorly written. I needed this working immediately so I hacked it to heck and back. I will be cleaning it up soon, but thought this may help somebody wanting to communicate with an arduino using c++ on the raspberry pi.
GITHUB: https://github.com/aelmendorf/Reliability-Stress-System/
.cpp
#include <QtGui> #include <QCoreApplication> #include "SlotTimer.h" #include "ui_mainwindow.h" #include <vector> #include <algorithm> #include <QDebug> #include <QFile> #include <QTextStream> #include <QDateTime> /** *Author: Andrew Elmendorf *Date: 3/20/17 *To-Do: * 1:Add Qtimer object to each slot * 2:convert BoardSlots to a class * 3:Cleanup your damn code! There is a lot to fix here. * */ SlotTimer::SlotTimer(QWidget *parent) :QMainWindow(parent),ui(new Ui::SlotTimer) { ui->setupUi(this); this->arduino=new QSerialPort(); this->connected=false; //Setup the table this->model = new QStandardItemModel(10,7,this); this->model->setHorizontalHeaderItem(0, new QStandardItem(QString("Name"))); this->model->setHorizontalHeaderItem(1, new QStandardItem(QString("BoardSlot"))); this->model->setHorizontalHeaderItem(2, new QStandardItem(QString("Start Time"))); this->model->setHorizontalHeaderItem(3, new QStandardItem(QString("Last Measure"))); this->model->setHorizontalHeaderItem(4, new QStandardItem(QString("Duration"))); this->model->setHorizontalHeaderItem(5, new QStandardItem(QString("Elapsed"))); this->model->setHorizontalHeaderItem(6, new QStandardItem(QString("Reading"))); this->model->setHorizontalHeaderItem(7, new QStandardItem(QString("Running?"))); //build slot list for(int i=0;i<8;i++) this->boardSlots.push_back(BoardSlot(0,i+1)); //set status table status to not loaded for(int i=0;i<8;i++){ QStandardItem *item = new QStandardItem(QString("Not Loaded")); this->model->setItem(i,0,item); //this->boardSlots.push_back(BoardSlot(0)); }//End for loop ui->timerList->model(); ui->timerList->setModel(this->model); }//End constructor, init program void SlotTimer::on_Start_t_clicked() { bool found=false; int index=0; //Find index of requested slot for(int i=0;i<this->boardSlots.size();i++){ if(this->boardSlots[i].channel==(long)ui->channel_in->value()){ found=true; index=i; }//end if == channel }//end loop through if(found){ if(!this->boardSlots[index].running && !this->boardSlots[index].loaded){ //set the table values this->boardSlots[index].duration_t=(long)ui->duration->value()*this->hrsTomilli; this->boardSlots[index].channel=(long)ui->channel_in->value(); this->boardSlots[index].start=QTime::currentTime(); this->boardSlots[index].current=this->boardSlots[index].start; this->boardSlots[index].inc=(long)ui->increment->value()*this->minsToMilli; this->boardSlots[index].elapsed_t=this->boardSlots[index].inc; this->boardSlots[index].running=true; this->boardSlots[index].loaded=true; this->boardSlots[index].slotName=ui->testName_in->text(); this->boardSlots[index].filename+=this->boardSlots[index].slotName+"_data.txt"; ui->current->setText(this->boardSlots[index].start.toString("hh:mm:ss")); this->boardSlots[index].ID=startTimer((int)this->boardSlots[index].inc); ui->ID->setText(QString::number(this->boardSlots[index].ID)); this->fillTable(this->boardSlots[index]); //Write out to the arduino // "PX Y" P: switching relay designator X:channel 1-8 Y: on or off QByteArray output; QString txt; QTextStream(&txt)<<"P"<<this->boardSlots[index].channel<<" 0\n"; output =txt.toLocal8Bit(); this->arduino->write(output); this->arduino->flush(); }else{ this->sendUserMessage("Warning","Board Loaded"); }//End check for slot loaded }else{ this->sendUserMessage("Warning","Slot Not Found"); }//End for slot found }//End start timer procedure void SlotTimer::timerEvent(QTimerEvent *e) { std::vector<BoardSlot>::iterator itr; itr = std::find (this->boardSlots.begin(),this->boardSlots.end(),BoardSlot(e->timerId())); if (itr != this->boardSlots.end()){ itr->elapsed_t=itr->elapsed_t+itr->inc; if(!itr->check()){ itr->current=QTime::currentTime(); this->fillTable(*itr); //Request Current Reading QByteArray output; QString txt; QTextStream(&txt)<<"R"<<itr->channel<<"\n"; output =txt.toLocal8Bit(); this->arduino->write(output); this->arduino->flush(); }else{ itr->running=false; this->model->setItem(itr->channel-1,7,new QStandardItem(QString("Done"))); killTimer(itr->ID); //sending a message to arduino QByteArray output; QString txt; // "PX Y" P: switching relay designator X:channel 1-8 Y: on or off QTextStream(&txt)<<"P"<<itr->channel<<" 1\n"; output =txt.toLocal8Bit(); this->arduino->write(output); this->arduino->flush(); }//if not finished do continue on, if done stop it all }else{ this->sendUserMessage("Error","No Such slot"); }// if slot not found. should never happen }//End timer event void SlotTimer::readData() { if (!this->arduino){ qDebug()<<"Why am I here!?!"; //Need a message return; } QByteArray in; //get buffer size and resize int buffSize=this->arduino->bytesAvailable(); in.resize(buffSize); //read and append the data this->arduino->read(in.data(),in.size()); this->recieved.append(in); //if it is a newline stop and finalize read. there is no guarantee that this //function will be called once for one command. have to make a buffer in struct/class and append until finished if(in.contains('\n')){ QString str = QString::fromUtf8(recieved.split('\n').first()); ui->current->setText(str); int index=str.split(':').first().toInt()-1; this->boardSlots[index].lastRead=str.split(':').last().toLong(); this->writeDataOut(this->boardSlots[index]); recieved.clear(); }//End terminator check }//End serial read data void SlotTimer::setControlsEnabled(bool enable) { ui->Start_t->setEnabled(enable); }//End button enabled void SlotTimer::on_connectSerial_clicked() { QSerialPortInfo port; //Find the arduino port using vendor and manufacturer IDs foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()){ ui->serialPortList->addItem(info.portName()); if(info.vendorIdentifier()==this->arduinoVendorID && info.productIdentifier()==this->megaProductID){ qDebug()<<info.manufacturer(); qDebug()<<info.vendorIdentifier(); qDebug()<<info.productIdentifier(); port=info; //found=true; }//end check for arduino }//end iteration of open ports //Set the port up! this->arduino->setPortName(port.portName()); this->arduino->setBaudRate(QSerialPort::Baud9600); this->arduino->setDataBits(QSerialPort::Data8); this->arduino->setParity(QSerialPort::NoParity); this->arduino->setStopBits(QSerialPort::OneStop); this->arduino->setFlowControl(QSerialPort::NoFlowControl); this->arduino->open(QIODevice::ReadWrite); this->arduino->setDataTerminalReady(true); //Connect the slot for readData() connect(arduino, SIGNAL(readyRead()),this,SLOT(readData())); //making sure setup worked. this->connected=this->arduino->isWritable() && this->arduino->isReadable(); if(this->connected==true){ ui->serialStatus->setText("Connected"); qDebug()<<"Success!"; }// if success!! }//connect serial void SlotTimer::fillTable(const BoardSlot &s) { this->model->setItem(s.channel-1,0,new QStandardItem(s.slotName)); this->model->setItem(s.channel-1,1,new QStandardItem(QString::number(s.channel))); this->model->setItem(s.channel-1,2,new QStandardItem(QString(s.start.toString("hh:mm:ss")))); this->model->setItem(s.channel-1,3,new QStandardItem(QString(s.current.toString("hh:mm:ss")))); this->model->setItem(s.channel-1,4,new QStandardItem(QString::number((double)s.duration_t/SlotTimer::hrsTomilli))); this->model->setItem(s.channel-1,5,new QStandardItem(QString::number((double)s.elapsed_t/SlotTimer::hrsTomilli))); if(s.running){ this->model->setItem(s.channel-1,7,new QStandardItem(QString("Running"))); }else{ this->model->setItem(s.channel-1,7,new QStandardItem(QString("Not Running"))); }//End check for running this->model->setItem(s.channel-1,6,new QStandardItem(QString::number(s.lastRead))); }//End fill table void SlotTimer::clearTable() { for(int i=0;i<8;i++){ this->model->setItem(i,0,new QStandardItem("Not Loaded")); this->model->setItem(i,1,new QStandardItem(" ")); this->model->setItem(i,2,new QStandardItem(" ")); this->model->setItem(i,3,new QStandardItem(" ")); this->model->setItem(i,4,new QStandardItem(" ")); this->model->setItem(i,5,new QStandardItem(" ")); this->model->setItem(i,6,new QStandardItem(" ")); this->model->setItem(i,7,new QStandardItem(" ")); }//End for loop }//End fill table void SlotTimer::clearSlot(int s) { this->model->setItem(s,0,new QStandardItem("Not Loaded")); this->model->setItem(s,1,new QStandardItem(" ")); this->model->setItem(s,2,new QStandardItem(" ")); this->model->setItem(s,3,new QStandardItem(" ")); this->model->setItem(s,4,new QStandardItem(" ")); this->model->setItem(s,5,new QStandardItem(" ")); this->model->setItem(s,6,new QStandardItem(" ")); this->model->setItem(s,7,new QStandardItem(" ")); }//End fill table void SlotTimer::on_timerList_clicked(const QModelIndex &index) { qDebug()<<index.row(); } void SlotTimer::on_Unload_Chan_clicked() { if(!this->boardSlots[ui->channel_in->value()-1].running){ int channel=ui->channel_in->value(); QString msg="Unload channel "+QString::number(channel)+"?"; if(this->getUserResponce("Unload?",msg)) { this->boardSlots[channel-1].reset(); this->clearSlot(channel-1); }//end check user response }else{ this->sendUserMessage("Warning","Board Loaded"); }//End check if slot as running board }//End unload void SlotTimer::on_Stop_Chan_clicked() { if(this->boardSlots[ui->channel_in->value()-1].running){ int channel=ui->channel_in->value(); QString msg="Stop channel "+QString::number(channel)+"?"; if(this->getUserResponce("Unload?",msg)) { this->boardSlots[ui->channel_in->value()-1].running=false; killTimer(this->boardSlots[ui->channel_in->value()-1].ID); QByteArray output; QString txt; QTextStream(&txt)<<"P"<<ui->channel_in->value()<<" 1\n"; output =txt.toLocal8Bit(); this->arduino->write(output); this->arduino->flush(); }//End check with user }else{ this->sendUserMessage("Error","Not Running"); }//End check if running }//End stop channel void SlotTimer::writeDataOut(const BoardSlot &s) { QFile out(s.filename); if (!out.open(QIODevice::ReadOnly | QIODevice::Text | QIODevice::ReadWrite |QIODevice::Append)){ qDebug() << "FAIL TO CREATE FILE / FILE NOT EXIT***"; }else{ QTextStream stream(&out); QDateTime temp=QDateTime::currentDateTime(); stream <<s.lastRead<<"\t"<<temp.toString("dd.MM.yyyy")<<"\t"<<s.current.toString("hh:mm:ss")<<endl; out.close(); }//End check if file }//End write data out bool SlotTimer::getUserResponce(const QString &t,const QString &msg) { bool ret=false; QMessageBox::StandardButton reply; reply = QMessageBox::question(0,t,msg,QMessageBox::Yes|QMessageBox::No); if (reply == QMessageBox::Yes) { ret=true; } else { ret=false; }//End set ret answer return ret; }//end request feedback void SlotTimer::sendUserMessage(const QString &t,const QString &msg) { QMessageBox messageBox; messageBox.critical(0,t,msg); messageBox.setFixedSize(500,200); }//End send message SlotTimer::~SlotTimer() { if(this->arduino->isOpen()){ this->arduino->close(); }//end serial open check delete ui; }//
.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QtGui> #include <QSerialPort> #include <QSerialPortInfo> #include <string> namespace Ui { class SlotTimer; }//UI namespace class SlotTimer : public QMainWindow { Q_OBJECT public: explicit SlotTimer(QWidget *parent = 0); ~SlotTimer(); struct BoardSlot { QTime current,start; long elapsed_t; long duration_t; long inc; long ID; int channel; bool running; bool loaded; long lastRead; QString slotName; QString filename; //Constructor overload for timerID BoardSlot(int id) { ID=id; loaded=false; running=false; lastRead=0; filename="/home/pi/Monitor/"; slotName=""; elapsed_t=0; duration_t=0; }//end timerID overload //constructor overload for initial channel and timerID BoardSlot(int id,int c) { ID=id; channel=c; loaded=false; running=false; lastRead=0; filename="/home/pi/Monitor/"; slotName=""; elapsed_t=0; duration_t=0; }//end channel/timerID overload //reset this timer void reset() { ID=0; loaded=false; running=false; lastRead=0; filename="/home/pi/Monitor/"; slotName=""; elapsed_t=0; duration_t=0; }//End timer reset //checking if done bool check() { return elapsed_t>duration_t; }//end check if done //equals overload for vector search bool operator==(const BoardSlot& b) const { return ID == b.ID; }//end equals overload };//End BoardSlot struct //Constants for timer conversion static const long hrsTomilli=3600000; static const long minsToMilli=60000; QSerialPort *arduino; //serial port of arduino QStandardItemModel *model; //model for building display table std::vector<BoardSlot> boardSlots;// using only in timerEvent. really don't need a vector, left because ran out of time bool connected; //are we connected/ QByteArray recieved; //from arduino buffer void setControlsEnabled(bool enable);//enable/disable controls. NOT EVEN USING void fillTable(const BoardSlot &s);//fille the table void writeDataOut(const BoardSlot &s);//write out to a txt file void clearTable();//clear the table void sendUserMessage(const QString &t,const QString &msg);//send a message a user bool getUserResponce(const QString &t,const QString &msg);//send a message a user requesting feedback void clearSlot(int s);//clear that slot! private slots: void timerEvent(QTimerEvent *e);//timer events! void readData();//read in serial void on_Start_t_clicked();//start a timer void on_connectSerial_clicked();//connect to the arduino void on_timerList_clicked(const QModelIndex &index);//not even used, was going to have the table as the slot selector. still might void on_Unload_Chan_clicked();//unload a channel void on_Stop_Chan_clicked();//stop a channel private: Ui::SlotTimer *ui; static const quint16 arduinoVendorID=9025;//arduino vendor ID for finding the port static const quint16 megaProductID=66;//arduino atmega product ID ID for finding the port void processError(const QString &error);//not even using, will implement later void initSerial();//initialize the arduino com! }; #endif // MAINWINDOW_H
-
Hi and welcome to devnet,
Thanks for sharing ! However please don't post on multiple subforums. One is enough.
Closing this one.