Any advice appreciated

Hey all,

I was thinking of writing up a mini research paper to share and showcase my arduino projects going forwards. I feel like writing up a paper to go with a project would be a valuable skill to learn as I plan on studying engineering in college (im a high schooler atm)

Do you think writing up a research paper (like a scientific report / thesis) would be a good idea? Do any of do the same? If so, what should be included in these papers?

For example, an idea I recently had was to use a button press to trigger a servo motor to hit the lights in my room. I was planning on writing up a paper to go alongside this small project. A quick question to ChatGPT yields this template:

Abstract
A brief summary of the project: goal, what was built, and its purpose.

Introduction
Motivation: Why automate a light switch this way?
Objective: Build a reliable, Arduino-based system that uses a button to control a servo motor that physically presses a switch.

Background and Theory
Basics of servo motors (angle control, PWM)
Digital input (button press)

Results

Does the servo consistently hit the switch?
How much delay or force is needed?
Any pictures/videos/screenshots of it working
Table of performance over 10 trials

Conclusion
Appendix
References (optional)

Would a structure like this be appropriate? Is writing up a paper to go with the project a good idea?

Why not have Chat write the paper for you?

I want to learn how to write it for myself! This is more of a learning experience for me rather than "getting it done for the sake of it". That's why I want to confirm whether such a format for a paper which I could upload to my GitHub or showcase elsewhere is a good idea.

Why not look at a real research paper in a respected publication and follow that format. You will see they are all basically the same.

That makes sense, but the thing is I'm not going to be doing any real research. These are small-scale, simple projects. I just want an efficient, and reputable way to showcase my projects.

Maybe not but if you want practice for writing real research papers at a college level you should treat your project as if you were.

Good to hear! Also, it would be great if you could share any examples of such papers other people (or you!) have made for Arduino / electronics projects?

The outline that Chat gave is standard.
Here is a more detailed outline:

However if you going to write something that is more like a tutorial the fromat would be different.

  • First off, all documentation is good.
  • How much documentation depends on your skills.
  • Personally I always start a project with a complete schematic.
  • As for the code, it is fully documented with meaningful comments, I avoid fancy one liners that are difficult to decipher.
    At the top of the sketch, I add a preamble which explains how things work.
    I write all my sketches in the same style, it has to be easily followed.
  • The important thing for me is, my documentation must be such that I can pick it up and follow it 6 years from now.

I do not use the formatted stye as you suggest, would it be useful, maybe :thinking: .

You marked this topic as solved. If you want more responses, uncheck the solved.

Thank you!

Would it be possible for you to share an example project of yours with all these files? Perhaps if you have it stored in a public GitHub repo I could take a quick look.

Done. It would be great if you could share some examples of Arduino projects documented in this format.

I don't have any. Most Arduino documentation you find online is usually given in the form of a tutorial, how to connect things, use this code etc.

If you’re seeking model Tutorials, you could do worse than to flip through some of the Tutorials here:

https://docs.arduino.cc/tutorials/

You’ll find quite a variety of styles and structures, which is acceptable, but they all pretty much provide the same information. The wide variety of styles means you’ll likely find one that just ‘clicks’ for you - perhaps, return here with a link to the one you like most, and ask members what they think is right/wrong/missing.


//
//================================================^================================================
//                              B a s i c   L C D   M e n u   S k e t c h
//
//  https://forum.arduino.cc/t/arduino-millis-and-indexing-code/1376338/142
//
//  LarryD
//
//  Version    YY/MM/DD    Comments
//  =======    ========    ========================================================================
//  1.00       25/03/12    Running code
//
//
//
// Notes:
// - The following sketch demonstrates how we can use LCD menus to change program behavior.
//   When you upload the sketch below, the LCD displays a 4-screen menu.
// - Close the switch connected to D02 for 1 second then release.
//   You will see the LED connected to D12 come on for 1 second, then turn off.
// - Tap the switch for less than 150ms seconds.
//   This time the LCD menu will advance to the next screen.
// - Tap the switch 3 more times, the menu will cycle back to the beginning.
// - Advance the LCD menu to Screen 4 by tapping the switch quickly 3 times.
// - "Screen 4" will be on the LCD, hold the switch closed for greater than 3 seconds.
//   The screen will display "LED Interval Updated".
// - Close the switch for 1 second, then release.
//   You will see the LED connected to D12 come on now for 4 seconds, then turn OFF.
//
//
//

//================================================
#include <makeTIMER.h> //makes non-blocking TIMERS
#include <makeInput.h> //makes physical switch objects

#include <Wire.h>

//========================
//Use I2C library:     https://github.com/duinoWitchery/hd44780
//LCD Reference:       https://www.arduino.cc/en/Reference/LiquidCrystal
#include <hd44780.h>   //makes LCD objects, main hd44780 header

//NOTE:
//hd44780_I2Cexp control LCD using I2C I/O expander backpack (PCF8574 or MCP23008)
//hd44780_I2Clcd control LCD with native I2C interface (PCF2116, PCF2119x, etc...)

#include <hd44780ioClass/hd44780_I2Cexp.h> //I2C expander i/o class header

//If you do not know what your I2C address is, first run the "I2C_Scanner" sketch
//OR
//run the "I2CexpDiag" sketch that comes with the hd44780 library
//hd44780_I2Cexp lcd(0x3F);

hd44780_I2Cexp lcd(0x27);


//================================================
#define LEDon              HIGH   //PIN---[220R]---A[LED]K---GND
#define LEDoff             LOW

#define PRESSED            LOW    //+5V---[Internal 50k]---PIN---[Switch]---GND
#define RELEASED           HIGH

#define CLOSED             LOW    //+5V---[Internal 50k]---PIN---[Switch]---GND
#define OPENED             HIGH

#define ENABLED            true
#define DISABLED           false

#define RELAYon            LOW
#define RELAYoff           HIGH

//Atmega 328 UNO, Pro Mini, NANO
#define PULSE62D13         cli(); PINB = bit(PINB5); PINB = bit(PINB5); sei()
#define PULSE126D13        cli(); PINB = bit(PINB5); asm("nop\n"); PINB = bit(PINB5); sei()

//================================================
#define ONE_SECOND         1000ul              //milliseconds
#define ONE_MINUTE         (ONE_SECOND * 60ul) //60 seconds in one minute
#define ONE_HOUR           (ONE_MINUTE * 60ul) //60 minutes in one hour
#define ONE_DAY            (ONE_HOUR * 24ul)   //24 hours in one day


//                                T I M E R   D e f i n i t i o n s
//================================================^================================================
//Notes:
//========================
//data members in class makeTIMER
//.TimerType,   .Interval, .TimerFlag,       .Restart,  .SpeedAdjustPin
//MILLIS/MICROS, 500ul,    ENABLED/DISABLED, YES/NO,    A0-A5
//
//the .SpeedAdjustPin defaults to 0 i.e. no speed adjustment is used
//.SpeedAdjustPin can be = A0-A5, a potentiometer on this pin adjusts the TIMER's speed (used for diagnostics)
//
//class static flag "makeTIMER::normalFlag" can be used to ENABLE/DISABLE adjustable TIMER speed,
//ENABLE (normal speed), DISABLED (a potentiometer on .SpeedAdjustPin controls the TIMER speed)
//
//these are the TIMER functions we can access:
//object.checkTIMER();             - checks to see if the TIMER status: STILLtiming/EXPIRED/TIMERdisabled
//object.enableRestartTIMER();     - enables and restarts the TIMER
//object.restartTIMER()            - restarts the TIMER
//object.disableTIMER();           - disables the TIMER
//object.expireTimer();            - make the TIMER expire
//object.setInterval(100ul);       - set the TIMER interval
//

//========================
makeTIMER heartbeatTIMER =
{
  //.TimerType, .Interval, .TimerFlag, .Restart, .SpeedAdjustPin
  MILLIS, 500ul, ENABLED, YES, 0
};

//========================  (5ms * s_filter) i.e. 5ms * 10 = 50ms for checking a valid switch operation
makeTIMER switchesTIMER =
{
  //.TimerType, .Interval, .TimerFlag, .Restart, .SpeedAdjustPin
  MILLIS, 5ul, ENABLED, YES, 0
};

//========================
makeTIMER machineTIMER =
{
  //.TimerType, .Interval, .TimerFlag, .Restart, .SpeedAdjustPin
  MICROS, 1000ul, ENABLED, YES, 0
};

//========================
makeTIMER commonTIMER =
{
  //.TimerType, .Interval, .TimerFlag, .Restart, .SpeedAdjustPin
  MILLIS, 500ul, DISABLED, NO, 0
};

//========================
makeTIMER testLedTIMER =
{
  //.TimerType, .Interval, .TimerFlag, .Restart, .SpeedAdjustPin
  MILLIS, 1000ul, DISABLED, NO, 0
};


//                                    S t a t e   M a c h i n e
//================================================^================================================
//
//the states in our State Machine
enum STATES : byte
{
  POWERUP, STARTUP, STATE1, WAIT1, STATE2, WAIT2, STATE3, WAIT3, STATE4, WAIT4, FINISHED, UPDATEDmessage
};

STATES mState = POWERUP;


//                              G P I O s   A n d   V a r i a b l e s
//================================================^================================================
//

//Analogs
//================================================
//

//INPUTS
//================================================
//
//We have access to:
//object.validChange()    - checks for a change in state               NOTvalidated(0), VALIDATED(1) or NOchange(2)
//object.pin              - input hardware pin number                  a valid input pin #
//object.lastState        - the state the input was/is in              HIGH/LOW
//object.switchTime       - the millis() value when the switch closes

//========================          GPIO 2
//make the physical switch object
makeInput mySwitch =
{
  //.pin, .lastState
  2, OPENED
};


//OUTPUTS
//================================================
//
const byte testLED                = 12;
const byte heartbeatLED           = 13;

//VARIABLES
//================================================
//
//                                  testLED ON intervals available
//                                     0       1       2       3
unsigned long intervalArray[]     = {1000ul, 2000ul, 3000ul, 4000ul};

//the currentely selected intervalArray item
byte intervalIndex                = 0;

//define our LCD screens
const char* screens[6][2] =
{
  //          111111               111111
  //0123456789012345     0123456789012345     //screenIndex value
  {"    Screen 1    ",  "  Time = 1 sec  "},  //0
  {"    Screen 2    ",  "  Time = 2 sec  "},  //1
  {"    Screen 3    ",  "  Time = 3 sec  "},  //2
  {"    Screen 4    ",  "  Time = 4 sec  "},  //3
  {"  LED Interval  ",  "    Updated!    "},  //4
  {"    Skeleton    ",  "     Sketch     "}   //5
};

//index of the screen now being displayed on the LCD
byte screenIndex                  = 0;

const byte updatedMessageIndex    = 4;
const byte powerUpMessageIndex    = 5;

//Timing Stuff
//========================
const unsigned long shortPushTime = 150ul;  // 0.15 seconds
const unsigned long longPushTime  = 3000ul; // 3 seconds


//                                           s e t u p ( )
//================================================^================================================
//
void setup()
{
  Serial.begin(115200);

  digitalWrite(heartbeatLED, LEDoff);
  pinMode(heartbeatLED, OUTPUT);

  digitalWrite(testLED, LEDoff);
  pinMode(testLED, OUTPUT);

  //================================================
  //LCD stuff
  lcd.begin(16, 2);
  lcd.clear();

  //display the powerup startup message on the LCD
  displayScreen(powerUpMessageIndex);

  //3 seconds to read the updated message
  //set the TIMER interval
  commonTIMER.setInterval(3000ul);

  //start the TIMER
  commonTIMER.enableRestartTIMER();

} //END of   setup()


//                                            l o o p ( )
//================================================^================================================
//
void loop()
{
  //========================================================================
  //Diagnostics:
  //Print the time it takes to return to this same spot.
  //Comment the next 3 lines when no longer needed.
  //static unsigned long startTime;
  //Serial.println(micros() - startTime);
  //startTime = micros();

  //========================================================================
  //Diagnostics:
  //Make a pulse on D13 equal to 62ns or 126ns.
  //PULSE62D13;
  //PULSE126D13;

  //========================================================================  T I M E R  heartbeatLED
  //condition returned: STILLtiming, EXPIRED or TIMERdisabled
  //is it time to toggle the heartbeat LED ?
  if (heartbeatTIMER.checkTIMER() == EXPIRED)
  {
    //toggle the heartbeat LED
    digitalWrite(heartbeatLED, digitalRead(heartbeatLED) == HIGH ? LOW : HIGH);
  }

  //========================================================================  T I M E R  switches
  //condition returned: STILLtiming, EXPIRED or TIMERdisabled
  //is it time to check our switches ?
  if (switchesTIMER.checkTIMER() == EXPIRED)
  {
    checkSwitches();
  }

  //========================================================================  T I M E R  machine
  //condition returned: STILLtiming, EXPIRED or TIMERdisabled
  //is it time to service our State Machine ?
  if (machineTIMER.checkTIMER() == EXPIRED)
  {
    checkMachine();
  }

  //========================================================================  T I M E R  testLed
  //condition returned: STILLtiming, EXPIRED or TIMERdisabled
  //if enabled, is it time to turn OFF the testLED ?
  if (testLedTIMER.checkTIMER() == EXPIRED)
  {
    digitalWrite(testLED, LEDoff);

    //we are finished with this TIMER
    testLedTIMER.disableTIMER();
  }


  //================================================
  //       Other non blocking code goes here
  //================================================


} //END of   loop()


//                                    c h e c k M a c h i n e ( )
//================================================^================================================
//
void checkMachine()
{
  //================================================
  //service the current "state"
  switch (mState)
  {
    //========================
    //this code is run once only at powerup/reset time
    case POWERUP:
      {
        //has the user had enough time to read the power up message ?
        if (commonTIMER.checkTIMER() == EXPIRED)
        {
          //we are finished with this TIMER
          commonTIMER.disableTIMER();

          //next state
          mState = STARTUP;
        }
      }
      break;

    //========================
    case STARTUP:
      {
        //initialize the LCD State Machine
        screenIndex = 0;
        intervalIndex = 0;

        //next state
        mState = STATE1;
      }
      break;

    //========================
    case STATE1:
      {
        //we really should not be using the magic number 0 here as it might change
        //if there is a future screen added, however, for this example we will use 0
        //
        //point to the screen we want displayed
        screenIndex = 0;

        //display the screen
        displayScreen(screenIndex);

        //next state
        mState = WAIT1;
      }
      break;

    //========================
    case WAIT1:
      {
        //stay in this state until the user does something with the mySwitch
      }
      break;

    //========================
    case STATE2:
      {
        //point to the screen we want displayed
        screenIndex = 1;

        //display the screen
        displayScreen(screenIndex);

        //next state
        mState = WAIT2;
      }
      break;

    //========================
    case WAIT2:
      {
        //stay in this state until the user does something with the mySwitch
      }
      break;

    //========================
    case STATE3:
      {
        //point to the screen we want displayed
        screenIndex = 2;

        //display the screen
        displayScreen(screenIndex);

        //next state
        mState = WAIT3;
      }
      break;

    //========================
    case WAIT3:
      {
        //stay in this state until the user does something with the mySwitch
      }
      break;

    //========================
    case STATE4:
      {
        //point to the screen we want displayed
        screenIndex = 3;

        //display the screen
        displayScreen(screenIndex);

        //next state
        mState = WAIT4;
      }
      break;

    //========================
    case WAIT4:
      {
        //stay in this state until the user does something with the mySwitch
      }
      break;

    //========================
    case FINISHED:
      {
        //back to the beginning of the menu screens
        //next state
        mState = STARTUP;
      }
      break;

    //========================
    case UPDATEDmessage:
      {
        //give some time for the user to read the updated message
        //condition returned: STILLtiming, EXPIRED or TIMERdisabled
        if (commonTIMER.checkTIMER() == EXPIRED)
        {
          //we are finished with this TIMER
          commonTIMER.disableTIMER();

          //back to the beginning of the menu screens
          //next state
          mState = STARTUP;
        }
      }
      break;

  } //END of  switch/case

} //END of   checkMachine()


//                                   c h e c k S w i t c h e s ( )
//================================================^================================================
//
//We have access to:
//object.validChange()    - checks to see if there was a valid state change
//object.pin              - input hardware pin number
//object.lastState        - the state the input was/is in
//object.switchTime       - the millis() value when the switch closes

void checkSwitches()
{
  //========================================================================  mySwitch
  //was there a valid change in state for this switch input ?
  //condition returned: NOTvalidated (0), VALIDATED (1) or NOchange (2)
  if (mySwitch.validChange() == VALIDATED)
  {
    //========================
    //was this switch closed ?
    if (mySwitch.lastState == CLOSED)
    {
      //nothing to do here, remember when the switch object closes,
      //we automatically save the time it closed in variable object.switchTime
      //where "object" is the name we gave to this switch
    }

    //========================
    //this switch was opened/released
    else
    {
      //================================================  Short Push
      //proceed to the next screen
      //was this a short push ?
      if (millis() - mySwitch.switchTime <= shortPushTime)
      {
        //we need to "cast" items to prevent compiler warnings
        //advance the State Machine to the next state
        mState = (STATES)((byte)mState + 1);

        //advance the TIMER interval index so it matches the screen being displayed
        intervalIndex++;
      }

      //================================================  Long Push
      //save the new TIMER interval
      //was this a long push ?
      else if (millis() - mySwitch.switchTime >= longPushTime)
      {
        //update the TIMER interval to the new value
        testLedTIMER.setInterval(intervalArray[intervalIndex]);

        //display the updated message on the LCD
        displayScreen(updatedMessageIndex);

        //3 seconds to read the updated message
        //set the TIMER interval
        commonTIMER.setInterval(3000ul);

        //start the TIMER
        commonTIMER.enableRestartTIMER();

        //next state
        mState = UPDATEDmessage;
      }

      //================================================  Regular Push
      //this was a regular push
      //i.e. longer than a short push AND shorter than a long push
      else
      {
        digitalWrite(testLED, LEDon);

        //enable and restart the testLedTIMER
        testLedTIMER.enableRestartTIMER();
      }
    }

  } //END of mySwitch

  //========================================================================  Next Switch

} //END of   checkSwitches()


//                                   d i s p l a y S c r e e n ( )
//================================================^================================================
//
//timing for this function shows about 2.13ms to print two lines of text to a 16X2 LCD
void displayScreen(int index)
{
  static unsigned long startTime;        //               <---------------<<<<<<
  startTime = micros();                  //               <---------------<<<<<<

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(screens[index][0]);
  lcd.setCursor(0, 1);
  lcd.print(screens[index][1]);

  Serial.print(micros() - startTime);   //               <---------------<<<<<<
  Serial.println(" microseconds");      //               <---------------<<<<<<

} //END of   displayScreen()


//================================================^================================================

What did you use to make the schematic?

This guy is one who does it right...

As for me; I wrote a "3am" book (Composition Notebook Quadrille) for my work purposes that I could reference when I had been on-shift for 36 hours and saw no relief from urgent work. All the devices I worked with, I made a quarter-page drawing with inputs and outputs and a table of particulars, and every time I learned something new about it, I added that to the page. It was so good, it was stolen by a co-worker (Jim!), but I had referenced it so often, I was able to reconstruct most of it with little referencing... then it was stolen again (Jim!), so I made a third one, again, completely from memory. After that one was stolen, I knew I did not need to re-accomplish it. It did its job.

  • You can use the free to use programs like Kicad or EasyEDA.